-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPSActiveNetworkSwitcher.psm1
More file actions
224 lines (186 loc) · 11 KB
/
PSActiveNetworkSwitcher.psm1
File metadata and controls
224 lines (186 loc) · 11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<#
.SYNOPSIS
Module to automate the switching of network connection states by having certain adapters disabled when other adapters are connected.
.DESCRIPTION
Can be used in automation or deployed to devices running Windows 8 or later. This module will not work Windows 7 or Earlier (regardless of PS version) due to Get-NetAdapter limitations.
Facilitating cleaner network switching when roaming between Ethernet and WiFi, on and off corporate networks and to better control the security of endpoints on the network.
It is intended for this script to be used in a scheduled task and triggered by network state change event log.
.EXAMPLE
TODO:
PS C:\> <example usage>
Explanation of what the example does
.INPUTS
None
.OUTPUTS
None
.NOTES
GitHub Source: https://github.com/aglasson/PSActiveNetworkSwitcher
This script uses an Apache License 2.0 permitting commercial use, modification and distribution.
#>
#---- General Functions ----#
function Switch-PSActiveNetwork {
[CmdletBinding()]
Param(
# If true will instead of selecting ethernet with lowest interface number allow multiple enabled.
[Parameter(Mandatory = $false)]
[switch]
$AllowMultiEth
)
Write-Log "Running 'Switch-PSActiveNetwork'"
# Simple logic: IF ethernet connected THEN switch off wireless ELSE switch on wireless.
# IF multiple, select the ethernet with lowest interface number.
$PerfMetricsStart = Get-Date
# Get Airplane mode state and stop if active
$AirplaneModeState = (Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\RadioManagement\SystemRadioState\).'(default)'
Write-Verbose "Airplane mode detected state: $AirplaneModeState"
if ($AirplaneModeState -eq 1) {
Write-Log "Airplane mode enabled, taking no action on adapter switching."
Return
}
# Get network devices and their states
$PhysicalAdapterList = Get-NetAdapter -Physical | Where-Object { $_.PhysicalMediaType -ne "Unspecified" } | Select-Object Name, ifIndex, PhysicalMediaType, Status
Write-Verbose "Output of {Get-NetAdapter -Physical} $($PhysicalAdapterList | Out-String)"
$WirelessAdapterList = $PhysicalAdapterList | Where-Object { $_.PhysicalMediaType -in ("Native 802.11", "Wireless WAN") }
$WirelessAdapterUpList = $WirelessAdapterList | Where-Object { $_.Status -eq "Up" }
$EthernetAdapterList = $PhysicalAdapterList | Where-Object { $_.PhysicalMediaType -eq "802.3" }
$EthernetAdapterUpList = $EthernetAdapterList | Where-Object { $_.Status -eq "Up" }
Write-Verbose ("Ethernet Adapater in 'Up' status: " + ($EthernetAdapterUpList | Measure-Object).Count)
if (($EthernetAdapterUpList | Measure-Object).Count -eq 1) {
Write-Log "Single 'Up' Ethernet Adapter Detected."
Write-Verbose "Wireless net adapters to be disabled: $($WirelessAdapterList | Out-String)"
Write-Log "Disabling wireless net adapters."
$WirelessAdapterList | ForEach-Object { Get-NetAdapter -ifIndex $_.ifIndex | Disable-NetAdapter -Confirm:$False }
} elseif (((($EthernetAdapterUpList | Measure-Object).Count) -gt 1)) {
Write-Log "More than one 'Up' Ethernet Adapter Detected."
if ($AllowMultiEth) {
Write-Log "-AllowMultiEth `$True so disabling all but Ethernet adapters."
$WirelessAdapterList | ForEach-Object { Get-NetAdapter -ifIndex $_.ifIndex | Disable-NetAdapter -Confirm:$False }
} else {
Write-Log "-AllowMultiEth `$False so disabling all Wirless and 'Up' Ethernet except 'Up' Eth with lowest ifIndex number."
$WirelessAdapterList | ForEach-Object { Get-NetAdapter -ifIndex $_.ifIndex | Disable-NetAdapter -Confirm:$False }
$EthernetMultiLowest = ($EthernetAdapterUpList | Measure-Object -Minimum -Property ifIndex).Minimum
Write-Verbose "'Up' Eth with lowest ifIndex number $($EthernetAdapterUpList | Where-Object {$_.ifIndex -ne $EthernetMultiLowest})"
$EthernetAdapterUpList | Where-Object { $_.ifIndex -ne $EthernetMultiLowest } | ForEach-Object { Get-NetAdapter -ifIndex $_.ifIndex | Disable-NetAdapter -Confirm:$False }
}
Write-Log "Multiple up ethernet adapters identified and -AllowMultiEth `$True, enabling wireless net adapters."
} elseif (((($EthernetAdapterUpList | Measure-Object).Count) -eq 0) -and (($WirelessAdapterUpList | Measure-Object).Count -gt 0)) {
Write-Verbose "No 'up' ethernet adapters identified, at least one 'up' wireless adapter."
if ((($WirelessAdapterUpList | Measure-Object).Count) -ge 2) {
if ((($WirelessAdapterUpList | Where-Object { $_.PhysicalMediaType -eq "Native 802.11" } | Measure-Object).Count) -eq 1) {
Write-Log "Only 1 'up' Wireless LAN adapters identified so disabling Wireless WAN adapters only."
$WirelessAdapterUpList | Where-Object { $_.PhysicalMediaType -eq "Wireless WAN" } | ForEach-Object { Get-NetAdapter -ifIndex $_.ifIndex | Disable-NetAdapter -Confirm:$False }
} else {
Write-Log "More than 1 'up' Wireless LAN adapters identified so disabling Wireless WAN and Wireless LAN except with lowest ifIndex number."
$WirelessLANMultiLowest = ($WirelessAdapterUpList | Where-Object { $_.PhysicalMediaType -eq "Native 802.11" } | Measure-Object -Minimum -Property ifIndex).Minimum
$WirelessAdapterUpList | Where-Object { $_.ifIndex -ne $WirelessLANMultiLowest } | ForEach-Object { Get-NetAdapter -ifIndex $_.ifIndex | Disable-NetAdapter -Confirm:$False }
}
} else {
Write-Log "Only one 'up' wireless adapter identified, no action required."
}
} else {
Write-Log "Criteria not met, enabling all net adapters."
Get-NetAdapter | Enable-NetAdapter -Confirm:$False
}
$TimeSpan = "{0:g}" -f (New-TimeSpan -Start $PerfMetricsStart -End (Get-Date))
Write-Log "Switch network time to run: $TimeSpan"
}
#---- Deploy Functions ----#
function Install-PSActiveNetwork {
[CmdletBinding()]
param (
# The path to the module files that will be copied to the task schedule runner location
[Parameter( Mandatory = $false,
HelpMessage = "to the module files that will be copied to the task schedule runner location.")]
[Alias("PSPath")]
[ValidateScript( { Test-Path ((Get-ChildItem -Path $_) | Where-Object { $_.Name -eq "SidelineScripts" }).FullName })]
[string]
$Path,
# The path to the module installation location
[Parameter( Mandatory = $false,
HelpMessage = "Path to a location for the module to be installed to. By default `'C:\Program Files\WindowsPowerShell\Modules`'.")]
[string]
$Destination = "C:\Program Files\WindowsPowerShell\Modules\PSActiveNetworkSwitcher"
# TODO:
# ^ This is currently the only supported destination within the Task Scheduler config that gets imported.
)
$PerfMetricsStart = Get-Date
if (!$Path -and ((Split-Path $PSCommandPath) -eq $Destination)) {
Write-Log "INSTALL: No path specified but `$PSCommandPath matches `$Destination so skipping module install"
$Path = $Destination
}
elseif ($Path) {
Write-Log "INSTALL: Path specified, proceeding with copying module files to '$Destination'"
if (!(Test-Path $Destination)) {
Write-Log "INSTALL: Destination path does not exist, creating dirs: '$Destination'"
New-Item -Path $Destination -ItemType Directory | Out-Null
}
Get-ChildItem -Path $Path -Exclude ".git" | Copy-Item -Destination $Destination -Recurse -Force -ErrorAction Stop
Write-Log "INSTALL: Module contents copy from source to destination Success."
}
else {
Write-Log "INSTALL: ERROR: No path specified and `$PSCommandPath does NOT match `$Destination so assuming failed intention of installing module."
Throw "Path required when intending to install module as well."
}
# Create/replace scheduled task.
$Command = "schtasks /create /xml `"$(Join-Path $Path 'SidelineScripts\PSActiveNetworkSwitcher Event Runner.xml')`" /tn `"PSActiveNetworkSwitcher Event Runner`" /ru SYSTEM /F"
Write-Log "INSTALL: Running create scheduled task (overwrite if exists) `'$Command`'"
$CmdRun = "cmd.exe /c $Command 2>&1"
$Results = Invoke-Command -ScriptBlock { $CmdRun }
if ($Results -like "SUCCESS*") {
Write-Log "INSTALL: Create/replace scheduled task completed successfully."
} else {
$Results
}
# Check for excess counts of scheduled tasks.
$RelatedSchedTasks = Get-ScheduledTask *networkswitcher*
if (($RelatedSchedTasks | Measure-Object).Count -gt 1) {
Write-Warning "INSTALL: Found more than one scheduled tasks matching '*networkswitcher*'."
Write-Log "INSTALL: WARNING: Found more than one scheduled tasks matching '*networkswitcher*'." -NoVerbose
Write-Verbose "INSTALL: These scheduled tasks from {Get-ScheduledTask *networkswitcher*} have been found: $($RelatedSchedTasks | Select-Object TaskName | Out-String)"
}
$TimeSpan = "{0:g}" -f (New-TimeSpan -Start $PerfMetricsStart -End (Get-Date))
Write-Log "INSTALL: PSActiveNetworkSwitcher install time to run: $TimeSpan"
}
#---- Logging/Output Functions ----#
Function Write-Log {
Param (
[Parameter(Mandatory = $True)]
[string]$LogMessage,
[switch]$NoVerbose
)
# Actual function to write append logfile entries
# Files will be appended with date stamp - essentially rolling daily
Function Write-LogEntry {
Param (
[string]$LogPath,
[string]$LogFileBase,
[string]$LogContent
)
# if either LogPath or LogFileBase come in empty determine values from current location and script name.
if (!$LogPath) {
# $LogPath = "$(Split-Path $PSCommandPath -Parent)\Logs\"
$LogPath = "C:\Temp\PSActiveNetworkSwitcher_Logs\"
}
if (!$LogFileBase) {
$LogFileBase = (Get-ChildItem $PSCommandPath).BaseName
}
$LogFilePath = (Join-Path -Path $LogPath -ChildPath ($LogFileBase + "_" + $(Get-Date -Format "yyyy-MM-dd") + ".log"))
if (!$VerboseOnce) {
$Script:VerboseOnce = $True
Write-Verbose "LogPath determined as `'$LogPath`'"
Write-Verbose "LogFileBase determined as `'$LogFileBase`'"
Write-Verbose "LogFile determined as `'$LogFilePath`'"
}
# If required log path does not exist create it
if (!(Test-Path $LogPath)) {
Write-Verbose "Logging directory/s do no exists, creating path: '$LogPath'"
New-Item $LogPath -ItemType Directory -Force | Out-Null
}
# Write line to logfile prepending the line with date and time
Add-Content -Path $LogFilePath -Value "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss.ms"): $LogContent"
}
Write-LogEntry -LogPath $logPath -LogFileBase $logFileBase -LogContent $LogMessage
if (!$NoVerbose) {
Write-Verbose -Message $LogMessage
}
}