Public/Import-PWSHPUKMGT-Csv.ps1

<#
.SYNOPSIS
    Bulk-creates or updates PWSHPUKMGT records from a CSV file.
.DESCRIPTION
    Reads a CSV file with Identity, SerialNumber, and (optional) Puk columns, resolves each
    identity in Active Directory, and writes each row as a PWSHPUKMGT record via the configured
    hosting backend. A blank Puk column generates a new compliant PUK for that row. A row that
    fails to import (unresolvable identity, missing required column, etc.) is reported as a
    non-terminating error and does not stop the rest of the import.
.PARAMETER Path
    Path to the CSV file. Expected columns: Identity, SerialNumber, Puk (Puk optional). See
    Template/Import-PWSHPUKMGT-Csv.template.csv for a ready-to-edit example.
.PARAMETER Force
    Overwrite existing records for identities already present in the target backend.
.PARAMETER Server
    The domain controller to run the underlying LDAP requests against. Defaults to the value
    configured in hosting.activeDirectory.server, or, if that is not set either, to the primary
    domain controller (PDC emulator) of the current domain.
.EXAMPLE
    Import-PWSHPUKMGT-Csv -Path 'D:\Import\devices.csv'
#>

function Import-PWSHPUKMGT-Csv {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter(Mandatory, Position = 0)]
        [string]$Path,

        [switch]$Force,

        [string]$Server
    )

    if (-not (Test-Path -LiteralPath $Path)) {
        throw "CSV file not found at '$Path'."
    }

    $config = Get-PukModuleConfig
    $certificate = Test-PukCertificate -Thumbprint $config.certificate.thumbprint -StoreLocation $config.certificate.storeLocation -RequiredEkuOids $config.certificate.requiredEkuOids
    $effectiveServer = Resolve-PukServer -Server $Server -Config $config

    $rows = Import-Csv -LiteralPath $Path
    $importedCount = 0

    foreach ($row in $rows) {
        try {
            if ([string]::IsNullOrWhiteSpace($row.Identity)) {
                throw "row has a blank Identity column."
            }
            if ([string]::IsNullOrWhiteSpace($row.SerialNumber)) {
                throw "row has a blank SerialNumber column."
            }

            $distinguishedName = Resolve-PukIdentity -Identity $row.Identity -Server $effectiveServer

            $puk = if ([string]::IsNullOrWhiteSpace($row.Puk)) {
                New-PWSHPUKMGT-Puk -Config $config
            }
            else {
                $row.Puk
            }

            $record = [PSCustomObject]@{
                DistinguishedName = $distinguishedName
                SerialNumber      = $row.SerialNumber
                Puk               = $puk
            }

            if ($PSCmdlet.ShouldProcess($distinguishedName, "Import PWSHPUKMGT record (serial '$($row.SerialNumber)')")) {
                Set-PukRecord -Config $config -Certificate $certificate -Record $record -Server $effectiveServer -Force:$Force -Confirm:$false
                $importedCount++
            }
        }
        catch {
            Write-Error "Failed to import row for identity '$($row.Identity)': $($_.Exception.Message)"
            Write-PukLog -Level Warning -Config $config -Message "Import-PWSHPUKMGT-Csv: failed to import row for identity '$($row.Identity)' from '$Path': $($_.Exception.Message)"
        }
    }

    Write-PukLog -Level Info -Config $config -Message "Import-PWSHPUKMGT-Csv: imported $importedCount of $($rows.Count) row(s) from '$Path'."
}