Private/New-OSDStageWiFiProfileDefinition.ps1

function New-OSDStageWiFiProfileDefinition {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$SSID,
        [Parameter(Mandatory)][ValidateSet('WPA2Personal','WPA3Personal','Open')][string]$Security,
        [object]$Password,
        [string]$ProfileName,
        [ValidateSet('Auto','Manual')][string]$ConnectionMode='Auto',
        [switch]$Hidden
    )

    $utf8=[System.Text.UTF8Encoding]::new($false,$true)
    try {$ssidBytes=$utf8.GetBytes($SSID)}
    catch {throw 'SSID must contain valid Unicode text.'}
    if([string]::IsNullOrWhiteSpace($SSID) -or $ssidBytes.Length -gt 32 -or $SSID -match '[\x00-\x1F]') {
        throw 'SSID must contain 1 to 32 UTF-8 bytes and no control characters.'
    }
    if(-not $PSBoundParameters.ContainsKey('ProfileName')){$ProfileName=$SSID}
    if([string]::IsNullOrWhiteSpace($ProfileName) -or $ProfileName.Length -gt 255 -or $ProfileName -match '[\x00-\x1F]') {
        throw 'ProfileName must contain 1 to 255 characters and no control characters.'
    }
    try {[System.Xml.XmlConvert]::VerifyXmlChars($ProfileName) | Out-Null}
    catch {throw 'ProfileName must contain valid XML text.'}

    $plain=$null
    $writer=$null
    $pointer=[IntPtr]::Zero
    try {
        if($Security -eq 'Open') {
            if($PSBoundParameters.ContainsKey('Password')){throw 'Open networks do not accept Password.'}
        }
        else {
            if($Password -is [System.Security.SecureString]) {
                $pointer=[System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
                $plain=[System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($pointer)
            }
            elseif($Password -is [string]){$plain=$Password}
            else {throw 'Personal networks require Password as a string or SecureString.'}
            # Validate here, rather than using validation attributes that echo rejected secrets.
            if($plain.Length -lt 8 -or $plain.Length -gt 63 -or $plain -match '[^\x20-\x7E]') {
                throw 'Password must contain 8 to 63 printable ASCII characters.'
            }
        }

        $authentication=switch($Security){'WPA2Personal'{'WPA2PSK'} 'WPA3Personal'{'WPA3SAE'} 'Open'{'open'}}
        $encryption=if($Security -eq 'Open'){'none'}else{'AES'}
        $ns='http://www.microsoft.com/networking/WLAN/profile/v1'
        $buffer=[System.Text.StringBuilder]::new()
        $settings=[System.Xml.XmlWriterSettings]::new()
        $settings.OmitXmlDeclaration=$true
        $writer=[System.Xml.XmlWriter]::Create($buffer,$settings)
        $writer.WriteStartElement('WLANProfile',$ns)
        $writer.WriteElementString('name',$ns,$ProfileName)
        $writer.WriteStartElement('SSIDConfig',$ns)
        $writer.WriteStartElement('SSID',$ns)
        $writer.WriteElementString('hex',$ns,([BitConverter]::ToString($ssidBytes).Replace('-','')))
        $writer.WriteElementString('name',$ns,$SSID)
        $writer.WriteEndElement()
        $writer.WriteElementString('nonBroadcast',$ns,([bool]$Hidden).ToString().ToLowerInvariant())
        $writer.WriteEndElement()
        $writer.WriteElementString('connectionType',$ns,'ESS')
        $writer.WriteElementString('connectionMode',$ns,$ConnectionMode.ToLowerInvariant())
        $writer.WriteStartElement('MSM',$ns)
        $writer.WriteStartElement('security',$ns)
        $writer.WriteStartElement('authEncryption',$ns)
        $writer.WriteElementString('authentication',$ns,$authentication)
        $writer.WriteElementString('encryption',$ns,$encryption)
        $writer.WriteElementString('useOneX',$ns,'false')
        $writer.WriteEndElement()
        if($Security -ne 'Open') {
            $writer.WriteStartElement('sharedKey',$ns)
            $writer.WriteElementString('keyType',$ns,'passPhrase')
            $writer.WriteElementString('protected',$ns,'false')
            $writer.WriteElementString('keyMaterial',$ns,$plain)
            $writer.WriteEndElement()
        }
        $writer.WriteEndElement()
        $writer.WriteEndElement()
        $writer.WriteEndElement()
        $writer.Flush()
        [pscustomobject]@{Name=$ProfileName;Xml=$buffer.ToString()}
    }
    finally {
        if($writer){$writer.Dispose()}
        if($pointer -ne [IntPtr]::Zero){[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($pointer)}
        $plain=$null
    }
}