Skip to content

Instantly share code, notes, and snippets.

@bjarkirafn
Last active November 12, 2020 18:52
Show Gist options
  • Save bjarkirafn/0ca3609155e6fccc789790f6cf0a7a0b to your computer and use it in GitHub Desktop.
Save bjarkirafn/0ca3609155e6fccc789790f6cf0a7a0b to your computer and use it in GitHub Desktop.
posh:snippets
function Convert-AsciiToBinary {
[CmdletBinding()]
[Alias('ascii2bin')]
param ([Parameter(Mandatory)][string]$String)
return [byte[]][char[]]$String |
ForEach-Object { [convert]::ToString($_, 2).PadLeft(8, '0')
}
}
# @https://powershell.one/powershell-internals/attributes/custom-attributes
#requires -Version 5.0
#region Attribute Type
# custom attributes derive from the type "Attribute":
class PesterTestAttribute : Attribute {
# field to store constructor argument:
[string]$TestName = ''
# field becomes an optional named argument later:
[int]$Level = 0
# field becomes an optional named argument later:
[bool]$IsParam = $false
# constructor with one argument,
# this argument becomes a mandatory positional argument later:
PesterTestAttribute([string]$TestName) {
$this.TestName = $TestName
}
# constructor with NO argument,
# turns the positional mandatory argument into a positional optional argument later:
PesterTestAttribute() {}
}
function Test-This {
param
(
[PesterTest('Variable', Level = 6, IsParam)]
[string]
$Name
)
$result = $PSBoundParameters
Write-Output $result
}
function Test-Attribute {
[PesterTest('ReturnValue')]
[PesterTest('Log', Level = 1)]
param
(
[PesterTest('Name', IsParam)]
[string]
$Name
)
[PesterTest()]$init = 100
}
$scriptblock = {
[PesterTest('ReturnValue')]
[PesterTest('Log')]
param()
'Hello!'
}
$scriptblock.Attributes
#endregion Attribute Type
#region Variable Attributes
# apply attribute to variable:
[PesterTest(Level = 5)]$test = 12
# read attribute:
(Get-Variable -Name test).Attributes
#endregion Variable attributes
#region Tag attributes
# define very simple attribute:
class DocumentAttribute : Attribute {}
# use attribute to tag important variables that you want to
# include into your documentation:
[Document()]$important = 12
$notimportant = "I am hidden"
[Document()]$addThis = "I am not!"
# dump only tagged variables:
Get-Variable |
Where-Object { $_.Attributes.Where{ $_.TypeId.Name -eq 'DocumentAttribute' } }
#endregion Tag attributes
#region IArgument Completers
class CustomerAttribute : System.Management.Automation.ArgumentCompleterAttribute {
# constructor calls base constructor and submits the completion code:
CustomerAttribute() : base( {
# receive information about current state:
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
# list all customers...
'Microsoft', 'Amazon', 'Google' |
Sort-Object -Property LogName |
# filter results by word to complete
Where-Object { $_.LogName -like "$wordToComplete*" } |
Foreach-Object {
[Management.Automation.CompletionResult]::new($_, $_, "ParameterValue", $_)
}
}) {
# constructor has no own code
}
}
function Get-CustomerInfo {
param
(
# suggest customer names:
[Customer()]
[string]
$Customer
)
"Hello $Customer!"
}
#endregion IArgument Completers
#region ArgumentCompleter Factory
# define the attribute:
class CompleteAttribute : System.Management.Automation.ArgumentCompleterAttribute {
# add an optional parameter
[string]$Icon = 'ParameterValue'
# constructor calls base constructor and submits the completion code:
# added a mandatory positional argument $Values with the autocompletion values
# this argument is passed to a static method that creates the scriptblock that the base constructor wants
# also pass reference to object instance ($this) to be able to access optional parameters like $Icon later:
CompleteAttribute([string[]] $Items) : base([CompleteAttribute]::_createScriptBlock($Items, $this)) {
# constructor has no own code
}
# create a static helper method that creates the scriptblock that the base constructor needs
# this is necessary to be able to access the argument(s) submitted to the constructor
# the method needs a reference to the object instance to (later) access its optional parameters:
hidden static [ScriptBlock] _createScriptBlock([string[]] $Items, [CompleteAttribute] $instance) {
$scriptblock = {
# receive information about current state:
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
# list all submitted values...
$Items |
Sort-Object -Property LogName |
# filter results by word to complete
Where-Object { $_.LogName -like "$wordToComplete*" } |
Foreach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_, $instance.Icon, $_)
}
}.GetNewClosure()
return $scriptblock
}
}
# example:
function Get-CustomerInfoNew {
param
(
# suggest customer names:
[Complete(('Karl', 'Jenny', 'Zumsel'), Icon = 'History')]
[string]
$Customer
)
"Hello $Customer!"
}
#endregion ArgumentCompleter Factory
#region Self learning validation attribute
class AutoLearnAttribute : System.Management.Automation.ValidateArgumentsAttribute {
# define path to store hint lists
[string]$Path = "$env:temp\hints"
# define id to manage multiple hint lists:
[string]$Id = 'default'
# define parameterless constructor:
AutoLearnAttribute() : base() {}
# define constructor with parameter for id:
AutoLearnAttribute([string]$Id) : base() {
$this.Id = $Id
}
# Validate() is called whenever there is a variable or parameter assignment
[void]Validate([object]$value, [Management.Automation.EngineIntrinsics]$engineIntrinsics) {
# make sure the folder with hints exists
$exists = Test-Path -Path $this.Path
if (!$exists) { $null = New-Item -Path $this.Path -ItemType Directory }
# create filename for hint list
$filename = '{0}.hint' -f $this.Id
$hintPath = Join-Path -Path $this.Path -ChildPath $filename
# use a hashtable to keep hint list
$hints = @{}
# read hint list if it exists
$exists = Test-Path -Path $hintPath
if ($exists) {
Get-Content -Path $hintPath -Encoding Default |
# remove leading and trailing blanks
ForEach-Object { $_.Trim() } |
# remove empty lines
Where-Object { ![string]::IsNullOrEmpty($_) } |
# add to hashtable
ForEach-Object {
# value is not used, set it to $true:
$hints[$_] = $true
}
}
# add new value to hint list
if (![string]::IsNullOrWhiteSpace($value)) {
$hints[$value] = $true
}
# save hints list
$hints.Keys |
Sort-Object |
Set-Content -Path $hintPath -Encoding Default
# skip any validation (we only care about logging)
}
}
# apply new attribute to a variable:
[AutoLearn()]$test = "Hello"
# variable is now self-learning and logs all assignments:
$test = 123
$test = "check this out"
# read logged values:
Get-Content -Path $env:temp\hints\default.hint
function Connect-MyServer {
param
(
[string]
[Parameter(Mandatory)]
# auto-learn computer names to servers.hint
[AutoLearn('servers')]
$ComputerName
)
"connecting you to $ComputerName"
}
Get-Content -Path $env:temp\hints\servers.hint
function Connect-MyServerNew {
param
(
[string]
[Parameter(Mandatory)]
# auto-learn computer names to servers.hint
# in folder c:\myhints:
[AutoLearn('servers', Path = 'c:\tmp\myhints')]
$ComputerName
)
"connecting you to $ComputerName"
}
Get-Content -Path c:\tmp\myhints\servers.hint
#endregion Self learning validation attribute
#Profile addition to redefine cd as a proxy for push location (and cd- for Pop).
# cd ... is transformed into into cd ..\.. (extra dot is an extra level),
# cd ^ is transformed into cd <<script i.e. profile>> directory
# cd \*doc is transformed into cd \*\Doc*\
# cd = is transformed into an item from the stack. = is the first each extra = goes one deeper in the stack
# cd - will not tab expand but will pop an item from the location stack. 3 or more - will do an extra pop.
# -- means "all the rest are a strings", so two levels needs -- --
# cd\ & cd.. (without space) do push instead of set and cd~ (no space) has been added
# cd HK[tab] will expand to HKCU: and HKLM: and similarly for other drives.
Remove-Item -Path Alias:\cd -ErrorAction SilentlyContinue
class PathTransformAttribute : Management.Automation.ArgumentTransformationAttribute {
[object] Transform([Management.Automation.EngineIntrinsics]$EngineIntrinsics, [object] $InputData) {
switch -regex ($InputData) {
"^=+" { return ($inputData -replace "^=+", (Get-Location -Stack).ToArray()[$Matches[0].Length - 1].Path); break }
"^\^" { return ($inputData -replace "^\^", $PSScriptRoot) ; break }
"^\\\*|/\*" { return ($pwd.path -replace "^(.*$($InputData.substring(2)).*?)[/\\].*$", '$1') ; break }
"^\.{3}" { return ($InputData -replace "(?<=^\.[.\\]*)(?=\.{2,}(\\|$))", ".\") ; break }
}
return ($InputData)
}
}
class ValidatePathAttribute : Management.Automation.ValidateArgumentsAttribute {
[string]$Exemption = "" #"^-+$"
[switch]$ContainersOnly
[int]$MaxItems = -1
[void] Validate([object] $arguments , [Management.Automation.EngineIntrinsics]$EngineIntrinsics) {
if ($this.Exemption -and $arguments -match $this.Exemption) { return } #Exempt some things eg "-"" or "----""
elseif ($arguments -match "^(\w+):\\?" -and (Get-PSDrive $Matches[1] -ErrorAction SilentlyContinue) ) { return } #Allow drives
else {
if ($this.ContainersOnly) { $count = (Get-Item -Path $arguments -ErrorAction SilentlyContinue).where( { $_.psIscontainer }).count }
else { $count = (Get-Item -Path $arguments -ErrorAction SilentlyContinue).count }
if ($count -eq 0 -and $this.maxitems -ge 0) {
throw [Management.Automation.ValidationMetadataException]::new("'$arguments' does not exist.")
}
elseif ($this.Maxitems -ge 0 -and $count -gt $this.maxitems) {
throw [Management.Automation.ValidationMetadataException]::new("'$arguments' resolved to multiple $count items. Maximum allowed is $($this.Maxitems)")
}
}
return
}
}
class PathCompleter : Management.Automation.IArgumentCompleter {
[Collections.Generic.IEnumerable[Management.Automation.CompletionResult]] CompleteArgument(
[string]$CommandName,
[string]$ParameterName,
[string]$WordToComplete,
[Management.Automation.Language.CommandAst]$CommandAst,
[Collections.IDictionary] $FakeBoundParameters
) {
$results = [Collections.Generic.List[Management.Automation.CompletionResult]]::new()
$dots = [regex]"^\.\.(\.*)(\\|$|/)" #find two dots, any more dots (captured), followed by / \ or end of string
$sep = [io.path]::DirectorySeparatorChar
$wtc = ""
switch -regex ($wordToComplete) {
#.. alone doesn't expand, expand .. followed by n dots (and possibly \ or /) to ..\ n+1 times
$dots {
$newPath = "..$Sep" * (1 + $dots.Matches($wordToComplete)[0].Groups[1].Length)
$wtc = $dots.Replace($wordtocomplete, $newPath) ; break
}
"^\^$" { $wtc = $PSScriptRoot ; break } # ^ [tab] ==> PS profile dir
"^\.$" { $wtc = "" ; break } # . and ~ alone don't expand.
"^~$" { $wtc = $env:USERPROFILE ; break }
#for 1 = sign tab through the location stack.
"^=$" {
foreach ($stackPath in (Get-Location -Stack).ToArray().Path) {
if ($stackpath -match "[ ']") { $stackpath = '"' + $stackPath + '"' }
$results.Add([Management.Automation.CompletionResult]::new($stackPath))
}
return $results ; continue
}
#replace string of = signs with the item that many up the location stack
"^=+$" { $wtc = (Get-Location -Stack).ToArray()[$wordToComplete.Length - 1].Path ; continue }
#if path is c:\here\there\everywhere\stuff convert "\*the" to "c:\here\there"
"^\\\*|/\*" { $wtc = $pwd.path -replace "^(.*$($WordToComplete.substring(2)).*?)[/\\].*$", '$1' ; continue }
default { $wtc = $wordToComplete }
}
foreach ($result in [Management.Automation.CompletionCompleters]::CompleteFilename($wtc) ) {
if ($result.resultType -eq "ProviderContainer" -or $CommandName -notin @("cd", "dir")) { $results.Add($result) }
}
foreach ($result in $Global:ExecutionContext.SessionState.Drive.GetAll().name -like "$wordTocomplete*") {
$results.Add([Management.Automation.CompletionResult]::new("$result`:"))
}
return $results
}
}
function cd {
<#
.ForwardHelpTargetName Microsoft.PowerShell.Management\Push-Location
.ForwardHelpCategory Cmdlet
#>
[CmdletBinding(DefaultParameterSetName = 'Path')]
param(
[Parameter(ParameterSetName = 'Path', Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[PathTransform()]
[ArgumentCompleter([PathCompleter])]
[ValidatePath(Exemption = "^-+$", ContainersOnly = $true, MaxItems = 1)]
[string]$Path,
[Parameter(ParameterSetName = 'LiteralPath', ValueFromPipelineByPropertyName = $true)]
[Alias('PSPath', 'LP')]
[string]$LiteralPath,
[switch]$PassThru,
[Parameter(ValueFromPipelineByPropertyName = $true)]
[string]$StackName
)
process {
if ($Path -match "^-+$") { foreach ($i in (1..$Path.Length)) { Pop-Location } }
elseif ($Path -or $LiteralPath) { Push-Location @PSBoundParameters }
}
}
Set-Alias -Name "cd-" -Value Pop-Location
Function cd.. { Push-Location -Path .. }
Function cd\ { Push-Location -Path \ }
Function cd~ { Push-Location -Path ~ }
$shell = New-Object -ComObject Shell.Application
foreach ($win in $shell.Windows()) {
$win.application.name
}
# $onenote = New-Object -ComObject OneNote.application
# $explorer = $shell.Windows()
# $folder = $explorer.Document.Folder
# $startDirPath = $folder.Self.Path
# $parent = [IO.Path]::GetDirectoryName($startDirPath)
# $parent
# $explorer.Navigate2($parent)
# $parentDirPath = $folder.ParentFolder.Self.Path
# $startDirPath
# $parentDirPath
$root = 'HKCU:\Software\Microsoft\IdentityCRL'
$UserEmail = (Get-ChildItem $root\UserExtendedProperties).PSChildName
$UserAccountUrl = (Get-ItemProperty -Path $root\InterruptState).AccountSettingsUrl
$UserEmail
$UserAccountUrl
param([string]$Path)
$resolvedPath = [IO.Path]::GetFullPath($Path)
(New-Object -ComObject WScript.Shell).CreateShortcut($resolvedPath).TargetPath
$appsPath = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FolderDescriptions'
Get-ItemProperty "$appsPath\*" |
Select-Object PSChildName, Name |
Sort-Object Name |
out-gridview
$folder = [ref]'dummy'
While ($folder.value) {
$folder.value = (Get-ItemProperty "$appsPath\*" |
Select-Object Name |
Sort-Object Name |
out-gridview -PassThru)
If ($folder.value) {
explorer "Shell:$($folder.value.Name)"
}
}
[Enum]::GetNames([Management.Automation.CompletionResultType]) |
Sort-Object
param(
[Parameter(Mandatory)]
[String]$Name,
[Parameter(Mandatory)]
[String]$Root,
[Parameter(Mandatory)]
[Management.Automation.PSCredential]$Credentials)
$net = new-object -ComObject WScript.Network
$driveName = $Name.EndsWith(":") ? $Name : "$($Name):"
$net.MapNetworkDrive($driveName, $Root.TrimEnd("\"), $false, $Credentials.UserName, $Credentials.Password)
# @ https://www.powershellmagazine.com/2015/04/13/pstip-use-shell-application-to-display-extended-file-attributes/
$com = (New-Object -ComObject Shell.Application).NameSpace('C:\')
$com.Items() | ForEach-Object {
New-Object -TypeName PSCustomObject -Property @{
Name = $com.GetDetailsOf($_,0)
Size = $com.GetDetailsOf($_,1)
ItemType = $com.GetDetailsOf($_,2)
}
}
function Get-ExtensionAttribute {
[CmdletBinding()]
Param (
[Parameter(ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true,
Position=0)]
[string[]]
$FullName
)
DynamicParam
{
$Attributes = New-Object System.Management.Automation.ParameterAttribute
$Attributes.ParameterSetName = "__AllParameterSets"
$Attributes.Mandatory = $false
$AttributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$AttributeCollection.Add($Attributes)
$Values = @($Com=(New-Object -ComObject Shell.Application).NameSpace('C:\');1..400 | ForEach-Object {$com.GetDetailsOf($com.Items,$_)} | Where-Object {$_} | ForEach-Object {$_ -replace '\s'})
$AttributeValues = New-Object System.Management.Automation.ValidateSetAttribute($Values)
$AttributeCollection.Add($AttributeValues)
$DynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("ExtensionAttribute", [string[]], $AttributeCollection)
$ParamDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$ParamDictionary.Add("ExtensionAttribute", $DynParam1)
$ParamDictionary
}
begin {
$ShellObject = New-Object -ComObject Shell.Application
$DefaultName = $ShellObject.NameSpace('C:\')
$ExtList = 0..400 | ForEach-Object {
($DefaultName.GetDetailsOf($DefaultName.Items,$_)).ToUpper().Replace(' ','')
}
}
process {
foreach ($Object in $FullName) {
# Check if there is a fullname attribute, in case pipeline from Get-ChildItem is used
if ($Object.FullName) {
$Object = $Object.FullName
}
# Check if the path is a single file or a folder
if (-not (Test-Path -Path $Object -PathType Container)) {
$CurrentNameSpace = $ShellObject.NameSpace($(Split-Path -Path $Object))
$CurrentNameSpace.Items() | Where-Object {
$_.Path -eq $Object
} | ForEach-Object {
$HashProperties = @{
FullName = $_.Path
}
foreach ($Attribute in $MyInvocation.BoundParameters.ExtensionAttribute) {
$HashProperties.$($Attribute) = $CurrentNameSpace.GetDetailsOf($_,$($ExtList.IndexOf($Attribute.ToUpper())))
}
New-Object -TypeName PSCustomObject -Property $HashProperties
}
} elseif (-not $input) {
$CurrentNameSpace = $ShellObject.NameSpace($Object)
$CurrentNameSpace.Items() | ForEach-Object {
$HashProperties = @{
FullName = $_.Path
}
foreach ($Attribute in $MyInvocation.BoundParameters.ExtensionAttribute) {
$HashProperties.$($Attribute) = $CurrentNameSpace.GetDetailsOf($_,$($ExtList.IndexOf($Attribute.ToUpper())))
}
New-Object -TypeName PSCustomObject -Property $HashProperties
}
}
}
}
end {
Remove-Variable -Force -Name DefaultName
Remove-Variable -Force -Name CurrentNameSpace
Remove-Variable -Force -Name ShellObject
}
}
$signature = @'
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
uint Msg,
UIntPtr wParam,
IntPtr lParam,
SendMessageTimeoutFlags fuFlags,
uint uTimeout,
out UIntPtr lpdwResult);
'@
Add-Type -MemberDefinition $signature -Name SendMessage -Namespace user32 -PassThru
$signature = @'
class Program
{
[System.Runtime.InteropServices.DllImport("Shell32.dll")]
private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SendMessageTimeout(IntPtr hWnd, int Msg, IntPtr wParam, string lParam, uint fuFlags, uint uTimeout, IntPtr lpdwResult);
private static readonly IntPtr HWND_BROADCAST = new IntPtr(0xffff);
private const int WM_SETTINGCHANGE = 0x1a;
private const int SMTO_ABORTIFHUNG = 0x0002;
static void Main(string[] args)
{
SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, IntPtr.Zero, null, SMTO_ABORTIFHUNG, 100, IntPtr.Zero);
}
}
'@
$NS = @{
Taskbar = '4234d49b-0245-4df3-b780-3893943456e1'
QuickAccess = '679F85CB-0220-4080-B29B-5540CC05AAB6'
}
$shell = New-Object -Com Shell.Application
$NameSpace = $shell.NameSpace("shell:::{$($NS.QuickAccess)}")
$items = $NameSpace.Items()
function Get-QuickAccess {
[CmdletBinding()]
[Alias('gqa')]
param(
[ArgumentCompleter( { 'Pinned', 'Unpinned' })]
[String]$Type = 'Pinned'
)
$qa = (New-Object -Com Shell.Application).NameSpace('shell:::{679F85CB-0220-4080-B29B-5540CC05AAB6}')
$match = (($Type -like 'Pinned')? 'UnPin From': 'Pin To') + ' Quick access'
$qa.Items() | Where-Object { ($_.Verbs() | ForEach-Object Name) -match $match }
}
$verbs = $items |
Where-Object {
($_.Verbs() | ForEach-Object Name) -match $match
}
$verbs
$NameSpace.Items() |
ForEach-Object -Parallel {
$verb = $_.Verbs() | ForEach-Object -Parallel { $_.Name }
$verb
# @{Item = $_; Verb = $_.Verbs() }
}
# Where-Object { $_.Verb.Name -match 'Remove from Quick access' } |
# ForEach-Object Item
# Where-Object{$_.Verbs().Name.Replace('&','') -match "Remove from QuickAccess"}
# |
# Where-Object { $_.Verbs().Name.Replace('&','') -like 'Remove from Quick access' }
#requires -Version 5
# this enum works in PowerShell 5 only
# in earlier versions, simply remove the enum,
# and use the numbers for the desired window state
# directly
Enum ShowStates {
Hide = 0
Normal = 1
Minimized = 2
Maximized = 3
ShowNoActivateRecentPosition = 4
Show = 5
MinimizeActivateNext = 6
MinimizeNoActivate = 7
ShowNoActivate = 8
Restore = 9
ShowDefault = 10
ForceMinimize = 11
}
# the C#-style signature of an API function (see also www.pinvoke.net)
$signarture = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);'
# add signature as new type to PowerShell (for this session)
$type = Add-Type -MemberDefinition $signarture -Name win -Namespace user32 -PassThru
# access a process
# (in this example, we are accessing the current PowerShell host
# with its process ID being present in $pid, but you can use
# any process ID instead)
$process = Get-Process | Where-Object { $_.ProcessName -like 'notepad' } | select -First 1
# get the process window handle
$hwnd = $process.MainWindowHandle
# apply a new window size to the handle, i.e. hide the window completely
$type::ShowWindowAsync($hwnd, [ShowStates]::ShowNoActivate)
# Start-Sleep -Seconds 2
# restore the window handle again
# [usre32.win]::ShowWindowAsync($hwnd, [ShowStates]::Show)
function Invoke-WakeOnLan
{
param
(
# one or more MACAddresses
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
# mac address must be a following this regex pattern:
[ValidatePattern('^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$')]
[string[]]
$MacAddress
)
begin
{
# instantiate a UDP client:
$UDPclient = [Net.Sockets.UdpClient]::new()
}
process
{
foreach($_ in $MacAddress)
{
try {
$currentMacAddress = $_
# get byte array from mac address:
$mac = $currentMacAddress -split '[:-]' |
# convert the hex number into byte:
ForEach-Object {
[Convert]::ToByte($_, 16)
}
#region compose the "magic packet"
# create a byte array with 102 bytes initialized to 255 each:
$packet = [byte[]](,0xFF * 102)
# leave the first 6 bytes untouched, and
# repeat the target mac address bytes in bytes 7 through 102:
6..101 | Foreach-Object {
# $_ is indexing in the byte array,
# $_ % 6 produces repeating indices between 0 and 5
# (modulo operator)
$packet[$_] = $mac[($_ % 6)]
}
#endregion
# connect to port 400 on broadcast address:
$UDPclient.Connect(([Net.IPAddress]::Broadcast),4000)
# send the magic packet to the broadcast address:
$null = $UDPclient.Send($packet, $packet.Length)
Write-Verbose "sent magic packet to $currentMacAddress..."
}
catch
{
Write-Warning "Unable to send ${mac}: $_"
}
}
}
end
{
# release the UDF client and free its memory:
$UDPclient.Close()
$UDPclient.Dispose()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment