Reputation: 53
I'm writing a PowerShell-Script that reads all shares from all AD-Servers and outputs them into a csv-file. At the same time the script is saving all occuring errors and outputs them into an error-log. The script will be run as a weekly task. When I run the script, all goes well until it gets to a server that has frozen. In that case, the script will just run forever because it gets no answer from the server.
Now I need to add some sort of timeout that skips a server after it doesn't recieve an answer for a specific amount of time. How would I do that with my existing code?
My Code:
$computers = (Get-Content C:\PowerShell\Shares\serverlist.txt).ForEach({
if(-not [string]::IsNullOrWhiteSpace($_))
{
"$_.domain.com"
}
})
$remoteCode = {
Get-SmbShare | Where-Object Path | Get-Acl |
Select-Object -Property "PSChildName", "Path", "Group", "AccessToString"
}
$results = Invoke-Command -ComputerName $computers -ScriptBlock $remoteCode 2>&1
$errors, $good = $results.Where({$_ -is [System.Management.Automation.ErrorRecord]}, 'Split')
$good | Sort-Object PSComputerName | Select-Object "PSComputerName", "PSChildName", "Path", "Group", @{ Name = "AccessToString"; Expression = { $_.AccessToString -replace("268435456", "FullControl") -replace("-1610612736", "ReadAndExecute")}} | export-csv -path C:\PowerShell\Shares\shares.csv -NoTypeInformation -delimiter ";"
$errors.Exception.Message | Set-Content $error_logfile -Encoding Unicode
Upvotes: 4
Views: 1765
Reputation: 60145
NOTE: This answer is pretty much useless, in an ideal world, -OperationTimeout
would do what it's name implies, however, as the helpful comment from mklement0 states:
Unfortunately, the OperationTimeout session option doesn't do what its name suggests: see GitHub issue #15696. Implementing an actual operation-duration timeout is the subject of GitHub proposal #5434, which suggest adding a
-Timeout
parameter toInvoke-Command
.
If you feel this would be a great implementation for future versions of PowerShell, consider up-voting his proposal!
You could use PSSessionOption
with a Operation Timeout and Open Timeout below the default values (3 minutes):
See the Parameter section of New-PSSessionOption
documentation:
-OpenTimeout
Determines how long the client computer waits for the session connection to be established. When the interval expires, the command to establish the connection fails.
-OperationTimeout
Determines the maximum time WinRM waits for positive connection tests from a live connection before initiating a connection time-out.
$timeOut = 30000 # => 30 seconds
$psso = New-PSSessionOption -OpenTimeout $timeOut -OperationTimeout $timeOut
$session = (Get-Content C:\PowerShell\Shares\serverlist.txt).ForEach({
if(-not [string]::IsNullOrWhiteSpace($_)) {
try {
New-PSSession -ComputerName "$_.domain.com" -SessionOption $psso
}
catch {
Write-Warning $_.Exception.Message
}
}
})
Then the rest of the script is the same, except for the use of -Session
instead -ComputerName
for Invoke-Command
:
$results = Invoke-Command -Session $session -ScriptBlock $remoteCode 2>&1
And lastly, after you're done with the remote connections, you would need to remove the PSSessions:
Remove-PSSession $session
Upvotes: 4