CPR.psm1

# Public Function Example - Replace With Your Function
function Add-YourFirstFunction {

  [CmdletBinding()]

  Param (
    # Your parameters go here...
  )

  # Your function code goes here...
  Write-Output "Your first function ran!"

}

enum Gender {
    Male = 1
    Female = 0
}

function Get-CPR {
    param (
        [Parameter(Mandatory=$false)]
        [int]$age,

        [Parameter(Mandatory=$false)]
        [Gender]$gender,

        [switch]$useModuloValidation,

        [switch]$omitHyphen
    )
    # If no age is specified - get a random age:
    if(!$age){
        $age = Get-Random -Minimum 0 -Maximum 100
    }


    # Calculate a starting date by subtracting "age" years from the current date
    $currentDate = Get-Date
    $birthDate = $currentDate.AddYears(-$age)

    # Subtract a random number of days (0-364) from the birth date
    $randomDays = Get-Random -Minimum 0 -Maximum 365
    $randomDate = $birthDate.AddDays(-$randomDays)




    # Format the date part of the CPR number
    $datePart = $randomDate.ToString("ddMMyy")


    if ($gender){
        $parity = $gender.value__
    } else {
        $parity = Get-Random -Minimum 0 -Maximum 2
    }

    $controlSequence = Get-Random -Minimum 1000 -Maximum 9999

    if ($controlSequence % 2 -ne $parity){
        $controlSequence++
    }

    $cpr = $datePart + $controlSequence.ToString("D4")

    # Adjust the control sequence until the CPR number passes the modulo 11 check
    if ($useModuloValidation) {
        while (!(Test-CPR -cpr $cpr)) {
            $controlSequence += 2
            if ($controlSequence -gt 9999) {
                $controlSequence = $controlSequence - 10000;
            }
            $cpr = $datePart + $controlSequence.ToString("D4")
        }
    }

    # Format the CPR number with or without a hyphen
    if ($omitHyphen) {
        $cpr = $datePart + $controlSequence.ToString("D4")
    }
    else {
        $cpr = $datePart.Insert(6, '-') + $controlSequence.ToString("D4")
    }

    return $cpr
}

function Get-CPRInfo {
    param (
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [string]$cpr
    )

    process{
    # Remove hyphen if present
    $cpr = $cpr -replace '-', ''

    # Extract date and control sequence parts
    $datePart = $cpr.Substring(0, 6)
    $controlSequence = $cpr.Substring(6)

    # Parse date part to a DateTime object
    $birthday = [DateTime]::ParseExact($datePart, "ddMMyy", $null)


    $currentDate = Get-Date
    if ($birthday -gt $currentDate){
        $birthday = $birthday.AddYears(-100)
    }

    # Calculate age
    $age = $currentDate.Year - $birthday.Year
    if ($currentDate.DayOfYear -lt $birthday.DayOfYear) {
        $age--
    }


    # Determine gender based on the last digit of the control sequence
    $gender = if ([int]$controlSequence[-1] % 2 -eq 0) { 'Female' } else { 'Male' }

    # Check if the CPR number is valid
    $valid = Test-CPR -cpr $cpr

    # Create and return a custom object with the requested properties
    $output = New-Object PSObject
    $output | Add-Member -Type NoteProperty -Name CPR -Value ($cpr.Insert(6, '-'))
    $output | Add-Member -Type NoteProperty -Name Valid -Value $valid
    $output | Add-Member -Type NoteProperty -Name Birthday -Value $birthday
    $output | Add-Member -Type NoteProperty -Name Age -Value $age
    $output | Add-Member -Type NoteProperty -Name Gender -Value $gender
    $output | Add-Member -Type NoteProperty -Name Control -Value $controlSequence

    return $output

    }

}

function Test-CPR {

    param (
        [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
        [string]$cpr
    )

    process{

    # Remove hyphen if present
    $cpr = $cpr -replace '-', ''

    if ($cpr.Length -ne 10) {
        Write-Output "Invalid CPR number. It should be a 10-digit number."
        return $false
    }

    # Extract date parts
    $day = [int]$cpr.Substring(0, 2)
    $month = [int]$cpr.Substring(2, 2)
    $year = [int]$cpr.Substring(4, 2)


    # Figure out century:
    if ($year -le [DateTime]::Now.Year - 2000) {
        $fullyear = 2000 + $year
    } else {
        $fullyear = 1900 + $year
    }

    # Check for valid date
    $isoDate = "$fullyear-$month-$day"

    If (-not (Test-Date $isoDate)){
        Write-Output "Invalid date in CPR number."
        return $false
    }


    $weights = @(4, 3, 2, 7, 6, 5, 4, 3, 2, 1)
    $sum = 0

    for ($i = 0; $i -lt $cpr.Length; $i++) {
        $digit = [int]::Parse($cpr[$i])
        $sum += $digit * $weights[$i]
    }

    return ($sum % 11 -eq 0)
    }
}



Export-ModuleMember -Function Add-YourFirstFunction, Get-CPR, Get-CPRInfo, Test-CPR