mirror of
https://github.com/HarmJ0y/Misc-PowerShell
synced 2026-08-09 12:07:26 +00:00
631 lines
27 KiB
PowerShell
631 lines
27 KiB
PowerShell
function Invoke-FindDebuggerBackdoors {
|
|
<#
|
|
.SYNOPSIS
|
|
Checks a remote server to see if the debugger for specific
|
|
binaries has been set through querying the remote registry.
|
|
|
|
License: BSD 3-Clause
|
|
Author: @harmj0y
|
|
|
|
.DESCRIPTION
|
|
This function uses either ping (test-connection) or RPC
|
|
(through WMI) to test connectivity to a remote server.
|
|
|
|
.PARAMETER HostName
|
|
The hostname/IP to test for debuggers
|
|
|
|
.EXAMPLE
|
|
Invoke-FindDebuggerBackdoors WINDOWS3 | ft -autosize
|
|
#>
|
|
[CmdletBinding()]
|
|
param(
|
|
[Parameter(ValueFromPipeline=$True)]
|
|
$HostName = "."
|
|
)
|
|
|
|
process {
|
|
$binaries = @("sethc.exe", "Utilman.exe", "osk.exe", "Narrator.exe", "Magnify.exe")
|
|
|
|
try{
|
|
$binaries | Foreach-Object {
|
|
$reg = [WMIClass]"\\$HostName\root\default:stdRegProv"
|
|
$hklm = 2147483650
|
|
$key = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\$($_)"
|
|
$value = "Debugger"
|
|
|
|
$result = $reg.GetStringValue($hklm, $key, $value).sValue
|
|
|
|
if($result){
|
|
if($HostName -eq "."){
|
|
$HostName = [System.Net.Dns]::GetHostByName(($env:computerName)) | FL HostName | Out-String | %{ "{0}" -f $_.Split(':')[1].Trim() }
|
|
}
|
|
$out = new-object psobject
|
|
$out | add-member Noteproperty 'Host' $HostName
|
|
$out | add-member Noteproperty 'Process' $_
|
|
$out | add-member Noteproperty 'Debugger' $result
|
|
$out
|
|
}
|
|
}
|
|
}
|
|
catch{
|
|
Write-Warning "[!] Error opening remote registry on $HostName. Remote registry likely not enabled."
|
|
$null
|
|
}
|
|
}
|
|
end{}
|
|
|
|
}
|
|
|
|
function Invoke-FindDomainDebuggerBackdoors {
|
|
<#
|
|
.SYNOPSIS
|
|
Queries all machines on the domain, and checks each one to
|
|
see if the debugger for specific binaries has been set
|
|
through querying the remote registry.
|
|
|
|
.EXAMPLE
|
|
Invoke-FindDomainDebuggerBackdoors | ft -autosize
|
|
#>
|
|
$CompSearcher = New-Object System.DirectoryServices.DirectorySearcher
|
|
$CompSearcher.Filter = ("(objectCategory=computer)")
|
|
$CompSearcher.PageSize = 200
|
|
|
|
$Computers = $CompSearcher.FindAll() | ForEach-Object { $_.properties.dnshostname }
|
|
$Computers | Invoke-Ping | ForEach-Object {
|
|
Invoke-FindDebuggerBackdoors $HostName
|
|
}
|
|
}
|
|
|
|
# adapted from RamblingCookieMonster's code at
|
|
# https://github.com/RamblingCookieMonster/PowerShell/blob/master/Invoke-Ping.ps1
|
|
function Invoke-Ping {
|
|
<#
|
|
.SYNOPSIS
|
|
Ping systems in parallel
|
|
Author: RamblingCookieMonster
|
|
|
|
.PARAMETER ComputerName
|
|
One or more computers to test
|
|
|
|
.PARAMETER Timeout
|
|
Time in seconds before we attempt to dispose an individual query. Default is 20
|
|
|
|
.PARAMETER Throttle
|
|
Throttle query to this many parallel runspaces. Default is 100.
|
|
|
|
.PARAMETER NoCloseOnTimeout
|
|
Do not dispose of timed out tasks or attempt to close the runspace if threads have timed out
|
|
|
|
This will prevent the script from hanging in certain situations where threads become non-responsive, at the expense of leaking memory within the PowerShell host.
|
|
|
|
.EXAMPLE
|
|
$Responding = $Computers | Invoke-Ping
|
|
|
|
# Create a list of computers that successfully responded to Test-Connection
|
|
|
|
.LINK
|
|
https://github.com/RamblingCookieMonster/PowerShell/blob/master/Invoke-Ping.ps1
|
|
https://gallery.technet.microsoft.com/scriptcenter/Invoke-Ping-Test-in-b553242a
|
|
#>
|
|
|
|
[cmdletbinding(DefaultParameterSetName='Ping')]
|
|
param(
|
|
[Parameter( ValueFromPipeline=$true,
|
|
ValueFromPipelineByPropertyName=$true,
|
|
Position=0)]
|
|
[string[]]$ComputerName,
|
|
|
|
[int]$Timeout = 20,
|
|
|
|
[int]$Throttle = 100,
|
|
|
|
[switch]$NoCloseOnTimeout
|
|
)
|
|
|
|
Begin
|
|
{
|
|
$Quiet = $True
|
|
|
|
#http://gallery.technet.microsoft.com/Run-Parallel-Parallel-377fd430
|
|
function Invoke-Parallel {
|
|
[cmdletbinding(DefaultParameterSetName='ScriptBlock')]
|
|
Param (
|
|
[Parameter(Mandatory=$false,position=0,ParameterSetName='ScriptBlock')]
|
|
[System.Management.Automation.ScriptBlock]$ScriptBlock,
|
|
|
|
[Parameter(Mandatory=$false,ParameterSetName='ScriptFile')]
|
|
[ValidateScript({test-path $_ -pathtype leaf})]
|
|
$ScriptFile,
|
|
|
|
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
|
|
[Alias('CN','__Server','IPAddress','Server','ComputerName')]
|
|
[PSObject]$InputObject,
|
|
|
|
[PSObject]$Parameter,
|
|
|
|
[switch]$ImportVariables,
|
|
|
|
[switch]$ImportModules,
|
|
|
|
[int]$Throttle = 20,
|
|
|
|
[int]$SleepTimer = 200,
|
|
|
|
[int]$RunspaceTimeout = 0,
|
|
|
|
[switch]$NoCloseOnTimeout = $false,
|
|
|
|
[int]$MaxQueue,
|
|
|
|
[validatescript({Test-Path (Split-Path $_ -parent)})]
|
|
[string]$LogFile = "C:\temp\log.log",
|
|
|
|
[switch] $Quiet = $false
|
|
)
|
|
|
|
Begin {
|
|
|
|
#No max queue specified? Estimate one.
|
|
#We use the script scope to resolve an odd PowerShell 2 issue where MaxQueue isn't seen later in the function
|
|
if( -not $PSBoundParameters.ContainsKey('MaxQueue') )
|
|
{
|
|
if($RunspaceTimeout -ne 0){ $script:MaxQueue = $Throttle }
|
|
else{ $script:MaxQueue = $Throttle * 3 }
|
|
}
|
|
else
|
|
{
|
|
$script:MaxQueue = $MaxQueue
|
|
}
|
|
|
|
Write-Verbose "Throttle: '$throttle' SleepTimer '$sleepTimer' runSpaceTimeout '$runspaceTimeout' maxQueue '$maxQueue' logFile '$logFile'"
|
|
|
|
#If they want to import variables or modules, create a clean runspace, get loaded items, use those to exclude items
|
|
if ($ImportVariables -or $ImportModules)
|
|
{
|
|
$StandardUserEnv = [powershell]::Create().addscript({
|
|
|
|
#Get modules and snapins in this clean runspace
|
|
$Modules = Get-Module | Select -ExpandProperty Name
|
|
$Snapins = Get-PSSnapin | Select -ExpandProperty Name
|
|
|
|
#Get variables in this clean runspace
|
|
#Called last to get vars like $? into session
|
|
$Variables = Get-Variable | Select -ExpandProperty Name
|
|
|
|
#Return a hashtable where we can access each.
|
|
@{
|
|
Variables = $Variables
|
|
Modules = $Modules
|
|
Snapins = $Snapins
|
|
}
|
|
}).invoke()[0]
|
|
|
|
if ($ImportVariables) {
|
|
#Exclude common parameters, bound parameters, and automatic variables
|
|
Function _temp {[cmdletbinding()] param() }
|
|
$VariablesToExclude = @( (Get-Command _temp | Select -ExpandProperty parameters).Keys + $PSBoundParameters.Keys + $StandardUserEnv.Variables )
|
|
Write-Verbose "Excluding variables $( ($VariablesToExclude | sort ) -join ", ")"
|
|
|
|
# we don't use 'Get-Variable -Exclude', because it uses regexps.
|
|
# One of the veriables that we pass is '$?'.
|
|
# There could be other variables with such problems.
|
|
# Scope 2 required if we move to a real module
|
|
$UserVariables = @( Get-Variable | Where { -not ($VariablesToExclude -contains $_.Name) } )
|
|
Write-Verbose "Found variables to import: $( ($UserVariables | Select -expandproperty Name | Sort ) -join ", " | Out-String).`n"
|
|
|
|
}
|
|
|
|
if ($ImportModules)
|
|
{
|
|
$UserModules = @( Get-Module | Where {$StandardUserEnv.Modules -notcontains $_.Name -and (Test-Path $_.Path -ErrorAction SilentlyContinue)} | Select -ExpandProperty Path )
|
|
$UserSnapins = @( Get-PSSnapin | Select -ExpandProperty Name | Where {$StandardUserEnv.Snapins -notcontains $_ } )
|
|
}
|
|
}
|
|
|
|
#region functions
|
|
|
|
Function Get-RunspaceData {
|
|
[cmdletbinding()]
|
|
param( [switch]$Wait )
|
|
|
|
#loop through runspaces
|
|
#if $wait is specified, keep looping until all complete
|
|
Do {
|
|
|
|
#set more to false for tracking completion
|
|
$more = $false
|
|
|
|
#run through each runspace.
|
|
Foreach($runspace in $runspaces) {
|
|
|
|
#get the duration - inaccurate
|
|
$currentdate = Get-Date
|
|
$runtime = $currentdate - $runspace.startTime
|
|
$runMin = [math]::Round( $runtime.totalminutes ,2 )
|
|
|
|
#set up log object
|
|
$log = "" | select Date, Action, Runtime, Status, Details
|
|
$log.Action = "Removing:'$($runspace.object)'"
|
|
$log.Date = $currentdate
|
|
$log.Runtime = "$runMin minutes"
|
|
|
|
#If runspace completed, end invoke, dispose, recycle, counter++
|
|
If ($runspace.Runspace.isCompleted) {
|
|
|
|
$script:completedCount++
|
|
|
|
#check if there were errors
|
|
if($runspace.powershell.Streams.Error.Count -gt 0) {
|
|
|
|
#set the logging info and move the file to completed
|
|
$log.status = "CompletedWithErrors"
|
|
Write-Verbose ($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1]
|
|
foreach($ErrorRecord in $runspace.powershell.Streams.Error) {
|
|
Write-Error -ErrorRecord $ErrorRecord
|
|
}
|
|
}
|
|
else {
|
|
|
|
#add logging details and cleanup
|
|
$log.status = "Completed"
|
|
Write-Verbose ($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1]
|
|
}
|
|
|
|
#everything is logged, clean up the runspace
|
|
$runspace.powershell.EndInvoke($runspace.Runspace)
|
|
$runspace.powershell.dispose()
|
|
$runspace.Runspace = $null
|
|
$runspace.powershell = $null
|
|
|
|
}
|
|
|
|
#If runtime exceeds max, dispose the runspace
|
|
ElseIf ( $runspaceTimeout -ne 0 -and $runtime.totalseconds -gt $runspaceTimeout) {
|
|
|
|
$script:completedCount++
|
|
$timedOutTasks = $true
|
|
|
|
#add logging details and cleanup
|
|
$log.status = "TimedOut"
|
|
Write-Verbose ($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1]
|
|
Write-Error "Runspace timed out at $($runtime.totalseconds) seconds for the object:`n$($runspace.object | out-string)"
|
|
|
|
#Depending on how it hangs, we could still get stuck here as dispose calls a synchronous method on the powershell instance
|
|
if (!$noCloseOnTimeout) { $runspace.powershell.dispose() }
|
|
$runspace.Runspace = $null
|
|
$runspace.powershell = $null
|
|
$completedCount++
|
|
|
|
}
|
|
|
|
#If runspace isn't null set more to true
|
|
ElseIf ($runspace.Runspace -ne $null ) {
|
|
$log = $null
|
|
$more = $true
|
|
}
|
|
|
|
#log the results if a log file was indicated
|
|
if($logFile -and $log){
|
|
($log | ConvertTo-Csv -Delimiter ";" -NoTypeInformation)[1] | out-file $LogFile -append
|
|
}
|
|
}
|
|
|
|
#Clean out unused runspace jobs
|
|
$temphash = $runspaces.clone()
|
|
$temphash | Where { $_.runspace -eq $Null } | ForEach {
|
|
$Runspaces.remove($_)
|
|
}
|
|
|
|
#sleep for a bit if we will loop again
|
|
if($PSBoundParameters['Wait']){ Start-Sleep -milliseconds $SleepTimer }
|
|
|
|
#Loop again only if -wait parameter and there are more runspaces to process
|
|
} while ($more -and $PSBoundParameters['Wait'])
|
|
|
|
#End of runspace function
|
|
}
|
|
|
|
#endregion functions
|
|
|
|
#region Init
|
|
|
|
if($PSCmdlet.ParameterSetName -eq 'ScriptFile')
|
|
{
|
|
$ScriptBlock = [scriptblock]::Create( $(Get-Content $ScriptFile | out-string) )
|
|
}
|
|
elseif($PSCmdlet.ParameterSetName -eq 'ScriptBlock')
|
|
{
|
|
#Start building parameter names for the param block
|
|
[string[]]$ParamsToAdd = '$_'
|
|
if( $PSBoundParameters.ContainsKey('Parameter') )
|
|
{
|
|
$ParamsToAdd += '$Parameter'
|
|
}
|
|
|
|
$UsingVariableData = $Null
|
|
|
|
# This code enables $Using support through the AST.
|
|
# This is entirely from Boe Prox, and his https://github.com/proxb/PoshRSJob module; all credit to Boe!
|
|
|
|
if($PSVersionTable.PSVersion.Major -gt 2)
|
|
{
|
|
#Extract using references
|
|
$UsingVariables = $ScriptBlock.ast.FindAll({$args[0] -is [System.Management.Automation.Language.UsingExpressionAst]},$True)
|
|
|
|
If ($UsingVariables)
|
|
{
|
|
$List = New-Object 'System.Collections.Generic.List`1[System.Management.Automation.Language.VariableExpressionAst]'
|
|
ForEach ($Ast in $UsingVariables)
|
|
{
|
|
[void]$list.Add($Ast.SubExpression)
|
|
}
|
|
|
|
$UsingVar = $UsingVariables | Group Parent | ForEach {$_.Group | Select -First 1}
|
|
|
|
#Extract the name, value, and create replacements for each
|
|
$UsingVariableData = ForEach ($Var in $UsingVar) {
|
|
Try
|
|
{
|
|
$Value = Get-Variable -Name $Var.SubExpression.VariablePath.UserPath -ErrorAction Stop
|
|
$NewName = ('$__using_{0}' -f $Var.SubExpression.VariablePath.UserPath)
|
|
[pscustomobject]@{
|
|
Name = $Var.SubExpression.Extent.Text
|
|
Value = $Value.Value
|
|
NewName = $NewName
|
|
NewVarName = ('__using_{0}' -f $Var.SubExpression.VariablePath.UserPath)
|
|
}
|
|
$ParamsToAdd += $NewName
|
|
}
|
|
Catch
|
|
{
|
|
Write-Error "$($Var.SubExpression.Extent.Text) is not a valid Using: variable!"
|
|
}
|
|
}
|
|
|
|
$NewParams = $UsingVariableData.NewName -join ', '
|
|
$Tuple = [Tuple]::Create($list, $NewParams)
|
|
$bindingFlags = [Reflection.BindingFlags]"Default,NonPublic,Instance"
|
|
$GetWithInputHandlingForInvokeCommandImpl = ($ScriptBlock.ast.gettype().GetMethod('GetWithInputHandlingForInvokeCommandImpl',$bindingFlags))
|
|
|
|
$StringScriptBlock = $GetWithInputHandlingForInvokeCommandImpl.Invoke($ScriptBlock.ast,@($Tuple))
|
|
|
|
$ScriptBlock = [scriptblock]::Create($StringScriptBlock)
|
|
|
|
Write-Verbose $StringScriptBlock
|
|
}
|
|
}
|
|
|
|
$ScriptBlock = $ExecutionContext.InvokeCommand.NewScriptBlock("param($($ParamsToAdd -Join ", "))`r`n" + $Scriptblock.ToString())
|
|
}
|
|
else
|
|
{
|
|
Throw "Must provide ScriptBlock or ScriptFile"; Break
|
|
}
|
|
|
|
Write-Debug "`$ScriptBlock: $($ScriptBlock | Out-String)"
|
|
Write-Verbose "Creating runspace pool and session states"
|
|
|
|
#If specified, add variables and modules/snapins to session state
|
|
$sessionstate = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
|
|
if ($ImportVariables)
|
|
{
|
|
if($UserVariables.count -gt 0)
|
|
{
|
|
foreach($Variable in $UserVariables)
|
|
{
|
|
$sessionstate.Variables.Add( (New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList $Variable.Name, $Variable.Value, $null) )
|
|
}
|
|
}
|
|
}
|
|
if ($ImportModules)
|
|
{
|
|
if($UserModules.count -gt 0)
|
|
{
|
|
foreach($ModulePath in $UserModules)
|
|
{
|
|
$sessionstate.ImportPSModule($ModulePath)
|
|
}
|
|
}
|
|
if($UserSnapins.count -gt 0)
|
|
{
|
|
foreach($PSSnapin in $UserSnapins)
|
|
{
|
|
[void]$sessionstate.ImportPSSnapIn($PSSnapin, [ref]$null)
|
|
}
|
|
}
|
|
}
|
|
|
|
#Create runspace pool
|
|
$runspacepool = [runspacefactory]::CreateRunspacePool(1, $Throttle, $sessionstate, $Host)
|
|
$runspacepool.Open()
|
|
|
|
Write-Verbose "Creating empty collection to hold runspace jobs"
|
|
$Script:runspaces = New-Object System.Collections.ArrayList
|
|
|
|
#If inputObject is bound get a total count and set bound to true
|
|
$global:__bound = $false
|
|
$allObjects = @()
|
|
if( $PSBoundParameters.ContainsKey("inputObject") ){
|
|
$global:__bound = $true
|
|
}
|
|
|
|
#Set up log file if specified
|
|
if( $LogFile ){
|
|
New-Item -ItemType file -path $logFile -force | Out-Null
|
|
("" | Select Date, Action, Runtime, Status, Details | ConvertTo-Csv -NoTypeInformation -Delimiter ";")[0] | Out-File $LogFile
|
|
}
|
|
|
|
#write initial log entry
|
|
$log = "" | Select Date, Action, Runtime, Status, Details
|
|
$log.Date = Get-Date
|
|
$log.Action = "Batch processing started"
|
|
$log.Runtime = $null
|
|
$log.Status = "Started"
|
|
$log.Details = $null
|
|
if($logFile) {
|
|
($log | convertto-csv -Delimiter ";" -NoTypeInformation)[1] | Out-File $LogFile -Append
|
|
}
|
|
|
|
$timedOutTasks = $false
|
|
|
|
#endregion INIT
|
|
}
|
|
|
|
Process {
|
|
#add piped objects to all objects or set all objects to bound input object parameter
|
|
if( -not $global:__bound ){
|
|
$allObjects += $inputObject
|
|
}
|
|
else{
|
|
$allObjects = $InputObject
|
|
}
|
|
}
|
|
|
|
End {
|
|
|
|
#Use Try/Finally to catch Ctrl+C and clean up.
|
|
Try
|
|
{
|
|
#counts for progress
|
|
$totalCount = $allObjects.count
|
|
$script:completedCount = 0
|
|
$startedCount = 0
|
|
|
|
foreach($object in $allObjects){
|
|
|
|
#region add scripts to runspace pool
|
|
|
|
#Create the powershell instance, set verbose if needed, supply the scriptblock and parameters
|
|
$powershell = [powershell]::Create()
|
|
|
|
if ($VerbosePreference -eq 'Continue')
|
|
{
|
|
[void]$PowerShell.AddScript({$VerbosePreference = 'Continue'})
|
|
}
|
|
|
|
[void]$PowerShell.AddScript($ScriptBlock).AddArgument($object)
|
|
|
|
if ($parameter)
|
|
{
|
|
[void]$PowerShell.AddArgument($parameter)
|
|
}
|
|
|
|
# $Using support from Boe Prox
|
|
if ($UsingVariableData)
|
|
{
|
|
Foreach($UsingVariable in $UsingVariableData) {
|
|
Write-Verbose "Adding $($UsingVariable.Name) with value: $($UsingVariable.Value)"
|
|
[void]$PowerShell.AddArgument($UsingVariable.Value)
|
|
}
|
|
}
|
|
|
|
#Add the runspace into the powershell instance
|
|
$powershell.RunspacePool = $runspacepool
|
|
|
|
#Create a temporary collection for each runspace
|
|
$temp = "" | Select-Object PowerShell, StartTime, object, Runspace
|
|
$temp.PowerShell = $powershell
|
|
$temp.StartTime = Get-Date
|
|
$temp.object = $object
|
|
|
|
#Save the handle output when calling BeginInvoke() that will be used later to end the runspace
|
|
$temp.Runspace = $powershell.BeginInvoke()
|
|
$startedCount++
|
|
|
|
#Add the temp tracking info to $runspaces collection
|
|
Write-Verbose ( "Adding {0} to collection at {1}" -f $temp.object, $temp.starttime.tostring() )
|
|
$runspaces.Add($temp) | Out-Null
|
|
|
|
#loop through existing runspaces one time
|
|
Get-RunspaceData
|
|
|
|
#If we have more running than max queue (used to control timeout accuracy)
|
|
#Script scope resolves odd PowerShell 2 issue
|
|
$firstRun = $true
|
|
while ($runspaces.count -ge $Script:MaxQueue) {
|
|
|
|
#give verbose output
|
|
if($firstRun){
|
|
Write-Verbose "$($runspaces.count) items running - exceeded $Script:MaxQueue limit."
|
|
}
|
|
$firstRun = $false
|
|
|
|
#run get-runspace data and sleep for a short while
|
|
Get-RunspaceData
|
|
Start-Sleep -Milliseconds $sleepTimer
|
|
}
|
|
#endregion add scripts to runspace pool
|
|
}
|
|
|
|
Write-Verbose ( "Finish processing the remaining runspace jobs: {0}" -f ( @($runspaces | Where {$_.Runspace -ne $Null}).Count) )
|
|
Get-RunspaceData -wait
|
|
}
|
|
Finally
|
|
{
|
|
#Close the runspace pool, unless we specified no close on timeout and something timed out
|
|
if ( ($timedOutTasks -eq $false) -or ( ($timedOutTasks -eq $true) -and ($noCloseOnTimeout -eq $false) ) ) {
|
|
Write-Verbose "Closing the runspace pool"
|
|
$runspacepool.close()
|
|
}
|
|
#collect garbage
|
|
[gc]::Collect()
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Verbose "PSBoundParameters = $($PSBoundParameters | Out-String)"
|
|
|
|
$bound = $PSBoundParameters.keys -contains "ComputerName"
|
|
if(-not $bound)
|
|
{
|
|
[System.Collections.ArrayList]$AllComputers = @()
|
|
}
|
|
}
|
|
Process
|
|
{
|
|
#Handle both pipeline and bound parameter. We don't want to stream objects, defeats purpose of parallelizing work
|
|
if($bound)
|
|
{
|
|
$AllComputers = $ComputerName
|
|
}
|
|
Else
|
|
{
|
|
foreach($Computer in $ComputerName)
|
|
{
|
|
$AllComputers.add($Computer) | Out-Null
|
|
}
|
|
}
|
|
}
|
|
End
|
|
{
|
|
#Built up the parameters and run everything in parallel
|
|
$params = @()
|
|
$splat = @{
|
|
Throttle = $Throttle
|
|
RunspaceTimeout = $Timeout
|
|
InputObject = $AllComputers
|
|
}
|
|
if($NoCloseOnTimeout)
|
|
{
|
|
$splat.add('NoCloseOnTimeout',$True)
|
|
}
|
|
|
|
Invoke-Parallel @splat -ScriptBlock {
|
|
$computer = $_.trim()
|
|
Try
|
|
{
|
|
#Pick out a few properties, add a status label. If quiet output, just return the address
|
|
$result = $null
|
|
if( $result = @( Test-Connection -ComputerName $computer -Count 2 -erroraction Stop ) )
|
|
{
|
|
$Output = $result | Select -first 1 -Property Address, IPV4Address, IPV6Address, ResponseTime, @{ label = "STATUS"; expression = {"Responding"} }
|
|
$Output.address
|
|
}
|
|
}
|
|
Catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
}
|