function Wait-ServersAreReachable { <# .Synopsis Waits on the list of $Servers to become reachable by WinRM with a timeout. .Parameter Servers The servers to connect to and wait for. .Parameter TimeoutMinutes The number of minutes to wait until this function times out. .Parameter RetryDelaySeconds The number of seconds to wait between WinRM connection test attempts. #> Param ( [Parameter(Mandatory = $true)] [string[]]$Servers, [Parameter(Mandatory = $false)] [int]$TimeoutMinutes = 10, [Parameter(Mandatory = $false)] [int]$RetryDelaySeconds = 5 ) $logLead = (Get-LogLeadName) # if there are no servers to wake up, skip it! if(Test-IsCollectionNullOrEmpty $Servers) { Write-Host "$logLead : No servers to act on. Skipping.." return } $csvServers = $Servers -join ", " Write-Host "$logLead : Waiting on Servers to Become Reachable: $csvServers" # Create counters to track how many servers have been reached, and start the timer. $connectCount = 0 $totalConnected = 0 $serverCount = $Servers.Count $stopWatch = [System.Diagnostics.Stopwatch]::StartNew() # Assign Servers to a ServerList, which we will whittle down as servers become reachable. $serversNotConnectedTo = $Servers Write-Host "$logLead : Attempting to connect to all servers. Will retry to connect for $TimeoutMinutes minutes for any that can't connect." while($connectCount -lt $serverCount) { $hostResults = Invoke-Parallel -objects $serversNotConnectedTo -returnObjects -numThreads 32 -script { param($server) $session = $null $logLead = "[Wait-ServersAreReachable]" try { $so = New-PSSessionOption -OpenTimeout 10000 -CancelTimeout 30000 -OperationTimeout 30000 -MaxConnectionRetryCount 1 $session = New-PSSession $server -ErrorAction SilentlyContinue -SessionOption $so $success = (1 -eq (Invoke-Command -Session $session -ErrorAction Stop -ScriptBlock { return 1 })) if($success) { Write-Host "$logLead : Connected successfully to $server" return @{"y" = $server} # Single Hashtable added as an item in array $hostResults } else { # Write-Verbose instead of Write-Host to reduce chattiness. The servers that are failing are written out in the end. Write-Verbose "$logLead : Could not connect to $server" return @{"n" = $server} # Single Hashtable added as an item in array $hostResults } } catch { Write-Verbose "$logLead : Error connecting to $server" return @{"n" = $server} # Single Hashtable added as an item in array $hostResults } finally { if($null -ne $session) { Remove-PSSession $session } } } # Get count of servers we can connect to. Array of Hashtables, filtered on the Keys, value = server name $connectCount = ( ($hostResults | Where-Object{$_.Keys -eq "y"}).Values ).Count $totalConnected += $connectCount # Replace $serversNotConnectedTo with the remaining servers that are failing, so that we do not re-test good servers. $serversNotConnectedTo = ($hostResults | Where-Object{$_.Keys -eq "n"}).Values Write-Verbose "$logLead : connectCount = $connectCount" Write-Verbose "$logLead : totalConnected = $totalConnected" Write-Verbose "$logLead : serverCount = $serverCount" if(([int]$stopWatch.Elapsed.TotalMinutes) -ge $TimeoutMinutes) { Write-Warning "$logLead : Exceeded timeout of $TimeoutMinutes minutes. Exiting." break } if($totalConnected -lt $serverCount) { Write-Host "$logLead : Connected to $totalConnected out of $serverCount servers. Sleeping $RetryDelaySeconds seconds." Start-Sleep -Seconds $RetryDelaySeconds } else { Write-Host "$logLead : Successfully connected to all servers." break } } if($totalConnected -lt $serverCount) { throw "$logLead : Couldn't connect to all servers in alloted time of $TimeoutMinutes minutes.`nCouldn't connect to: $serversNotConnectedTo " } }