Files
ms-private/Network.ps1
T
0x000 41bb252214
Windows tests / test-and-build (push) Canceled after 0s
Release 0.0.6 with usable GUI diagnostics and capture controls
2026-10-01 20:27:37 -04:00

55 lines
4.6 KiB
PowerShell

#Requires -Version 5.1
[CmdletBinding(SupportsShouldProcess)]
param(
[ValidateSet('Plan','Apply','Restore','Confirm','Validate','CaptureStart','CaptureStop','CaptureConvert')][string]$Mode='Plan',
[ValidateSet('Observe','BlockOptionalTelemetry','Isolate')][string]$Profile='Observe',
[int]$RollbackMinutes=10,[string]$Journal,[string]$CaptureDirectory,[switch]$FromRecoveryTask,[switch]$Json
)
Set-StrictMode -Version Latest;$ErrorActionPreference='Stop'
Import-Module (Join-Path $PSScriptRoot 'src/Wind.Core.psm1')
Import-Module (Join-Path $PSScriptRoot 'src/Wind.Network.psm1')
$stateRoot=Join-Path ([Environment]::GetFolderPath('LocalApplicationData')) 'MsPrivate\network'
if($Mode -eq 'Plan'){$x=Get-WindNetworkPlan -Profile $Profile -RollbackMinutes $RollbackMinutes;if($Json){$x|ConvertTo-Json -Depth 8}else{$x.Items|Format-Table -Wrap};return}
if($Mode -eq 'Validate'){$x=Get-WindNetworkValidation;if($Json){$x|ConvertTo-Json -Depth 8}else{$x|Format-List};return}
if($Mode -eq 'CaptureStart'){
if(-not $CaptureDirectory){$CaptureDirectory=Join-Path $stateRoot ('capture-'+[guid]::NewGuid().ToString('N'))}
$CaptureDirectory=Resolve-WindCaptureDirectory -Path $CaptureDirectory -StateRoot $stateRoot
$etl=Join-Path $CaptureDirectory 'capture.etl';if(Test-Path -LiteralPath $etl){throw 'Capture output already exists. Choose a new capture directory.'}
if(-not $PSCmdlet.ShouldProcess($CaptureDirectory,'Start packet capture')){return}
Assert-WindMutationAllowed
[IO.Directory]::CreateDirectory($CaptureDirectory)|Out-Null
Invoke-WindPacketMonitor -ArgumentList @('start','--capture','--comp','nics','--pkt-size','0','--file-name',$etl)
[pscustomobject]@{Status='Running';Directory=$CaptureDirectory;Warning='Capture can contain private addresses and DNS names. Stop and delete or export it explicitly.'}|ConvertTo-Json
return
}
if($Mode -in @('CaptureStop','CaptureConvert')){
if(-not $CaptureDirectory){throw "$Mode requires -CaptureDirectory."};$full=Resolve-WindCaptureDirectory -Path $CaptureDirectory -StateRoot $stateRoot
$action=if($Mode-eq'CaptureStop'){'Stop packet capture and convert to PCAPNG'}else{'Convert saved packet capture to PCAPNG'}
if(-not $PSCmdlet.ShouldProcess($full,$action)){return}
Assert-WindMutationAllowed
$etl=Join-Path $full 'capture.etl';$pcap=Join-Path $full 'capture.pcapng'
if(-not(Test-Path -LiteralPath $etl -PathType Leaf)){throw 'Capture ETL file is missing; no capture was stopped.'}
if(Test-Path -LiteralPath $pcap){throw 'Converted capture already exists; preserve or move it before retrying conversion.'}
if($Mode-eq'CaptureStop'){Invoke-WindPacketMonitor -ArgumentList @('stop')}
Invoke-WindPacketMonitor -ArgumentList @('etl2pcap',$etl,'--out',$pcap)
if(-not(Test-Path -LiteralPath $pcap -PathType Leaf)){throw 'Packet capture conversion returned success without creating the PCAPNG file.'}
Save-WindJournal -Journal (Get-WindNetworkValidation) -Path (Join-Path $full 'connections.json')
Write-Output "Capture converted: $pcap";return
}
Assert-WindMutationAllowed
if($Mode -eq 'Apply'){
if($Profile -eq 'Observe'){throw 'Observe has no firewall changes to apply.'};if(-not $PSCmdlet.ShouldProcess('Windows Firewall',$Profile)){return}
[IO.Directory]::CreateDirectory($stateRoot)|Out-Null
if(-not $Journal){$Journal=Join-Path $stateRoot ((Get-Date -Format 'yyyyMMdd-HHmmss')+'-'+[guid]::NewGuid().ToString('N')+'.json')}
$runtime=Join-Path $stateRoot 'recovery-runtime';[IO.Directory]::CreateDirectory((Join-Path $runtime 'src'))|Out-Null;[IO.Directory]::CreateDirectory((Join-Path $runtime 'config'))|Out-Null
Copy-Item -LiteralPath $PSCommandPath -Destination (Join-Path $runtime 'Network.ps1') -Force
foreach($name in @('Wind.Core.psm1','Wind.Network.psm1','MsPrivate.IO.psm1')){Copy-Item -LiteralPath (Join-Path $PSScriptRoot ('src\'+$name)) -Destination (Join-Path $runtime ('src\'+$name)) -Force}
Copy-Item -LiteralPath (Join-Path $PSScriptRoot 'config\network.json') -Destination (Join-Path $runtime 'config\network.json') -Force
$result=Invoke-WindNetworkApply -Profile $Profile -RollbackMinutes $RollbackMinutes -JournalPath $Journal -RecoveryScript (Join-Path $runtime 'Network.ps1') -Confirm:$false
Write-Output "Network journal: $Journal";$result|Format-List;return
}
if(-not $Journal){throw "$Mode requires -Journal."}
$saved=Get-Content -LiteralPath $Journal -Raw|ConvertFrom-Json
$journalWriter=Get-Command Save-WindJournal -CommandType Function;$save={param($x)& $journalWriter -Journal $x -Path $Journal}.GetNewClosure()
if($Mode-eq'Confirm'){Confirm-WindNetwork -Journal $saved -Save $save|Format-List}else{Restore-WindNetwork -Journal $saved -Save $save|Format-List}