1+ <#
2+ . SYNOPSIS
3+ Set interface metrics for physical adapters only.
4+ - Disconnected physical adapters => metric 100
5+ - Connected physical adapters => metric 10 (except when both wired+wifi are Up: wired=10, wifi=50)
6+ - Use -Trial to preview planned changes without applying them
7+ #>
8+
9+ param (
10+ [switch ]$Trial
11+ )
12+
13+ # Patterns (adjust if your adapter names differ)
14+ $wiredPatterns = @ (' Ethernet*' , ' Local Area Connection*' )
15+ $wifiPatterns = @ (' Wi-Fi*' , ' Wi‑Fi*' , ' Wireless Network Connection*' , ' Wireless*' )
16+
17+ function MatchesPattern ($alias , $patterns ) {
18+ foreach ($p in $patterns ) { if ($alias -like $p ) { return $true } }
19+ return $false
20+ }
21+
22+ # Get only physical adapters
23+ $allAdapters = Get-NetAdapter - Physical - ErrorAction SilentlyContinue
24+
25+ if (-not $allAdapters ) {
26+ Write-Host " No physical adapters found. Exiting."
27+ return
28+ }
29+
30+ # Detect Up wired and Up wifi presence (physical adapters only)
31+ $upAdapters = $allAdapters | Where-Object { $_.Status -eq ' Up' }
32+ $upWired = $upAdapters | Where-Object { MatchesPattern $_.InterfaceAlias $wiredPatterns }
33+ $upWifi = $upAdapters | Where-Object { MatchesPattern $_.InterfaceAlias $wifiPatterns }
34+
35+ $planned = @ ()
36+
37+ foreach ($a in $allAdapters ) {
38+ $alias = $a.InterfaceAlias.Trim ()
39+ if ([string ]::IsNullOrWhiteSpace($alias )) { continue }
40+ $ipif = Get-NetIPInterface - InterfaceAlias $alias - AddressFamily IPv4 - ErrorAction SilentlyContinue | Select-Object - First 1
41+ $current = ($ipif.InterfaceMetric -as [int ])
42+
43+ if ($a.Status -eq ' Disconnected' ) {
44+ $typeVal = if (MatchesPattern $alias $wiredPatterns ) { ' Wired' } elseif (MatchesPattern $alias $wifiPatterns ) { ' Wireless' } else { ' Other' }
45+ $planned += [pscustomobject ]@ {
46+ InterfaceAlias = $alias
47+ Status = $a.Status
48+ Type = $typeVal
49+ CurrentMetric = $current
50+ PlannedMetric = 100
51+ Reason = ' Disconnected'
52+ }
53+ continue
54+ }
55+
56+ if ($a.Status -eq ' Up' ) {
57+ if (($upWired.Count -gt 0 ) -and ($upWifi.Count -gt 0 )) {
58+ # Both present: prefer wired
59+ if (MatchesPattern $alias $wiredPatterns ) {
60+ $pm = 10
61+ $reason = ' Wired up (prefer)'
62+ } elseif (MatchesPattern $alias $wifiPatterns ) {
63+ $pm = 50
64+ $reason = ' Wi‑Fi up (deprioritized because wired also up)'
65+ } else {
66+ $pm = 10
67+ $reason = ' Other Up'
68+ }
69+ }
70+ else {
71+ # Not both present: any Up physical adapter gets 10
72+ $pm = 10
73+ $reason = ' Only adapter type Up => prioritized'
74+ }
75+
76+ $typeVal = if (MatchesPattern $alias $wiredPatterns ) { ' Wired' } elseif (MatchesPattern $alias $wifiPatterns ) { ' Wireless' } else { ' Other' }
77+
78+ $planned += [pscustomobject ]@ {
79+ InterfaceAlias = $alias
80+ Status = $a.Status
81+ Type = $typeVal
82+ CurrentMetric = $current
83+ PlannedMetric = $pm
84+ Reason = $reason
85+ }
86+ }
87+ }
88+
89+ if ($planned.Count -eq 0 ) {
90+ Write-Host " No planned changes determined for physical adapters."
91+ return
92+ }
93+
94+ Write-Host " Planned changes:`n "
95+ $planned | Sort-Object Type, InterfaceAlias | Format-Table InterfaceAlias, Status, Type, CurrentMetric, PlannedMetric, Reason - AutoSize
96+
97+ if ($Trial ) {
98+ Write-Host " `n Trial mode enabled: no changes will be applied."
99+ return
100+ }
101+
102+ # Apply only when different
103+ foreach ($p in $planned ) {
104+ if ($p.CurrentMetric -eq $p.PlannedMetric ) {
105+ Write-Host " No change required for '$ ( $p.InterfaceAlias ) ' (metric already $ ( $p.CurrentMetric ) )."
106+ continue
107+ }
108+ try {
109+ Write-Host " Setting metric $ ( $p.PlannedMetric ) on interface '$ ( $p.InterfaceAlias ) ' (was $ ( $p.CurrentMetric ) )."
110+ Set-NetIPInterface - InterfaceAlias $p.InterfaceAlias - InterfaceMetric $p.PlannedMetric - ErrorAction Stop
111+ }
112+ catch {
113+ Write-Warning " Failed to set metric on '$ ( $p.InterfaceAlias ) ': $ ( $_.Exception.Message ) "
114+ }
115+ }
116+
117+ Write-Host " Done."
0 commit comments