3LWakeOnLan.psm1
# Name : 3LWakeOnLan.psm1 # Author : Frits van Drie (3-Link.nl) # Date : 2021-10-20 Function Invoke-WakeUpComputer { <# .SYNOPSIS Send a Wake-On-LAN magic packet .DESCRIPTION Send a Wake-On-LAN magic packet to all passed MAC-addresses UDP-port defaults to 7 IPv4-address defaults to 255.255.255.255 The following separators in the MAC-address are accepted: - (dash), : (colon), . (dot) .EXAMPLE Start-Computer -macAddress '6805CAAF534A', 'B4-2E-99:A6.55.2D' Start-Computer -macAddress 'C8-60-00-BF-B8-7E', '00-15-5D-00-02-A8' Broadcasts a magic packet to multiple mac-addresses through UDP-port 7 Separator characters are removed .EXAMPLE Start-Computer -macAddress '6805CAAF534A' -Port 9 -Verbose Broadcasts a magic packet through UDP-port 9 .NOTES Author : Frits van Drie (3-Link.nl) Versions : 2021.09.18 IPv4-address is now optional and defaults to the all-subnet broadcast address Added support for multiple MAC-addresses Added support for MAC-address through pipeline #> [CmdletBinding()] Param ( [parameter(mandatory=$true, ValueFromPipeline=$true)] [string[]]$macAddress, [ipaddress]$ipv4Address = '255.255.255.255', [int]$port = 7 ) Begin{ Write-Verbose "Start Function: $($MyInvocation.MyCommand)" } Process { foreach ($mac in $macAddress) { # Convert mac-address Write-Verbose "Check MAC-address: $mac" if ( -not (IsValidMacAddress $mac) ) { Write-Error "$mac is not a valid MAC-address" return } Write-Verbose "$mac is a valid MAC-address" Write-Verbose "Convert MAC-address: $mac" $mac = $mac.replace('-','').Replace(':','').Replace('.','') $target = 0,2,4,6,8,10 | Foreach { [convert]::ToByte($mac.substring($_,2),16) } Write-Verbose "Create magic packet" $packet = (,[byte]255 *6) + ($target * 16) $udpClient = New-Object System.Net.Sockets.UdpClient Write-Verbose "Send magic packet (MAC: $mac, IPv4: $ipv4Address, Port: UDP-$port)" Write-Verbose "`t`tMAC : $mac" Write-Verbose "`t`tIPv4: $ipv4Address" Write-Verbose "`t`tPort: UDP-$port" $udpClient.Connect($ipv4Address, $port) [void]$udpClient.Send($packet, 102) } } # process End { Write-Verbose "End Function: $($MyInvocation.MyCommand)" } } Function Get-MacAddress{ <# .SYNOPSIS Get a computer network hardware address .DESCRIPTION .NOTE Last modified: 2021-10-20 .AUTHOR Frits van Drie (3-Link.nl) #> Param ( [parameter(mandatory=$true)] [string[]]$computerName ) foreach ($computer in $computerName) { try { $networkadapterconfiguration = Get-CimInstance win32_networkadapterconfiguration -ComputerName $computer | select description, macaddress -ea Stop } catch { Write-Error $Error[0] } Write-Output $networkadapterconfiguration } } Function IsValidMacAddress { <# .SYNOPSIS Checks the validity of a given mac-address .DESCRIPTION Checks the validity of a given mac-address. Valid separators are: dash (-), colon (:) and dot (.) .INPUT String .OUTPUT Boolean .NOTE Last modified: 2021-09-21 .AUTHOR Frits van Drie (3-Link.nl) #> [CmdletBinding()] param ( [parameter(mandatory=$true, position=0)] [string]$macAddress ) if ( $macAddress -match "([a-fA-F0-9]{2,2}[:\-\.]{0,1}){5}([a-fA-F0-9]{2,2}){1}$" ) { return $true } else { return $false } } Function Add-ComputerMacAddressToRegistry{ <# .SYNOPSIS Save a computer network hardware address in the local registry .DESCRIPTION .NOTE Last modified: 2021-09-20 .AUTHOR Frits van Drie (3-Link.nl) #> [CmdletBinding()] param ( [parameter(mandatory=$true)] [string]$computerName, [parameter(mandatory=$true)] [string]$macAddress ) Begin { Write-Verbose "Start Function: $($MyInvocation.MyCommand)" try { $regKey = "HKCU:\Software\3-Link\PSWakeOnLan" Write-Verbose "Check registry-key: $regKey" if ( -not (Test-Path $regKey -ea SilentlyContinue) ) { Write-Verbose "Create new registry-key: $regKey" $null = New-Item $regKey -Force -ea Stop Write-Verbose "Success" } } catch { Write-Verbose "Error creating registry-key: $regKey" Write-Error $Error[0] Return } } Process{ # Convert mac-address Write-Verbose "Check MAC-address: $mac" if ( -not (IsValidMacAddress $mac) ) { Write-Error "$mac is not a valid MAC-address" return } Write-Verbose "$mac is a valid MAC-address" try { Write-Verbose "Add property $computerName to $regKey" $null = New-ItemProperty -Name $computerName -Path $regKey -Value $mac -ea Stop Write-Verbose "Success" } catch [System.IO.IOException]{ try { Write-Verbose "Add $mac to property $regkey\$computerName" $value = (Get-ItemProperty -Path $regKey).$computerName $mac = "$value;$mac" $null = Set-ItemProperty -Name $computerName -Path $regKey -Value $mac -ea Stop Write-Verbose "Success" } catch [System.IO.IOException]{ Write-Verbose "Error adding $mac to $regKey\$computerName" Write-Error $Error[0] Return } } } End { Write-Verbose "End Function: $($MyInvocation.MyCommand)" } } Function Get-ComputerMacAddressFromFile { [CmdletBinding()] param( [string]$filePath = 'C:\Users\fvd\AppData\Roaming\3-Link\PowerShell\WakeOnLan.json', [string]$computerName = '*', [string]$macAddress = '*', [string]$ipv4Address = '*', [string]$port = '*' ) # Check filePath if ( -not (Test-Path $filePath) ) { Write-Error "File not found: $filePath" return } try { [array]$arr = Get-Content $filePath | ConvertFrom-Json -ea Stop $result = $arr | Where { ($_.computerName -like $computerName) -and ($_.macAddress -like $macAddress) -and ($_.ipv4Address -like $ipv4Address) -and ($_.port -like $port) } } catch { Write-Error "$filePath is not a valid JSON-file" return } Write-Output $result } Function Add-ComputerMacAddressToFile { [CmdletBinding()] param( [string]$filePath = 'C:\Users\fvd\AppData\Roaming\3-Link\PowerShell\WakeOnLan.json', [parameter(mandatory=$true)] [string]$computerName, [parameter(mandatory=$true)] [string]$macAddress, [parameter(mandatory=$false)] [string]$ipv4Address = '255.255.255.255', [parameter(mandatory=$false)] [string]$port = 7 ) Begin { Write-Verbose "Start Function ($($MyInvocation.MyCommand))" # Check filePath if ( -not (Test-Path $filePath) ) { try { Write-Verbose "Create new file: $filePath" New-Item $filePath -ItemType File -ErrorAction Stop Write-Verbose "Success" } catch { Write-Verbose "Error creating new file: $filePath" Write-Error $Error[0] break } } try { Write-Verbose "Reading content from file: $filePath" $content = Get-Content $filePath -ErrorAction Stop } catch { Write-Error "Error reading $filePath" break } try { Write-Verbose "Convert content from file to JSON" [array]$arr = $content | ConvertFrom-Json -ErrorAction Stop } catch { Write-Error "$filePath is not a valid JSON-file" break } } Process { # Check mac-address Write-Verbose "Check MAC-address: $macAddress" if ( -not (IsValidMacAddress $macAddress) ) { Write-Error "$macAddress is not a valid MAC-address" return } Write-Verbose "$macAddress is a valid MAC-address" # Check ipv4-Address Write-Verbose "Check IPv4-address: $ipv4Address" <# if ( -not (IsValidIPv4Address $ipv4Address) ) { Write-Error "$ipv4Address is not a valid IPv4-address" return } #> Write-Verbose "$ipv4Address is a valid IPv4-address" $newEntry = New-Object PSObject Add-Member -InputObject $newEntry -MemberType NoteProperty -Name 'computerName' -Value $computerName Add-Member -InputObject $newEntry -MemberType NoteProperty -Name 'macAddress' -Value $macAddress Add-Member -InputObject $newEntry -MemberType NoteProperty -Name 'ipv4Address' -Value $ipv4Address Add-Member -InputObject $newEntry -MemberType NoteProperty -Name 'port' -Value $port # Check for duplicates Write-Verbose "Check for duplicates" $duplicateFound = $arr | Where { "$_" -eq $newEntry } if ( $duplicateFound ) { Write-Warning "Entry for $computerName already exists" Write-Verbose $duplicateFound return } # Add entry to File $arr += $newEntry try { Write-Verbose "Convert content to JSON" $json = $arr | ConvertTo-Json -ea Stop } catch { Write-Verbose "Error converting content to JSON" Write-Error $Error[0] Return } try { Write-Verbose "Write new JSON-content to file: $filePath" $json | Set-Content $filePath -ea Stop } catch { Write-Verbose "Error writing content to file: $filePath" Write-Error $Error[0] Return } } End { Write-Verbose "End Function ($($MyInvocation.MyCommand))" } } Function Remove-ComputerMacAddressFromFile { [CmdletBinding()] param( [string]$filePath = 'C:\Users\fvd\AppData\Roaming\3-Link\PowerShell\WakeOnLan.json', [parameter(mandatory=$true)] [string]$computerName, [parameter(mandatory=$false)] [string]$macAddress = '*', [parameter(mandatory=$false)] [string]$ipv4Address = '*', [parameter(mandatory=$false)] [string]$port = '*' ) Begin { Write-Verbose "Start Function ($($MyInvocation.MyCommand))" # Check filePath if ( -not (Test-Path $filePath) ) { Write-Verbose "File not found: $filePath" Write-Error $Error[0] break } # Read file try { Write-Verbose "Reading content from file: $filePath" $content = Get-Content $filePath -ErrorAction Stop } catch { Write-Error "Error reading $filePath" break } # Convert content from JSON try { Write-Verbose "Convert content from file to JSON" [array]$arr = $content | ConvertFrom-Json -ErrorAction Stop } catch { Write-Error "$filePath is not a valid JSON-file" break } } Process { <# # Check mac-address Write-Verbose "Check MAC-address: $macAddress" if ( -not (IsValidMacAddress $macAddress) ) { Write-Error "$macAddress is not a valid MAC-address" break } Write-Verbose "$macAddress is a valid MAC-address" # Check ipv4-Address Write-Verbose "Check IPv4-address: $ipv4Address" <# if ( -not (IsValidIPv4Address $ipv4Address) ) { Write-Error "$ipv4Address is not a valid IPv4-address" return } #> # Write-Verbose "$ipv4Address is a valid IPv4-address" #> # Define object to remove $entry = New-Object PSObject Add-Member -InputObject $entry -MemberType NoteProperty -Name 'computerName' -Value $computerName Add-Member -InputObject $entry -MemberType NoteProperty -Name 'macAddress' -Value $macAddress Add-Member -InputObject $entry -MemberType NoteProperty -Name 'ipv4Address' -Value $ipv4Address Add-Member -InputObject $entry -MemberType NoteProperty -Name 'port' -Value $port # Find object Write-Verbose "Find entry" $entryFound = $arr | Where { ($_.computerName -like $computerName) -and ($_.macAddress -like $macAddress) -and ($_.ipv4Address -like $ipv4Address) -and ($_.port -like $port) } #"$_" -eq $entry } if ( -not $entryFound ) { Write-Verbose "Entry not found" return } Write-Verbose "Entry found" # Remove entry from array foreach ($item in $entryFound) { $arr = $arr | Where { "$_" -ne $item } } try { Write-Verbose "Convert content to JSON" $json = $arr | ConvertTo-Json -ea Stop } catch { Write-Verbose "Error converting content to JSON" Write-Error $Error[0] Return } try { Write-Verbose "Write new JSON-content to file: $filePath" if ( $json -eq $null ) { $json = "" } $json | Set-Content $filePath -ea Stop } catch { Write-Verbose "Error writing content to file: $filePath" Write-Error $Error[0] Return } } End { Write-Verbose "End Function ($($MyInvocation.MyCommand))" } } Function Start-Computer { [CmdletBinding()] param( [parameter(mandatory=$true, position = 0)] [string]$computerName ) Get-ComputerMacAddressFromFile -computerName $computerName | foreach { Invoke-WakeUpComputer -macAddress $_.macAddress -ipv4Address $_.ipv4Address -port $_.port } } |