Posted in : Active Directory, Azure, Microsoft, Powershell, Windows, Windows Server Av Stina Perbo Utas Översätt med Google ⟶
4 years ago
Invoking commands remotely on machines is something we must do from time to time, in many scenarios speed is a critical factor as the remote command could be in response to anything from a incident to security breach. Speed combined with large environments in the cloud with many clients/servers deallocated often makes this a difficult task.
In smaller environments we would normally ping targets, and based on the response we execute a script through winrm asyncronously (invoke-command -asjob). The problem is that the ping part is often not executed in parallell.
While googling a solution i came across an Async ping sweep script (link at the end) that works brilliantly but only accepts ipranges and not hostnames, but the method to send async pings is so good that I used it in my implementation.
The result:
Function Test-ConnectionAsync { <# .Synopsis Ping targets asynchronously .DESCRIPTION Ping targets using dns names or ip addresses asynchronously .NOTES Name: Test-ConnectionAsync Author: Vikingur Saemundsson Date Created: 2020-07-20 Version History: 2020-07-20 - Vikingur Saemundsson Initial Creation Xenit AB #> Param( [Parameter( Mandatory=$true, ValueFromPipeline=$true )] [string[]]$Targets, $Timeout = 1000 # milliseconds ) Begin{ #Cleanup Remove-Event -SourceIdentifier "Async-Ping*" Unregister-Event -SourceIdentifier "Async-Ping*" } Process{ Foreach($target in $targets){ #prepare a unique identifier for the ping object so we can later identify the results $thisName = "Ping_$target`_$([guid]::NewGuid().ToString())" #Create ping object in variable New-Variable -Name $thisName -Value (New-Object System.Net.NetworkInformation.Ping) #Register the variable as event Register-ObjectEvent -InputObject (Get-Variable $thisName -ValueOnly) -EventName PingCompleted -SourceIdentifier "Async-$thisName" #invoke async ping in variable (Get-Variable $thisName -ValueOnly).SendAsync($target,$timeout,$thisName) #Cleanup variable Remove-Variable $thisName } $pending = (Get-Event -SourceIdentifier "Async-Ping*").Count #await all responses While($pending -lt $targets.Count){ Wait-Event -SourceIdentifier "Async-Ping*" | Out-Null Start-Sleep -Milliseconds 10 $pending = (Get-Event -SourceIdentifier "Async-Ping*").Count } [array]$Return = Get-Event -SourceIdentifier "Async-Ping*" | ForEach-Object{ [pscustomobject]@{ Target = $_.SourceIdentifier.Substring(11).Substring(0,$_.SourceIdentifier.Length-48) Status = $_.SourceEventArgs.Reply.Status Error = $_.SourceEventArgs.Error Reply = $_.SourceEventArgs.Reply } } } End{ #Cleanup Remove-Event -SourceIdentifier "Async-Ping*" Unregister-Event -SourceIdentifier "Async-Ping*" Return $Return } }
The output is a object that contains original target name, the ping status (Success, Timeout etc), errors and the Ping reply object.
PS C:\Users\vikingur.saemundsson> $Targets = 'localhost','google.com' PS C:\Users\vikingur.saemundsson> Test-ConnectionAsync -Targets $targets -Timeout $timeout Target Status Error Reply ------ ------ ----- ----- localhost Success System.Net.NetworkInformation.PingReply google.com Success System.Net.NetworkInformation.PingReply PS C:\Users\vikingur.saemundsson> Test-ConnectionAsync -Targets $targets -Timeout $timeout | Select -ExpandProperty reply Status : Success Address : ::1 RoundtripTime : 8 Options : Buffer : {97, 98, 99, 100...} Status : Success Address : 216.58.211.14 RoundtripTime : 12 Options : System.Net.NetworkInformation.PingOptions Buffer : {97, 98, 99, 100...}
Using this we can use Invoke-Command with the -AsJob command to invoke.
Test-ConnectionAsync -Targets $Servers.Name -timeout 50 -verbose | ForEach-Object{ Invoke-Command -ComputerName $_.Target -AsJob -JobName $_.Target -ThrottleLimit 100 -ScriptBlock { $env:COMPUTERNAME gpupdate /force | Out-Null } -ErrorAction Stop }
To get a sense of the performance of the system I did some benchmark pings against a Google ip range. The average /24 network took 0.5 seconds, or 547 milliseconds to respond using a max timeout of 100ms per attempt. The function does not really scale linearly, but I believe that’s more on my side than the code.
pinging 256 targets (35.191.0.0 - 35.191.0.255) 50 times average: 547.62735 milliseconds pinging 512 targets (35.191.0.0 - 35.191.1.255) 50 times average: 1618.175738 milliseconds pinging 1024 targets (35.191.0.0 - 35.191.3.255) 50 times average: 2480.677944 milliseconds pinging 2048 targets (35.191.0.0 - 35.191.7.255) 50 times average: 5737.749198 milliseconds pinging 4096 targets (35.191.0.0 - 35.191.15.255) 50 times average: 10840.020774 milliseconds
Async network ping sweep
https://gallery.technet.microsoft.com/scriptcenter/Asynchronous-Network-Ping-abdf01aa
Tags : #Script, Async, asynchronous, Azure, code, How to, Microsoft, Ping, PowerShell, Security, Windows, Windows 10, Windows Server, Windows Server 2016
Personlig rådgivning
Vi erbjuder personlig rådgivning med författaren för 1400 SEK per timme. Anmäl ditt intresse i här så återkommer vi så snart vi kan.
Add comment