LoopbackAdapter.psm1
#Region './prefix.ps1' 0 <# .EXTERNALHELP LoopbackAdapter-help.xml #> $moduleRoot = Split-Path ` -Path $MyInvocation.MyCommand.Path ` -Parent #region LocalizedData $culture = 'en-US' if (Test-Path -Path (Join-Path -Path $moduleRoot -ChildPath $PSUICulture)) { $culture = $PSUICulture } Import-LocalizedData ` -BindingVariable LocalizedData ` -Filename 'LoopbackAdapter.strings.psd1' ` -BaseDirectory $moduleRoot ` -UICulture $culture #endregion #EndRegion './prefix.ps1' 23 #Region './Private/Install-Chocolatey.ps1' 0 <# .SYNOPSIS Install Chocolatey. .DESCRIPTION Installs Chocolatey from the internet if it is not installed. .PARAMETER Force Force the install of Chocolatey, without confirming with the user. .EXAMPLE Install-Chocolatey .OUTPUTS None #> function Install-Chocolatey { [CmdLetBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High')] param ( [Parameter()] [Switch] $Force ) # Check chocolatey is installed - if not, install it $chocolateyInstalled = Test-Path -Path (Join-Path -Path $ENV:ProgramData -ChildPath 'Chocolatey\Choco.exe') if (-not $chocolateyInstalled) { if ($Force -or $PSCmdlet.ShouldProcess($LocalizedData.DownloadAndInstallChocolateyShould)) { Write-Verbose -Message $LocalizedData.InstallingChocolateyMessage try { $chocolateyInstallScript = (Invoke-WebRequest -UseBasicParsing -Uri 'https://chocolatey.org/install.ps1').Content $chocolateyInstallScript = [scriptblock]::Create($chocolateyInstallScript) $null = $chocolateyInstallScript.Invoke() } catch { throw ($LocalizedData.ChocolateyInstallationError -f $_) } } else { throw $LocalizedData.NetworkAdapterExistsWrongTypeError } } else { Write-Verbose -Message $LocalizedData.ChocolateyInstalledMessage } } #EndRegion './Private/Install-Chocolatey.ps1' 58 #Region './Private/Install-Devcon.ps1' 0 <# .SYNOPSIS Install the DevCon.Portable (Windows Device Console) package using Chocolatey. .DESCRIPTION Installs Chocolatey from the internet if it is not installed, then uses it to download the DevCon.Portable (Windows Device Console) package. The devcon.portable Chocolatey package can be found here and installed manually if no internet connection is available: https://chocolatey.org/packages/devcon.portable/ Chocolatey will remain installed after this function is called. .PARAMETER Force Force the install of Chocolatey and the Devcon.portable package if not already installed, without confirming with the user. .EXAMPLE Install-Devcon .OUTPUTS The fileinfo object containing the appropriate DevCon*.exe application that was installed for this architecture. #> function Install-Devcon { [OutputType([System.IO.FileInfo])] [CmdLetBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High')] param ( [Parameter()] [Switch] $Force ) Install-Chocolatey @PSBoundParameters # Check DevCon installed - if not, install it. $devConInstalled = ((Test-Path -Path "$ENV:ProgramData\Chocolatey\Lib\devcon.portable\Devcon32.exe") ` -and (Test-Path -Path "$ENV:ProgramData\Chocolatey\Lib\devcon.portable\Devcon64.exe")) if (-not $devConInstalled) { try { <# This will download and install DevCon.exe It will also be automatically placed into the path #> if ($Force -or $PSCmdlet.ShouldProcess($LocalizedData.DownloadAndInstallDevConShould)) { Write-Verbose -Message $LocalizedData.InstallDevconMessage $null = & choco @('install','-r','-y','devcon.portable') } else { throw $LocalizedData.DevConNotInstalledError } } catch { throw ($LocalizedData.DevConInstallationError -f $_) } } if ([Environment]::Is64BitOperatingSystem -eq $True) { Get-ChildItem -Path "$ENV:ProgramData\Chocolatey\Lib\devcon.portable\Devcon64.exe" } else { Get-ChildItem -Path "$ENV:ProgramData\Chocolatey\Lib\devcon.portable\Devcon32.exe" } } #EndRegion './Private/Install-Devcon.ps1' 77 #Region './Private/Uninstall-Devcon.ps1' 0 <# .SYNOPSIS Install the DevCon.Portable (Windows Device Console) package using Chocolatey. .DESCRIPTION Installs Chocolatey from the internet if it is not installed, then uses it to uninstall the DevCon.Portable (Windows Device Console) package. Chocolatey will remain installed after this function is called. .PARAMETER Force Force the uninstall of the devcon.portable package if it is installed, without confirming with the user. .EXAMPLE Uninstall-Devcon .OUTPUTS None. #> function Uninstall-Devcon { [CmdLetBinding( SupportsShouldProcess = $true, ConfirmImpact = 'High')] param ( [Parameter()] [Switch] $Force ) Install-Chocolatey @PSBoundParameters try { <# This will download and install DevCon.exe It will also be automatically placed into the path #> if ($Force -or $PSCmdlet.ShouldProcess($LocalizedData.UninstallDevConShould)) { $null = & choco @('uninstall','-r','-y','devcon.portable') } else { throw $LocalizedData.DevConNotUninstalledError } } catch { throw ($LocalizedData.DevConNotUninstallationError -f $_) } } #EndRegion './Private/Uninstall-Devcon.ps1' 54 #Region './Private/Wait-ForDevconUpdate.ps1' 0 <# .SYNOPSIS Waits for changes made by DevCon.exe to complete before continuing. .DESCRIPTION Waits for the DevCon.exe process to exit and then checks whether Get-NetAdapter completes successfully. Get-NetAdapter will throw "Illegal operation attempted on a registry key that has been marked for deletion." if the changes are still processing. .PARAMETER DevconExeTimeout Time in seconds to wait for the DevCon process to complete. .PARAMETER RegistryUpdateTimeout Time in seconds to wait for the registry to finish processing changes. .EXAMPLE Wait-ForDevconUpdate .NOTES N/A #> function Wait-ForDevconUpdate { [CmdletBinding()] param ( [Parameter()] [System.Int32] $DevconExeTimeout = 5, [Parameter()] [System.Int32] $RegistryUpdateTimeout = 5 ) Get-Process -Name 'DevCon' -ErrorAction SilentlyContinue | Wait-Process -Timeout $DevconExeTimeout $registryUpdated = $false $registryTimer = 0 $waitIncrement = 0.5 while ($registryUpdated -eq $false) { try { $null = Get-NetAdapter -ErrorAction Stop *>&1 $registryUpdated = $true } catch [Microsoft.Management.Infrastructure.CimException] { if ($registryTimer -ge $RegistryUpdateTimeout) { throw $_ } Start-Sleep -Seconds $waitIncrement $registryTimer += $waitIncrement } } } #EndRegion './Private/Wait-ForDevconUpdate.ps1' 60 #Region './Public/Get-LoopbackAdapter.ps1' 0 function Get-LoopbackAdapter { [OutputType([Microsoft.Management.Infrastructure.CimInstance[]])] [CmdLetBinding()] param ( [Parameter()] [System.String] $Name ) # Check for the existing Loopback Adapter if ($Name) { $adapter = Get-NetAdapter ` -Name $Name ` -ErrorAction Stop if ($adapter.DriverDescription -ne 'Microsoft KM-TEST Loopback Adapter') { throw ($LocalizedData.NetworkAdapterExistsWrongTypeError -f $Name) } # if return $adapter } else { Get-NetAdapter | Where-Object -Property DriverDescription -eq 'Microsoft KM-TEST Loopback Adapter' } # if } #EndRegion './Public/Get-LoopbackAdapter.ps1' 31 #Region './Public/New-LoopbackAdapter.ps1' 0 function New-LoopbackAdapter { [OutputType([Microsoft.Management.Infrastructure.CimInstance])] [CmdLetBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $Name, [Parameter()] [switch] $Force ) $null = $PSBoundParameters.Remove('Name') # Check for the existing Loopback Adapter $adapter = Get-NetAdapter ` -Name $Name ` -ErrorAction SilentlyContinue # Is the loopback adapter installed? if ($adapter) { throw ($localizedData.NetworkAdapterExistsError -f $Name) } # if # Make sure DevCon is installed. $devConExe = (Install-Devcon @PSBoundParameters).FullName <# Get a list of existing Loopback adapters This will be used to figure out which adapter was just added #> $existingAdapters = (Get-LoopbackAdapter).PnPDeviceID <# Use Devcon.exe to install the Microsoft Loopback adapter Requires local Admin privs. #> Write-Verbose -Message ($LocalizedData.CreatingLoopbackAdapterMessage -f $Name) $null = & $DevConExe @('install', "$($ENV:SystemRoot)\inf\netloop.inf", '*MSLOOP') Wait-ForDevconUpdate # Find the newly added Loopback Adapter $adapters = Get-NetAdapter $adapter = $adapters | Where-Object -FilterScript { ($_.PnPDeviceID -notin $ExistingAdapters ) -and ` ($_.DriverDescription -eq 'Microsoft KM-TEST Loopback Adapter') } if (-not $adapter) { throw ($LocalizedData.NewNetworkAdapterNotFoundError -f $Name) } # if # Rename the new Loopback adapter Write-Verbose -Message ($LocalizedData.SettingNameOfNewLoopbackAdapterMessage -f $Name) $null = Rename-NetAdapter ` -Name $adapter.Name ` -NewName $Name ` -ErrorAction Stop # Set the metric to 254 Write-Verbose -Message ($LocalizedData.SettingMetricOfNewLoopbackAdapterMessage -f $Name) $null = Set-NetIPInterface ` -InterfaceAlias $Name ` -InterfaceMetric 254 ` -ErrorAction Stop <# Wait till IP address binding has registered in the CIM subsystem. if after 30 seconds it has not been registered then throw an exception. #> [System.Boolean] $adapterBindingReady = $false [System.DateTime] $startTime = Get-Date while (-not $adapterBindingReady ` -and (((Get-Date) - $startTime).TotalSeconds) -lt 30) { try { $ipAddress = Get-CimInstance ` -ClassName MSFT_NetIPAddress ` -Namespace ROOT/StandardCimv2 ` -Filter "((InterfaceAlias = '$Name') AND (AddressFamily = 2))" ` -ErrorAction Stop if ($ipAddress) { $adapterBindingReady = $true } # if Write-Verbose -Message ($LocalizedData.WaitingForIPAddressMessage -f $Name) Start-Sleep -Seconds 1 } catch { Write-Warning -Message ($LocalizedData.GetIPAddressWarning -f $_) } } # while if (-not $ipAddress) { throw $LocalizedData.NewNetworkAdapterNotFoundInCIMError } # Pull the newly named adapter (to be safe) $adapter = Get-NetAdapter ` -Name $Name ` -ErrorAction Stop return $adapter } #EndRegion './Public/New-LoopbackAdapter.ps1' 118 #Region './Public/Remove-LoopbackAdapter.ps1' 0 function Remove-LoopbackAdapter { [CmdLetBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [System.String] $Name, [Parameter()] [switch] $Force ) process { $null = $PSBoundParameters.Remove('Name') # Check for the existing Loopback Adapter $adapter = Get-NetAdapter ` -Name $Name ` -ErrorAction SilentlyContinue # Is the loopback adapter installed? if (-not $adapter) { # Adapter doesn't exist throw ($LocalizedData.LoopbackAdapterNotFound -f $Name) } # Is the adapter Loopback adapter? if ($adapter.DriverDescription -ne 'Microsoft KM-TEST Loopback Adapter') { # Not a loopback adapter - don't uninstall this! throw ($LocalizedData.NetworkAdapterWrongTypeError -f $Name) } # if # Make sure DevCon is installed and return path to executable $devConExe = (Install-Devcon @PSBoundParameters).FullName <# Use Devcon.exe to remove the Microsoft Loopback adapter using the PnPDeviceID. Requires local Admin privs. #> Write-Verbose -Message ($LocalizedData.RemovingLoopbackAdapterMessage -f $Name) $null = & $devConExe @('remove',"@$($adapter.PnPDeviceID)") Wait-ForDevconUpdate } } # function Remove-LoopbackAdapter #EndRegion './Public/Remove-LoopbackAdapter.ps1' 49 #Region './suffix.ps1' 0 #EndRegion './suffix.ps1' 1 |