Public/Test-Connections.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
function Test-Connections { <# .Synopsis Test-Connection to multiple devices in parallel. .Description Test-Connection to multiple devcies in parallel with a color and "watch" feature. .Example Test-Connections -TargetName 1.1.1.1 -Watch .Example Test-Connections -TargetName 1.1.1.1, 1.0.0.1, 8.8.4.4, 8.8.8.8, 9.9.9.9 -Watch .Example Test-Connections 1.1.1.1, 1.0.0.1, 8.8.4.4, 8.8.8.8, 9.9.9.9 -Watch -Repeat .Example Test-Connections 1.1.1.1, 1.0.0.1, 8.8.4.4, 8.8.8.8, 9.9.9.9 -Count 10 -Watch .Example Test-Connections $(Get-Content servers.txt) -Watch .Example @("1.1.1.1", "1.0.0.1", "8.8.4.4", "8.8.8.8", "9.9.9.9") | Test-Connections -Watch .Example Connect-VIServer esxi.local Get-VM | Test-Connections -Watch .Example (1..10) | ForEach-Object { "192.168.0.$_" } | Test-Connections -Watch .Notes Name: Test-Connections Author: David Isaacson Last Edit: 2022-04-24 Keywords: Test-Connection, ping, icmp .Link https://github.com/daisaacson/test-connections .Inputs TargetName[] .Outputs none #Requires -Version 2.0 #> [CmdletBinding(SupportsShouldProcess = $True)] Param ( [Parameter(Mandatory = $True, ValueFromPipeline = $True, HelpMessage = "Stop after sending Count pings")] [string[]]$TargetName, [Parameter(Mandatory = $False)] [Alias("c")] [int]$Count = 4, [Parameter(Mandatory = $False, HelpMessage = "Continjously send pings")] [Alias("Continuous", "t")] [switch]$Repeat, [Parameter(Mandatory = $False, HelpMessage = "Delay between pings")] [int]$Delay = 1, [Parameter(Mandatory = $False, HelpMessage = "Interval between pings")] [Alias("u")] [int]$Update = 1000, [Parameter(Mandatory = $False, HelpMessage = "Watch")] [Alias("w")] [Switch]$Watch ) Begin { Write-Verbose -Message "Begin $($MyInvocation.MyCommand)" $Targets = @() # Destingwish between Windows PowerShell and PowerShell Core $WindowsPowerShell = $PSVersionTable.PSEdition -and $PSVersionTable.PSEdition -eq 'Desktop' $PowerShellCore = ! $WindowsPowerShell } Process { Write-Verbose -Message "Process $($MyInvocation.MyCommand)" If ($pscmdlet.ShouldProcess("$TargetName")) { ForEach ($Target in $TargetName) { Write-Verbose -Message "$Target, $Count, $Delay, $Repeat" Try { If ($WindowsPowerShell) { # Create new Target and Start-Job # Windows PowerShell 5.1 Test-Connection sucks, wrapper for Test-Connection to behave more like Test-Connection in PowerShell Core $Targets += [Target]::new($Target, $(Start-Job -ScriptBlock $([ScriptBlock]::Create({ Param ([String]$TargetName, [int]$Count = 4, [int]$Delay = 1, [bool]$Repeat) $Ping = 0 While ($Repeat -or $Count -gt $Ping) { Write-Verbose "$($Repeat) $($Count) $($Ping)" $Ping++ $icmp = Test-Connection -ComputerName $TargetName -Count 1 -ErrorAction SilentlyContinue If ($icmp) { [PSCustomObject]@{ Ping = $Ping; Status = "Success" Latency = $icmp.ResponseTime } } else { [PSCustomObject]@{ Ping = $Ping Status = "Failed" Latency = 9999 } } Start-Sleep -Seconds $Delay } } ) ) -ArgumentList $Target, $Count, $Delay, $Repeat ) ) } else { If ($Repeat) { $Targets += [Target]::new($Target, $(Start-Job -ScriptBlock $([ScriptBlock]::Create({ Param ($Target) Test-Connection -TargetName $Target -Ping -Repeat })) -ArgumentList $Target)) } else { $Targets += [Target]::new($Target, $(Start-Job -ScriptBlock $([ScriptBlock]::Create({ Param ($Target, $Count) Test-Connection -TargetName $Target -Ping -Count $Count })) -ArgumentList $Target, $Count)) } } } Catch { $_ } } } } End { Write-Verbose -Message "End $($MyInvocation.MyCommand)" If ($pscmdlet.ShouldProcess("$TargetName")) { # https://blog.sheehans.org/2018/10/27/powershell-taking-control-over-ctrl-c/ # Change the default behavior of CTRL-C so that the script can intercept and use it versus just terminating the script. [Console]::TreatControlCAsInput = $True # Sleep for 1 second and then flush the key buffer so any previously pressed keys are discarded and the loop can monitor for the use of # CTRL-C. The sleep command ensures the buffer flushes correctly. Start-Sleep -Seconds 1 $Host.UI.RawUI.FlushInputBuffer() # Continue to loop while there are pending or currently executing jobs. While ($Targets.Job.HasMoreData -contains "True") { # If a key was pressed during the loop execution, check to see if it was CTRL-C (aka "3"), and if so exit the script after clearing # out any running jobs and setting CTRL-C back to normal. If ($Host.UI.RawUI.KeyAvailable -and ($Key = $Host.UI.RawUI.ReadKey("AllowCtrlC,NoEcho,IncludeKeyUp"))) { If ([Int]$Key.Character -eq 3) { Write-Warning -Message "Removing Test-Connection Jobs" If ($PowerShellCore) { Write-Host "`e[2A" } $Targets.Job | Remove-Job -Force $killed = $True [Console]::TreatControlCAsInput = $False break } # Flush the key buffer again for the next loop. $Host.UI.RawUI.FlushInputBuffer() } # Perform other work here such as process pending jobs or process out current jobs. # Get Test-Connection updates $Targets.Update() # Print Output $Targets.ToTable() | Format-Table # Move cursor up to overwrite old output If ($Watch -and $PowerShellCore) { Write-Host "`e[$($Targets.length+5)A" } # Output update delay Start-Sleep -Milliseconds $Update } # Clean up jobs If (!$killed) { $Targets.Job | Remove-Job -Force } # If in "Watch" mode, print output one last time If ($Watch) { $Targets.ToTable() | Format-Table } } } } #End function |