restart-computer with logs or result

65 views Asked by At

I need to restart 5 or 6 computers at the same time. It works nice with the command restart-computer. But I want to add -wait to be sure each server has restarted.

So, of course, I can do something like this:

foreach ($VMs in $Servers){
    restart-computer $Servers -force -wait
    Write-Output "$vms has been rebooted"
}

I tried with -asjob, but I don't really understand how it works and how I can have a result. Also, it means I can't use -wait anymore.

Is there a way to export the result of restart-computer to a log or an array?
How can I know if one of the server could not restart, and will the script will continue to run if it's the case?

2

There are 2 answers

3
sirtao On BEST ANSWER

Restart-Computer gives no output of its own.
That said, you can simply do something like

# Creates string list to collect the logs
$RestartLog = [System.Collections.Generic.List[object]]@()

foreach ($VM in $VMList) {
    # restarts $VM, by force, waits for Powershell to be available, checks every 2 seconds for a total of 300 seconds(5minutes) 
    # if you do not set -Timeout, it will wait forever
    # if the computer doesn't answer before the Timeout is reached, the command goes on.
    Restart-Computer $VM -Force -Wait -For PowerShell -Timeout 300 -Delay 2 -WhatIf

    # Prepares Log line
    $RestartLine = 'Computer {0} has been restarted at {1}' -f $VM, (Get-Date)

    # add string to list
    $RestartLog.Add($RestartLine)

    # optional: write it to the screen
    Write-Host $RestartLine
}

# append list to log file
$RestartLog | Out-File -FilePath $FileLog -Append
1
Dennis On

If only working with Windows PowerShell 5.1, you can speed up the solution provided by @sirtao by using jobs.

In PWSH 7.x just use Start-ThreadJob instead to trim it down even further.
With big jobs, parallel piping as suggested by @sirtao is even better than foreach.

$VMList = 'Server1','Server2' #etc.
$FileLog = $ENV:ProgramData\Reboot.log #replace with your path
$RestartLog = @()

Get-Job | Remove-Job -Force # Remove any pending jobs from before

foreach ($VM in $VMList) {
  Start-Job {# Reboot each VM and check every 2 secs for 5 min using PowerShell
    Restart-Computer $Using:VM -Force -Wait -For PowerShell -Timeout 300 -Delay 2

    return 'Computer {0} has been restarted at {1}' -f $Using:VM, (Get-Date)
  }
}

foreach ($RebootJob in Get-Job) {# Wait for each VM to reboot and collect the result
  $Message = Receive-Job $RebootJob -AutoRemoveJob -Wait
  
  $RestartLog += $Message
  Write-Output $Message
}

$RestartLog | Out-File -FilePath $FileLog -Append

Note: I only use += for increased code readability. It actually rebuilds the array completely each time which is a bad practice if working with large data sets.

See Why should I avoid using the increase assignment operator (+=) to create a collection