Public/network/Reset-NetworkStack.ps1
|
#Requires -Version 5.1 function Reset-NetworkStack { <# .SYNOPSIS Reset the Windows network stack (winsock, TCP/IP, DNS cache, ARP) .DESCRIPTION Encapsulates the classic netsh network-repair sequence (netsh winsock reset and netsh int ip reset) plus a DNS client cache flush and ARP cache clear into one idempotent, ShouldProcess-guarded action. Returns a structured result listing each step that ran with its exit code, overall success, and RebootRequired (always true). Requires administrator privileges and ALWAYS needs a reboot to finalize. WARNING: on a remote target `netsh int ip reset` can drop the WinRM session mid-run, so verify results out-of-band after running remotely. .PARAMETER ComputerName One or more computer names to target. Defaults to the local computer. Accepts pipeline input by value and by property name. .PARAMETER Credential Optional PSCredential for authenticating to remote computers. Ignored for local machine operations. .PARAMETER IncludeFirewall Opt-in switch. Adds a `netsh advfirewall reset` step, which is more intrusive (resets all Windows Firewall profiles and rules to their default state). .PARAMETER SkipDnsFlush Opt-in switch. Skips the DNS client cache flush step (Clear-DnsClientCache). .EXAMPLE Reset-NetworkStack Local usage example. .EXAMPLE Reset-NetworkStack -ComputerName SRV01 -IncludeFirewall Remote single-machine example. .EXAMPLE 'SRV01', 'SRV02' | Reset-NetworkStack -SkipDnsFlush Pipeline usage example. .OUTPUTS PSWinOps.NetworkStackResetResult One object per target machine describing the steps that ran, their exit codes, overall Success, and RebootRequired (always $true). .NOTES Author: Franck SALLET Version: 1.0.0 Last Modified: 2026-07-06 Requires: PowerShell 5.1+ / Windows only Requires: Administrator privileges (winsock/int ip/advfirewall reset) WARNING: netsh int ip reset can drop the WinRM session on a remote target mid-run; verify results out-of-band after running remotely. .LINK https://github.com/k9fr4n/PSWinOps .LINK https://learn.microsoft.com/en-us/windows-server/networking/technologies/netsh/netsh-interface-ip #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] [OutputType('PSWinOps.NetworkStackResetResult')] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [ValidateNotNullOrEmpty()] [string[]]$ComputerName = $env:COMPUTERNAME, [Parameter(Mandatory = $false)] [System.Management.Automation.PSCredential]$Credential, [Parameter(Mandatory = $false)] [switch]$IncludeFirewall, [Parameter(Mandatory = $false)] [switch]$SkipDnsFlush ) begin { Write-Verbose "[$($MyInvocation.MyCommand)] Starting network stack reset" if (-not (Test-IsAdministrator)) { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.UnauthorizedAccessException]::new('Reset-NetworkStack requires Administrator privileges.'), 'ElevationRequired', [System.Management.Automation.ErrorCategory]::PermissionDenied, $null ) ) } $netshPath = Join-Path -Path $env:SystemRoot -ChildPath 'System32\netsh.exe' if (-not (Test-Path -Path $netshPath -PathType Leaf)) { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.IO.FileNotFoundException]::new("netsh.exe not found at '$netshPath'."), 'NetshNotFound', [System.Management.Automation.ErrorCategory]::ObjectNotFound, $netshPath ) ) } $resetScriptBlock = { param( [string]$NetshPath, [bool]$SkipDns, [bool]$IncludeFw ) $stepsRun = [System.Collections.Generic.List[psobject]]::new() # WinsockReset — always run $winsockResult = Invoke-NativeCommand -FilePath $NetshPath -ArgumentList @('winsock', 'reset') $stepsRun.Add([PSCustomObject]@{ Step = 'WinsockReset'; ExitCode = $winsockResult.ExitCode }) # IpReset — always run (may drop WinRM on a remote target) $ipResult = Invoke-NativeCommand -FilePath $NetshPath -ArgumentList @('int', 'ip', 'reset') $stepsRun.Add([PSCustomObject]@{ Step = 'IpReset'; ExitCode = $ipResult.ExitCode }) # DnsFlush — skipped when SkipDns is set if (-not $SkipDns) { try { Clear-DnsClientCache -ErrorAction Stop $stepsRun.Add([PSCustomObject]@{ Step = 'DnsFlush'; ExitCode = 0 }) } catch { $stepsRun.Add([PSCustomObject]@{ Step = 'DnsFlush'; ExitCode = 1 }) } } # ArpClear — always run try { Clear-Arp -Confirm:$false -ErrorAction Stop $stepsRun.Add([PSCustomObject]@{ Step = 'ArpClear'; ExitCode = 0 }) } catch { $stepsRun.Add([PSCustomObject]@{ Step = 'ArpClear'; ExitCode = 1 }) } # FirewallReset — opt-in only if ($IncludeFw) { $fwResult = Invoke-NativeCommand -FilePath $NetshPath -ArgumentList @('advfirewall', 'reset') $stepsRun.Add([PSCustomObject]@{ Step = 'FirewallReset'; ExitCode = $fwResult.ExitCode }) } $overallSuccess = -not ($stepsRun | Where-Object { $_.ExitCode -ne 0 }) [PSCustomObject]@{ StepsRun = $stepsRun.ToArray() Success = [bool]$overallSuccess } } } process { foreach ($targetComputer in $ComputerName) { try { $shouldProcessTarget = "network stack on $targetComputer" $shouldProcessAction = 'Reset (winsock + int ip + dns + arp' + $(if ($IncludeFirewall) { ' + firewall' } else { '' }) + ')' if (-not $PSCmdlet.ShouldProcess($shouldProcessTarget, $shouldProcessAction)) { continue } $invokeParams = @{ ComputerName = $targetComputer ScriptBlock = $resetScriptBlock ArgumentList = @($netshPath, [bool]$SkipDnsFlush, [bool]$IncludeFirewall) Credential = $Credential } $rawResult = Invoke-RemoteOrLocal @invokeParams [PSCustomObject]@{ PSTypeName = 'PSWinOps.NetworkStackResetResult' ComputerName = $targetComputer StepsRun = $rawResult.StepsRun Success = $rawResult.Success RebootRequired = $true Timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' } } catch { Write-Error "[$($MyInvocation.MyCommand)] Failed on '$targetComputer': $_" } } } end { Write-Verbose "[$($MyInvocation.MyCommand)] Completed network stack reset" } } |