Threadable Pinging Functions
Overview
I developed this tool, Get-DMGThreadedPingableComputers.ps1, to allow you to ping several computers in your environment at once though multiple threads, severely decreasing the amount of time required to return ping results on a large set of computers. What’s neat about it is you can easily get ping results on hundreds of computers in just seconds.
How To Use This Tool
You can either search directly for computers within the script, pass some computers through on the pipeline or import a .CSV file. You can also export results to a .CSV file.
Pass a list of computers and export results to CSV:
Get-ADComputer -filter {name -like "*sql*"} | Get-DGMThreadedPingableComputers -csvoutput "C:\Scripts\Get-DGMThreadedPingableComputer\Get-DGMThreadedPingableComputer-output.csv"
Pass a list of computers (with example output):
Get-ADComputer -filter {name -like "*DGM06123*"} -Properties Description,OperatingSystem | Get-DGMThreadedPingableComputers
No Arguments triggers searching for computers within the script (with example output):
Get-DGMThreadedPingableComputers
PowerShell Script: Get-DMGThreadedPingableComputers.ps1
<#
.Synopsis
Threads and threads
.DESCRIPTION
The tool, Get-DMGThreadedPingableComputers.ps1 was written by David Maiolo.
.EXAMPLE
Get-DMGThreadedPingableComputers -CSVFile laps_computers_import.csv
#>
function Where-ParallelObject {
param(
[Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)] $input,
[ScriptBlock] $Filter,
[int] $threads,
[switch] $progressBar,
[String] $progressBartext
)
$inputQueue = [System.Collections.Queue]::Synchronized( (New-Object System.Collections.Queue) )
$results = [System.Collections.Queue]::Synchronized( (New-Object System.Collections.Queue) )
$sessionstate = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
$sessionstate.Variables.Add(
(New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry('inputQueue', $inputQueue, $null))
)
$sessionstate.Variables.Add(
(New-Object System.Management.Automation.Runspaces.SessionStateVariableEntry('results', $results, $null))
)
$runspacepool = [runspacefactory]::CreateRunspacePool(1, $threads, $sessionstate, $Host)
$runspacepool.Open()
foreach ($object in $input) {
$inputQueue.Enqueue($object)
}
$jobs = @()
$sbpre = '
while($inputQueue.Count -gt 0) {
$_ = $inputQueue.Dequeue();
if('
$sbpost = ')
{
$results.Enqueue($_);
}
}
'
$sb = [ScriptBlock]::Create($sbpre + $Filter.toString() + $sbpost)
1..$threads | % {
$job = [PowerShell]::Create().AddScript($sb)
$job.RunspacePool = $runspacepool
$jobs += New-Object PSObject -Property @{
Job = $job
Result = $job.BeginInvoke()
}
}
do {
if($progressBar.IsPresent)
{
Write-Progress -Activity ($progressBartext+" " +$input.Count+ " Objects") -status ("" + $($results.Count) + " complete.") -percentComplete ( ($results.Count) / $input.Count * 100)
}
Start-Sleep -Seconds 1
} while ( $jobs.Result.IsCompleted -contains $false)
foreach ($job in $jobs) {
$job.Job.EndInvoke($job.Result)
}
$runspacepool.Close()
$runspacepool.Dispose()
return $results.ToArray()
}
function LogIt
{
param (
[Parameter(Mandatory=$true)]
$message,
[Parameter(Mandatory=$true)]
$component,
[Parameter(Mandatory=$true)]
$type )
switch ($type)
{
1 { $type = "Info" }
2 { $type = "Warning" }
3 { $type = "Error" }
4 { $type = "Verbose" }
}
if (($type -eq "Verbose") -and ($Global:Verbose))
{
$toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
$toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
Write-Host $message
}
elseif ($type -ne "Verbose")
{
$toLog = "{0} `$$<{1}><{2} {3}>" -f ($type + ":" + $message), ($Global:ScriptName + ":" + $component), (Get-Date -Format "MM-dd-yyyy"), (Get-Date -Format "HH:mm:ss.ffffff"), $pid
$toLog | Out-File -Append -Encoding UTF8 -FilePath ("filesystem::{0}" -f $Global:LogFile)
if ($type -eq 'Info') { Write-Host $message }
if ($type -eq 'Warning') { Write-Host $message -ForegroundColor Yellow}
if ($type -eq 'Error') { Write-Host $message -ForegroundColor Red}
}
if (($type -eq 'Warning') -and ($Global:ScriptStatus -ne 'Error')) { $Global:ScriptStatus = $type }
if ($type -eq 'Error') { $Global:ScriptStatus = $type }
if ((Get-Item $Global:LogFile).Length/1KB -gt $Global:MaxLogSizeInKB)
{
$log = $Global:LogFile
Remove-Item ($log.Replace(".log", ".lo_"))
Rename-Item $Global:LogFile ($log.Replace(".log", ".lo_")) -Force
}
}
function GetScriptDirectory
{
$invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $invocation.MyCommand.Path
}
function Get-DMGThreadedPingableComputers {
param(
[Parameter(Position=0,Mandatory=$false,ValueFromPipeline=$true)] $input,
[ValidateScript({(Test-Path $_)})]
[String] $csvinput,
[ValidateScript({($_ -le 100 -and $_ -gt 0)})]
[int] $threads=100,
[String] $csvoutput
)
$path = (get-item -Path .).FullName
$arraytoping=@()
#Header
Write-Host "==========================================" -ForegroundColor Cyan
Write-Host "Ping Computers in Threads " -ForegroundColor Cyan
Write-Host "v0.1 (2017-12-28) by dmaiolo" -ForegroundColor Cyan
Write-Host "Threading function by jreal" -ForegroundColor Cyan
Write-Host "==========================================" -ForegroundColor Cyan
LogIt -message ("Starting Logging for $Global:ScriptName") -component "Main()" -type 1
#Check for what arguments were passed
if([bool]($MyInvocation.BoundParameters.Keys -match 'csvinput')){
Write-Host "Importing $csvinput..."
$csvimport = import-csv $csvinput
$csvimport | foreach-object {$arraytoping += $_.name; Write-Host "Importing $_.name ..."}
}
elseif([bool]($MyInvocation.BoundParameters.Keys -match 'input')){
Write-Host "Importing from pipeline..."
foreach ($object in $input) {
$arraytoping += $object
}
}else{
Write-Host "Manual Input Selected."
$arraytoping = Get-DMGSearchQueryComputers
}
if([bool]($MyInvocation.BoundParameters.Keys -match 'csvoutput')){
$csvoutputcheck = $true
}
#Ping the computers
$pingablecomputers = Get-DMGOnlineComputers -ComputerList $arraytoping -Threads $threads
#Create Pingable Table
if ($pingablecomputers){
Write-Host ========================================== -ForegroundColor Cyan
Write-Host Pingable Computers -ForegroundColor Green
Write-Host ========================================== -ForegroundColor Cyan
$pingablecomputers | Select Name,Description,OperatingSystem | Format-Table -AutoSize
}else{
Write-Host "No Pingable Computers Were Found."
}
#Create Non-Pingable Array
$nonpingablecomputers = $arraytoping | where {$pingablecomputers -notcontains $_}
#Create Non-Pingable Table
if ($nonpingablecomputers){
Write-Host ========================================== -ForegroundColor Cyan
Write-Host Non Pingable Computers -ForegroundColor Red
Write-Host ========================================== -ForegroundColor Cyan
$nonpingablecomputers | Select Name,Description,OperatingSystem | Format-Table -AutoSize
}else{
Write-Host "No Non-Pingable Computers Were Found."
}
#Export to CSV if chosen
if ($csvoutputcheck){
Write-Host ========================================== -ForegroundColor Cyan
Write-Host CSV Output Results -ForegroundColor Cyan
Write-Host ========================================== -ForegroundColor Cyan
#Build the array
$results = @()
$pingablecomputers | select Name,Description,OperatingSystem,@{Name='Pingable';Expression={"True"}} | %{$results += $_ }
$nonpingablecomputers | select Name,Description,OperatingSystem,@{Name='Pingable';Expression={"False"}} | %{$results += $_ }
New-DMGCSVOut -csvoutputpath $csvoutput -arrayforoutput $results
}
#Footer
Write-Host ========================================== -ForegroundColor Cyan
Write-Host "Log File of Results Generated" -ForegroundColor Cyan
Write-Host ========================================== -ForegroundColor Cyan
Write-Host "Log File`: $Global:LogFile VIEW WITH CMTRACE.EXE"
LogIt -message ("Ending Logging for $Global:ScriptName") -component "Main()" -type 1
}
function Get-DMGSearchQueryComputers
{
Write-Host "[1] Search by whole or partial computer name"
Write-Host "[2] Search by description"
Write-Host "[3] Search by Operating System"
do {
try {$numOk = $true; [int]$GetMyANumber = Read-host "Selection"}
catch {$numOK = $false}}
until (($GetMyANumber -ge 1 -and $GetMyANumber -le 3) -and $numOK)
$validcharacters = "^[a-zA-Z0-9\s]+$"
do {
try {$stringOk = $true; [string]$query = Read-host "Enter search query (only letters and numbers)"}
catch {$stringOk = $false}}
until (($query -match $validcharacters) -and $stringOk)
$query = "*"+$query
$query = $query+"*"
switch ($GetMyANumber)
{
1 {$computers = Get-ADComputer -Properties Description,OperatingSystem -filter {name -like $query}}
2 {$computers = Get-ADComputer -Properties Description,OperatingSystem -filter {description -like $query}}
3 {$computers = Get-ADComputer -Properties Description,OperatingSystem -filter {OperatingSystem -like $query}}
}
return $computers
}
function Get-DMGOnlineComputers{
param(
[Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
[int] $threads,
[Array] $ComputerList
)
Write-Host ========================================== -ForegroundColor Cyan
Write-Host Pinging Computers and Building Table -ForegroundColor Cyan
Write-Host ========================================== -ForegroundColor Cyan
$computers = @()
if ($ComputerList.Length -gt 0){
Write-Host "Pinging"($ComputerList.length)"computers in $threads threads."
$computers = $ComputerList | Where-ParallelObject -Filter {Test-Connection -ComputerName $_.Name -Quiet -Count 1} -Threads $threads -ProgressBar -progressBartext "Pinging"
<#$computers | foreach-object {
LogIt -message ("ICMP Response Succesful`: " +($_.Name).ToString() +" - "+($_.Description).ToString()) -component "Main()" -type 1
}#>
return $computers
}else{
Write-Host "No Computers were found."
return $false
}
}
function New-DMGCSVOut{
param(
[Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true)]
[String] $csvoutputpath,
[array] $arrayforoutput
)
try{
$arrayforoutput | export-csv $csvoutputpath -notypeinformation
LogIt -message ("CSV Export`: CSV Created at $csvoutputpath") -component "Main()" -type 1
}catch{
LogIt -message ("CSV Export`: CSV Could NOT be Created at $csvoutputpath") -component "Main()" -type 3
}
}
$VerboseLogging = "true"
[bool]$Global:Verbose = [System.Convert]::ToBoolean($VerboseLogging)
$Global:LogFile = Join-Path (GetScriptDirectory) "'Get-DMGThreadedPingableComputer.log"
$Global:MaxLogSizeInKB = 10240
$Global:ScriptName = 'Get-DMGThreadedPingableComputer.ps1'
$Global:ScriptStatus = 'Success'
Leave a Reply
Want to join the discussion?Feel free to contribute!