Summary: Jeremy Engel, provides expert commentary for 2012 Scripting Games Advanced Event 8.
Microsoft Scripting Guy, Ed Wilson, is here. Jeremy Engel is the expert commentator for Advanced Event 8.
Jeremy works in the health care industry as a lead systems engineer and architect, promoting new technologies and helping drive their acceptance and implementation. Being a fanatic of efficiency and automation, he also focuses on developing programs and scripts to ease the burden of administration for himself, his colleagues, and the community. His most notable contribution thus far is the PowerShell Module for DHCP. He is currently working on releasing a multitude of other modules and scripts.
He is a great admirer of the Windows PowerShell community and is honored to be a judge for this year’s Scripting Games. He wishes all the contestant’s happy scripting and good luck! Jeremy’s proudest contributions to this world are his three wonderful children, who together with his beautiful wife live in the bustling metropolis of Oak Ridge, North Carolina.
When I was developing my script for the 2012 Scripting Games Advanced Event 8, the first question I asked myself was how best to differentiate between wired and wireless connections. I began by examining the Win32_NetworkAdapter class, but I couldn’t find any reliable method therein of determining the physical media type. I thought about scanning the NetConnectionID for indicators like “Wireless” or “Local Area Connection” but those were horribly imprecise, especially given the ability of users to rename them to whatever they wanted. Even without renaming the network connection on my Win8 slate, I found that the wired adapter was named “Wired Ethernet Connection” and the wireless adapter, “Wi-Fi.” As you can see, there was just no way to plan for all the possibilities. Now, as it happened, I had the beta copy of Windows PowerShell 3.0 installed on my laptop, so on a whim I typed “Get-Net” and tabbed out. To my delight a Get-Net6to4Configuration cmdlet popped up, and two tabs later, I came upon Get-NetAdapter!
Lo and behold, there it was: the PhysicalMediaType property, and it differentiated between 802.11 (wireless) and 802.3 (wired) among others. While the NetAdpater.Types.ps1 xml says that the PhysicalMediaType strings will appear as “802.3” and “Native 802.11,” I decided not to use the –eq operator when filtering, but rather the –match operator, just in case additional 802.3/11 media types would be defined in the future. I also wanted to differentiate between connection state and device state. The AdminStatus property worked best for the device state, with its Up and Down designations. And although the Status property displayed aspects of the connection state, it appeared to be a viewer-friendly overall status pulling from multiple sources. That’s good for what it is, but a truer property to determine the connection state seemed to me to be MediaConnectionState.
Why did I care about the connection state when the event parameters didn’t call for any such analysis? When writing a script, I always try to think about who is going to use the script and what they might be expecting. Thus I wanted to show a warning message should the adapter that’s toggled into the enabled state be disconnected. That way the user can take corrective action right away, whether that be to plug-in a network cable or join a wireless network, rather than determine at some later point that they are not connected to any network.
As part of the Event 8 requirements, users are to be prompted if more than one of the network adapters are enabled or disabled. I planned for that and then took it a step further and decided to give the user the ability to specify which adapter(s) they wanted to include in the toggling process. That would allow them to bypass the multiadapter prompt.
Lastly, by typing Get-Command –Noun NetAdapter into Windows PowerShell, I found the Disable and Enable companion cmdlets that I would need to complete my script’s functionality.
With my requirements and desired logic delineated, writing the script was pretty simple. I separated the logic for selecting the appropriate adapter and put it in its own function for two reasons: one, I wanted to be able to loop should the user provide an invalid selection; and two, I needed to use the code in four different instances and I didn’t want to have to repeat the same code over and over again. Also, I discovered that I needed to add a Start-Sleep line to give the newly enabled network adapter a chance to connect.
To put a pretty bow on the script, I added regions so that readers could easily understand the logical stages of the script, and then added a Help file for reference in Windows PowerShell. Here is the entire script:
Switch-NetworkConnection.ps1
<#
.Synopsis
Toggles the enabled network connection between a wired and a wireless network adapter.
.Description
The Switch-NetworkConnection.ps1 script toggles the enabled network connection between a wired and a wireless network adapter.
This script can only be used on mobility platforms with PowerShell 3.0 installed and must be run as Administrator. Furthermore, only one wired and one wireless network adapter can be selected to take part in the toggling process. You can either select the desired network adapters from a dispalyed list, or specify which adapters will take part using the available parameters.
.Parameter WiredNetworkAdapter
This parameter specifies the wired network connection that will be used in the toggling process.
This accepted value for this parameter is either the name of the network adapter or a NetAdapter object representing that network adapter.
.Parameter WirelessNetworkAdapter
This parameter specifies the wired network connection that will be used in the toggling process.
This accepted value for this parameter is either the name of the network adapter or a NetAdapter object representing that network adapter.
.Example
.\Switch-NetworkConnection.ps1
This example determines the wired and wireless network adapters that will be toggled. If multiple network adapters of a given type are found, the script will prompt for a choice.
.Example
.\Switch-NetworkConnection.ps1 -WiredNetworkAdapter "Local Area Connection" -WirelessNetworkAdapter "WLAN 2"
In this exmaple, the wired and wireless adapters were specified because multiple network adapters of each type are present and the user wanted to bypass the network adapter selection process.
.Outputs
Microsoft.Management.Infrastructure.CimInstance[]
.Notes
Name: Switch-NetworkConnection.ps1
Author: Jeremy Engel
CreatedDate: 03.26.2012
ModifiedDate: 03.29.2012
Version: 1.0.0
#>
#Requires -version 3.0
Param([Parameter(Mandatory=$false,Position=0)][Alias("Wired","LAN")][PSObject]$WiredNetworkAdapter,
[Parameter(Mandatory=$false,Position=1)][Alias("Wireless","WLAN")][PSObject]$WirelessNetworkAdapter
)
function Get-AdapterSelection {
Param([Parameter(Mandatory=$true)][string]$Text,
[Parameter(Mandatory=$true)][Microsoft.Management.Infrastructure.CimInstance[]]$Adapters
)
Write-Host $Text
for($i=0;$i-lt$Adapters.Count;$i++) { Write-Host " $($i+1). $($Adapters[$i].Name)" }
$n = [int](Read-Host "Selection")
if($n -lt 1 -or $n -gt $Adapters.Count+1) {
Write-Host "Invalid selection." -ForegroundColor Red
return (Get-AdapterSelection -Type $Type -Adapters $Adapters)
}
else { return $Adapters[$n-1] }
}
function Main {
#region System Requirements and Runspace Validation
if(!(Get-WmiObject -Class Win32_Battery)) {
Write-Host "ERROR: This script is designed for use on laptops and tablets only." -ForegroundColor Red
return
}
if(([Security.Principal.WindowsIdentity]::GetCurrent()).Owner -ne "S-1-5-32-544") {
Write-Host "ERROR: This script may only be run as Administrator. Please open a PowerShell window as Administrator and try again." -ForegroundColor Red
return
}
#endregion
#region Adapter Validation and Selection
$adapters = Get-NetAdapter -ErrorAction Stop
$wired = $adapters | Where-Object { $_.PhysicalMediaType -match "802.3" }
$wireless = $adapters | Where-Object { $_.PhysicalMediaType -match "802.11" }
if(!$adapters -or !$wireless -or !$wired) {
$type = if(!$adapters){"any"}elseif(!$wireless){"any wireless"}else{"any wired"}
Write-Host "ERROR: You do not have $type network adapters." -ForegroundColor Red
return
}
if($WiredNetworkAdapter) {
$wired = if($WiredNetworkAdapter -is [string]) { $wired | Where-Object { $_.Name -eq $WiredNetworkAdapter } }
elseif($WiredNetworkAdapter -is [Microsoft.Management.Infrastructure.CimInstance]) { $WiredNetworkAdapter }
else { $null }
if(!$wired) {
Write-Host "ERROR: Could not locate a wired network adapter by the name of $WiredNetworkAdapter." -ForegroundColor Red
return
}
}
if($WirelessNetworkAdapter) {
$wireless = if($WirelessNetworkAdapter -is [string]) { $wireless | Where-Object { $_.Name -eq $WirelessNetworkAdapter } }
elseif($WirelessNetworkAdapter -is [Microsoft.Management.Infrastructure.CimInstance]) { $WirelessNetworkAdapter }
else { $null }
if(!$wireless) {
Write-Host "ERROR: Could not locate a wireless network adapter by the name of $WirelessNetworkAdapter." -ForegroundColor Red
return
}
}
if($wired.Count -gt 1) {
$text = "$($wired.Count) wired network adapters were found on your system. Please select the desired network adapter by number."
$wired = Get-AdapterSelection -Text $text -Adapters $wired
}
if($wireless.Count -gt 1) {
$text = "$($wireless.Count) wireless network adapters were found on your system. Please select the desired network adapter by number."
$wireless = Get-AdapterSelection -Text $text -Adapters $wireless
}
#endregion
#region Action Determination
if($wired.AdminStatus -eq "Down" -and $wireless.AdminStatus -eq "Down") {
$text = "Both network adapters are disabled. Choose the number of the network adapter you wish to enable."
$enableMe = Get-AdapterSelection -Text $text -Adapters $wired,$wireless
$disableMe = $wired,$wireless | Where-Object { $_.Name -ne $enableMe.Name }
}
elseif($wired.AdminStatus -eq "Up" -and $wireless.AdminStatus -eq "Up") {
$text = "Both network adapters are enabled. Choose the number of the network adapter you wish to disable."
$disableMe = Get-AdapterSelection -Text $text -Adapters $wired,$wireless
$enableMe = $wired,$wireless | Where-Object { $_.Name -ne $disableMe.Name }
}
else {
$enableMe = $wired,$wireless | Where-Object { $_.AdminStatus -eq "Down" }
$disableMe = $wired,$wireless | Where-Object { $_.AdminStatus -eq "Up" }
}
#endregion
#region Action Execution
$enableMe | Enable-NetAdapter -ErrorAction Stop
$disableMe | Disable-NetAdapter -Confirm:$false -ErrorAction Stop
Start-Sleep -Seconds 2 # Pause while the enabled adapter establishes a connection
#endregion
#region Output
$adapters = Get-NetAdapter
$check = $adapters | Where-Object { $_.Name -eq $enableMe.Name }
if($check.MediaConnectionState -eq "Disconnected") {
Write-Host "WARNING: The enabled network adapter [$($check.Name)] is in a disconnected state." -ForegroundColor Yellow
}
$adapters
#endregion
}
Main
~Jeremy
2012 Scripting Games Guest Commentator Week Part 2 will continue tomorrow when we will present the scenario for Event 9.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy