I have large list of PC numbers (around 2000 -) I have a query with the following command:
$Computers = get-content = "C:\Users\Public\Documents\CSV\tfiles\Computernames.txt"
foreach ($Computer in $Computers) {
query user /server:$Computer
}
I'm wondering if I can speed up this process by skipping the command if there is no result from a pc name after 2seconds..
Other, faster methods are also welcome.
CodePudding user response:
You can start a background job and wait for it only for 2 seconds:
$Computers = Get-Content "C:\Users\Public\Documents\CSV\tfiles\Computernames.txt"
foreach ($Computer in $Computers) {
Start-Job { query user /server:$using:Computer } |Wait-Job -Timeout 2 |Receive-Job
}
If the job completes within 2 seconds, Receive-Job
will unpack and output the query results. If the job doesn't complete within the timeout, then Receive-Job
doesn't receive any input and the loop continues as normal.
For more information about PowerShell Jobs, see the about_Jobs
help topic
CodePudding user response:
Re finding a faster method, let me complement Mathias R. Jessen's helpful answer with a PowerShell (Core) 7 solution that uses parallel execution via ForEach-Object
-Parallel
, combined with -AsJob
:
$computers = Get-Content C:\Users\Public\Documents\CSV\tfiles\Computernames.txt
# Specify how many threads may run in parallel simultaneously,
# 5 by default.
# For network-based operations, increasing that limit,
# via -ThrottleLimit, may make sense.
# For local operations, a limit that exceeds the number of CPU cores
# may decrease performance.
$maxParallelThreads = 10
# Start the parallel threads asynchronously and return them as a job.
$job =
$computers |
ForEach-Object -AsJob -ThrottleLimit $maxParallelThreads -Parallel {
[pscustomobject] @{
Computer = $_
Result = query user /server:$_
}
}
# Receive job output in a polling loop, and terminate child jobs
# that have run too long.
do {
Start-Sleep -Milliseconds 500 # Sleep a little; adjust as needed.
# Get pending results.
$job | Receive-Job
# If any child jobs have been running for more than 2 seconds,
# stop (terminate) them.
# This will open up slots for more threads to spin up.
foreach ($childJob in $job.ChildJobs.Where({ $_.State -eq 'Running' })) {
if (([datetime]::now - $childJob.PSBeginTime).TotalSeconds -ge 2) {
# Derive the target computer from the child job ID
$targetComputer = $computers[$childJob.Id - $job.Id - 1]
Write-Verbose -Verbose "Stopping job for computer '$targetComputer' due to running longer than 2 seconds..."
$childJob | Stop-Job
}
}
} while ($job.ChildJobs.Where({ $_.State -in 'NotStarted', 'Running' }))
# Clean up.
$job | Remove-Job -Force