Public/Reset-WinClatConfiguration.ps1

Function Reset-WinClatConfiguration {

    <#

    .SYNOPSIS
        Returns the Windows CLAT (WinCLAT) global configuration to the Windows defaults.

    .DESCRIPTION
        Sets Pref64FromDns, Pref64FromRA, and AutoEnable to enabled, the values Windows uses when the WinCLAT feature arrives, without an export file. Runs locally or against one or more remote computers in parallel. Requires elevation on the target computer.

        Permit is changed only when -Permit is given. Microsoft disables Permit by default today and plans to enable it by default in a future release, so a plain reset leaves Permit as it is and never stops CLAT. Use -Permit Disabled for a full reset to today's defaults, or -Permit Enabled to reset and permit CLAT.

        Only settings whose persistent (local) value differs from the default are written, so the confirmation names only real changes. Every computer that was read returns four WinClat.SetResult rows, in the order Permit, Pref64FromDns, Pref64FromRA, AutoEnable: written settings report the values read back after the change, settings that already matched report Success with the message that they were not written, and without -Permit the Permit row reports its current values with the message 'Not changed; use -Permit to set it.'

        As with Set-WinClatConfiguration, settings that Group Policy controls are written locally and reported as PolicyOverride when the policy keeps a different value, and the configuration is read back after every change. A plain reset and -Permit Enabled do not ask for confirmation by default, because they only switch settings on. When -Permit Disabled would change Permit on any computer in the run, every computer in the run asks, because disabling Permit stops CLAT on every automatically enabled interface.

        Manual instances are not changed. Enabling AutoEnable leaves a manually enabled instance running, and so does disabling Permit. For a clean state, also run Set-WinClatInstance -State Disabled on each manually enabled interface, after disabling AutoEnable.

        Remote computers must have WinRM enabled, typically through Group Policy. Roaming devices may be offline at run time. Each remote computer is first checked on TCP 5985 (WinRM over HTTP); one that does not answer within 2 seconds, or whose name does not resolve, is returned as Unreachable at once instead of after a WinRM timeout. Failures are not written as errors: every computer returns its result with a Status and a Message that explains it, and when a run for several computers has any computer that did not complete, one warning at the end gives the count. To list them, filter the results, for example with Where-Object -FilterScript { $_.Status -ne 'Success' }.

        The function does not write a log. Piping the results to Export-Csv keeps a complete record of a run.

    .PARAMETER Permit
        Also sets Permit: Disabled for a full reset to today's Windows defaults, or Enabled to permit CLAT. When omitted, Permit is not changed. Disabling Permit disables CLAT on every interface where it was automatically enabled, blocks new manual enables, and asks for confirmation, but a manually enabled instance that is already running keeps translating.

    .PARAMETER ComputerName
        One or more computers to reset. Accepts pipeline input by value and by property name, including objects from Get-ADComputer and Get-ADObject; DNSHostName is preferred over Name. Blank values and values beginning with '#' are ignored, so Get-Content output can be piped directly. Defaults to the local computer.

    .PARAMETER Credential
        Credentials used to connect to remote computers. Not used for the local computer.

    .PARAMETER ThrottleLimit
        Maximum number of concurrent remote connections. The default is 32.

    .INPUTS
        System.String. Computer names.

        System.Management.Automation.PSObject. Objects with a DNSHostName, ComputerName, Name, or CN property, such as those from Get-ADComputer and Get-ADObject.

    .OUTPUTS
        WinClat.SetResult. When a run returns exactly one result, it also carries the type name WinClat.SetResult#Single, which selects a list view instead of the default table.

    .EXAMPLE
        Reset-WinClatConfiguration

        Sets Pref64FromDns, Pref64FromRA, and AutoEnable to enabled on the local computer and leaves Permit unchanged.

    .EXAMPLE
        Reset-WinClatConfiguration -ComputerName CLIENT4 -Permit Disabled

        Returns CLIENT4 to today's Windows defaults, including Permit disabled, after confirmation.

    .EXAMPLE
        Set-WinClatConfiguration -ComputerName CLIENT4 -AutoEnable Disabled -Confirm:$false
        Set-WinClatInstance -ComputerName CLIENT4 -InterfaceAlias 'Ethernet' -State Disabled -Confirm:$false
        Reset-WinClatConfiguration -ComputerName CLIENT4

        Resets CLIENT4 to the Windows defaults with no manually enabled instance left running on its Ethernet adapter. A reset does not change manual instances, and Set-WinClatInstance refuses -State Disabled while AutoEnable is enabled, so AutoEnable is disabled first, which briefly stops CLAT on every automatically enabled interface. The reset then enables AutoEnable again, and Windows starts CLAT on each eligible interface by itself.

    .EXAMPLE
        Get-Content -Path .\clients.txt | Reset-WinClatConfiguration -WhatIf

        Shows which settings a reset would change on each computer in clients.txt, without changing anything.

    .EXAMPLE
        Get-ADComputer -Filter 'Name -like "LAB*"' | Reset-WinClatConfiguration -Permit Enabled | Export-Csv -Path .\WinClatReset.csv -NoTypeInformation

        Resets every LAB computer in Active Directory with CLAT permitted, and records the results in WinClatReset.csv.

    .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/

        See docs/DESIGN.md, section 7.8.

    #>


    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium', PositionalBinding = $false)]
    [OutputType('WinClat.SetResult')]

    Param (

        # Enabled or Disabled, like Set-WinClatConfiguration (DESIGN.md, section 7.8).
        [ValidateSet('Enabled', 'Disabled')]
        [string]$Permit,

        [Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName)]
        [Alias('DNSHostName', 'CN', 'Name')]
        [string[]]$ComputerName = $env:COMPUTERNAME,

        [PSCredential]$Credential,

        [ValidateRange(1, 1024)]
        [int]$ThrottleLimit = 32

    )

    Begin {

        # The Windows defaults (DESIGN.md, section 7.8). A plain hashtable, so ContainsKey works on the target whether it
        # arrives deserialized or in a local runspace.
        $WinClatRequested = @{

            Pref64FromDns = $true
            Pref64FromRA  = $true
            AutoEnable    = $true

        }

        $Report = @{}

        If ($PSBoundParameters.ContainsKey('Permit')) {

            $WinClatRequested['Permit'] = $Permit -eq 'Enabled'

        }

        Else {

            $Report['Permit'] = 'Not changed; use -Permit to set it.'

        }

        $Targets = New-Object -TypeName 'System.Collections.Generic.List[string]'

    }

    Process {

        # Read $_ only for pipeline input; otherwise it may be an outer ForEach-Object variable.
        $PipelineObject = $null

        If ($MyInvocation.ExpectingInput) {

            $PipelineObject = $_

        }

        ForEach ($Name in @(Get-WinClatTargetName -InputObject $PipelineObject -ComputerName $ComputerName -Cmdlet $PSCmdlet)) {

            $Targets.Add($Name)

        }

    }

    End {

        $Shared = @{

            ThrottleLimit = $ThrottleLimit
            Cmdlet        = $PSCmdlet

        }

        If ($Credential) {

            $Shared['Credential'] = $Credential

        }

        # One summary warning at the end instead of an error per computer (DESIGN.md, section 4.6). For a single computer the
        # results are held, so exactly one is shown as a list and several as a table (section 6); fleet results still stream.
        $Tally = New-WinClatTally -ComputerName $Targets.ToArray()

        # Pass 1: read every computer, keeping only the settings that differ from the defaults.
        $Items = @(Get-WinClatConfigurationPlan @Shared -ComputerName $Targets.ToArray() -Requested $WinClatRequested -Report $Report -OnlyChanged)

        # Disabling permit stops CLAT on every automatically enabled interface, so the run confirms like ConfirmImpact High.
        # The preference is read at the first ShouldProcess call, so it applies to every computer in the run.
        If (@($Items | Where-Object -FilterScript { $_.PSObject.TypeNames[0] -eq 'WinClat.ConfigurationPlan' -and $_.DisablesPermit }).Count -gt 0 -and $ConfirmPreference -eq 'High') {

            $ConfirmPreference = 'Medium'

        }

        $Unchanged = ''

        If ($Report.ContainsKey('Permit')) {

            $Unchanged = ' Permit is left unchanged; use -Permit to set it.'

        }

        $Run = New-Object -TypeName 'System.Collections.Generic.List[object]'

        ForEach ($Item in $Items) {

            If ($Item.PSObject.TypeNames[0] -ne 'WinClat.ConfigurationPlan') {

                $Item | Measure-WinClatResult -Tally $Tally
                Continue

            }

            # Nothing differs, so there is nothing to confirm; the unchanged rows are still returned.
            If ($Item.Change.Count -eq 0 -or $PSCmdlet.ShouldProcess($Item.ComputerName, "Reset to the Windows defaults. $($Item.Action)$Unchanged")) {

                $Run.Add($Item)

            }

        }

        # Pass 2: change the confirmed computers and verify by reading the configuration back.
        If ($Run.Count -gt 0) {

            Invoke-WinClatConfigurationChange @Shared -Plan $Run.ToArray() | Measure-WinClatResult -Tally $Tally

        }

        Complete-WinClatResult -Tally $Tally

        Write-WinClatFailureSummary -Tally $Tally -Action 'changed' -Cmdlet $PSCmdlet

    }

}