Private/Get-WinClatExportScript.ps1
|
Function Get-WinClatExportScript { <# .SYNOPSIS Returns the self-contained script block that Export-WinClatConfiguration runs on each target. .DESCRIPTION The script block takes no arguments and returns one object (DESIGN.md, section 7.5): 1. Feature check: 'clat' in the 'netsh interface ?' sub-context list. If absent, returns a WinClat.ExportResult with Status NotSupported on Windows Server or FeatureNotAvailable on a client (Get-WinClatFeatureFailure). 2. Runs 'netsh.exe interface clat dump', which does not require elevation. A non-zero exit code is classified with Get-WinClatNetshFailure. 3. Parses the output with ConvertFrom-WinClatDump, the strict parser Import-WinClatConfiguration also uses, into Permit, Pref64FromDns, Pref64FromRA, and AutoEnable. Output that is not a WinCLAT configuration script returns Failed, so no file is written. 4. Reads the policy registry key with Get-WinClatPolicyControlled and returns a WinClat.ExportData object with the dump text in Content. dump exports the persistent (local) values, not values set by Group Policy (section 10), so replaying a file restores the local configuration. Export-WinClatConfiguration and the unit tests both use this function, so the tests exercise the script block that is sent remotely. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.Management.Automation.ScriptBlock. .EXAMPLE & (Get-WinClatExportScript) Returns the dump of the local computer as a WinClat.ExportData object. .LINK https://learn.microsoft.com/windows-server/administration/windows-commands/netsh .NOTES Version: 1.0.0 Creation Date: October 28, 2026 Last Updated: October 28, 2026 Author: Richard Hicks Organization: Richard M. Hicks Consulting, Inc. Contact: rich@richardhicks.com Website: https://www.richardhicks.com/ #> [CmdletBinding()] [OutputType([scriptblock])] Param () $HelperName = @( 'ConvertFrom-WinClatDump' 'ConvertTo-WinClatExportResult' 'Get-WinClatNetshFailure' 'Get-WinClatPolicyControlled' 'Get-WinClatFeatureFailure' 'Test-WinClatFeature' ) $Body = { If (-not (Test-WinClatFeature -InputObject @(netsh.exe interface '?'))) { # NotSupported on Windows Server, FeatureNotAvailable on a client that has not received the feature. $Missing = Get-WinClatFeatureFailure $Failure = @{ ComputerName = $env:COMPUTERNAME Status = $Missing.Status CollectedAtUtc = (Get-Date).ToUniversalTime() Message = $Missing.Message } ConvertTo-WinClatExportResult @Failure Return } $Output = @(netsh.exe interface clat dump) $ExitCode = $LASTEXITCODE $CollectedAtUtc = (Get-Date).ToUniversalTime() If ($ExitCode -ne 0) { $Classified = Get-WinClatNetshFailure -InputObject $Output -ExitCode $ExitCode ConvertTo-WinClatExportResult -ComputerName $env:COMPUTERNAME -Status $Classified.Status -CollectedAtUtc $CollectedAtUtc -Message $Classified.Message Return } # The same strict parser that Import-WinClatConfiguration uses, so every file written can be imported. $Parsed = ConvertFrom-WinClatDump -InputObject $Output If ($Parsed.Problem) { ConvertTo-WinClatExportResult -ComputerName $env:COMPUTERNAME -Status 'Failed' -CollectedAtUtc $CollectedAtUtc -Message "netsh.exe did not return a WinCLAT configuration script, so nothing was exported: $($Parsed.Problem)" Return } $Settings = $Parsed.Settings $Result = @{ ComputerName = $env:COMPUTERNAME Status = 'Success' Settings = $Settings PolicyControlled = Get-WinClatPolicyControlled CollectedAtUtc = $CollectedAtUtc Content = (@($Output | ForEach-Object -Process { "$_" }) -join "`r`n") + "`r`n" } ConvertTo-WinClatExportResult @Result } Get-WinClatRemoteScript -HelperName $HelperName -ScriptBlock $Body } |