Hi Bnrtech,
In addition, I found this function, which can help us to Gracefully Restart Virtual Machines on Hyper-V, please note I haven't tested:
function Restart-VM {
<#
.SYNOPSIS
Restarts one or more virtual machines by performing an orderly shutdown and startup sequence.
.DESCRIPTION
Restarts one or more virtual machines by performing an orderly shutdown and startup sequence.
Shadows the built-in Restart-VM, which does not contain the same functionality.
.PARAMETER Name
A string array containing the name(s) of the virtual machine to restart.
.PARAMETER ComputerName
The name(s) of the computer(s) that host(s) the target virtual machine(s). If not specified, the local host will be used.
.PARAMETER AsJob
Places the restart operation in a job and returns immediately.
Cannot be included with Passthru.
.PARAMETER Force
If the virtual machine is not running integration services, or if the integration services do not respond promptly, performs a Turn Off operation.
If not specified, only virtual machines with responding integration services will be restarted.
.PARAMETER VM
The virtual machine object to be restarted.
.PARAMETER Timeout
Maximum number of seconds to wait for the target system to shut down gracefully before performing a Turn Off operation. Default is eternity.
If multiple virtual machines are specified, each has its own separate timer.
.PARAMETER ForceTimeout
Number of seconds to wait for a forced turn off to work before assuming the worker process is hung. Default and minimum is 5 seconds.
If multiple virtual machines are specified, each has its own separate timer.
Has no effect if Force is not also specified.
.PARAMETER Passthru
Causes the script to emit a virtual machine object that represents the VM that was restarted.
Cannot be included with AsJob.
.OUTPUTS
None by default.
If -Passthru is specified, Microsoft.HyperV.PowerShell.VirtualMachine.
If -AsJob is specified, System.Management.Automation.PSRemotingJob.
.NOTES
Author: Eric Siron
Copyright: (C) 2014 Altaro Software
Version 1.0.1
Authored Date: November 15, 2014
1.0.1 revision: November 26, 2014: Minor fix to timeout logic.
.LINK
http://www.altaro.com/hyper-v/free-script-restart-vm/
.EXAMPLE
C:\PS> Restart-VM svtest
Description
-----------
Restarts the virtual machine named test on the local host.
.EXAMPLE
C:\PS> Restart-VM svhungsystem -Force
Description
-----------
Restarts the virtual machine named svhungsystem on the local host even if it is not responding.
.EXAMPLE
C:\PS> Get-VM -Name svtrouble | Restart-VM -Force -ForceTimeout 30
Description
-----------
Forces the virtual machine named svtrouble to shut down, but extends the maximum wait time from 5 seconds to 30 seconds.
.EXAMPLE
C:\PS> Restart-VM svserver1, svserver2 -ComputerName svhv1 -Timeout 60
Description
-----------
Restarts VMs named svserver1 and svserver2 on Hyper-V host svhv1. If either does not shut down within 60 seconds, it is forcefully turned off.
.EXAMPLE
C:\PS> Get-ClusterVM | Restart-VM
Description
-----------
Using the output of Get-ClusterVM (another free script from Altaro), restarts all cluster VMs.
#>
[CmdletBinding(DefaultParameterSetName='ByName', SupportsShouldProcess=$true)]
param(
[Alias("VMName")]
[Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByName', Mandatory=$true, Position=1)]
[String[]]$Name,
[Alias("VMHost")]
[Parameter(ValueFromPipelineByPropertyName=$true, Position=2, ParameterSetName='ByName')]
[String[]]$ComputerName = @(, $env:COMPUTERNAME),
[Parameter(ValueFromPipelineByPropertyName=$true)]
[Switch]$AsJob,
[Parameter(ValueFromPipelineByPropertyName=$true)]
[Switch]$Force,
[Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='ByVM')]
[Microsoft.HyperV.PowerShell.VirtualMachine[]]$VM,
[Parameter(ValueFromPipelineByPropertyName=$true)]
[UInt32]$Timeout = 0,
[Parameter(ValueFromPipelineByPropertyName=$true)]
[UInt32]$ForceTimeout = 5,
[Parameter(ValueFromPipelineByPropertyName=$true)]
[Switch]$Passthru
)
BEGIN {
### Globals ###
$JobList = @()
### Script blocks ###
$RestartScript = {
param(
[Parameter(Position=1)][Object]$VMObject, # deserialized and cannot be used as a VM object
[Parameter(Position=2)][UInt32]$Timeout,
[Parameter(Position=3)][UInt32]$ForceTimeout,
[Parameter(Position=4)][Switch]$Force,
[Parameter(Position=5)][Switch]$Passthru
)
### Constants ###
New-Variable -Name VMStateRunning -Value 2 -Option Constant
New-Variable -Name VMStateTurnedOff -Value 3 -Option Constant
New-Variable -Name MinimumForceTimeout -Value 5 -Option Constant
### Functions ###
function TurnOff {
param(
[Parameter()][Object]$VMObject, # deserialized and cannot be used as a VM object
[Parameter()][UInt32]$Timeout,
[Parameter()][ValidateSet("Shutdown", "TurnOff")][String]$Mode
)
switch($Mode)
{
"Shutdown" {
Stop-VM -ComputerName $VMObject.ComputerName -Name $VMObject.Name -Force
}
"TurnOff" {
Stop-VM -ComputerName $VMObject.ComputerName -Name $VMObject.Name -Force -TurnOff
}
}
$TimeoutCounter = 0
$Continue = $true
while($Continue)
{
Start-Sleep -Seconds 1
$Continue = ((Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -ComputerName $VMObject.ComputerName -Filter "Name = '$($VMObject.VMId.Guid.ToString().ToUpper())'").EnabledState -ne $VMStateTurnedOff)
if($Timeout -and $Continue)
{
$TimeoutCounter++
if($TimeoutCounter -ge $Timeout)
{
$false
return
}
}
}
$true
}
if($ForceTimeout -lt $MinimumForceTimeout) { $ForceTimeout = $MinimumForceTimeout }
$ForceRequired = $true # this will be set off if a graceful shutdown is successful
$StopAttempted = $false
# output from get-vm isn't always reliable, ask WMI if the VM is on
if((Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -ComputerName $VMObject.ComputerName -Filter "Name = '$($VMObject.VMId.Guid.ToString().ToUpper())'").EnabledState -eq $VMStateRunning)
{
# The VM is on. Check for the shutdown integration service.
$ShutdownIntegrationStatus = Get-VMIntegrationService -Name "Shutdown" -ComputerName $VMObject.ComputerName -VMName $VMObject.VMName
if($ShutdownIntegrationStatus.Enabled)
{
if($ShutdownIntegrationStatus.PrimaryOperationalStatus -eq "Ok")
{
$StopAttempted = $true
if(TurnOff -VMObject $VMObject -Timeout $Timeout -Mode "Shutdown")
{
$ForceRequired = $false
}
else
{
Write-Warning "Graceful shutdown for $($VMObject.Name) was unsuccessful."
}
}
}
if($Force -and $ForceRequired)
{
$StopAttempted = $true
Write-Verbose -Message "Attempting to turn off (hard shut down) $($VMObject.VMName) on $($VMObject.ComputerName)"
if(-not(TurnOff -VMObject $VMObject -Timeout $ForceTimeout -Mode "TurnOff"))
{
Write-Warning -Message "Unable to turn off $($VMObject.VMName)"
}
}
if($ForceRequired -and -not $Force)
{
Write-Warning -Message "VM $($VMObject.VMName) can only be restarted with the -Force switch"
}
# start the VM if the script tried to turn it off and its status is off
if((Get-WmiObject -Namespace root\virtualization\v2 -Class Msvm_ComputerSystem -ComputerName $VMObject.ComputerName -Filter "Name = '$($VMObject.VMId.Guid.ToString().ToUpper())'").EnabledState -eq $VMStateTurnedOff)
{
Start-VM -ComputerName $VMObject.ComputerName -Name $VMObject.Name
if($Passthru)
{
# just passing the object back will return a deserialized object. allow the calling thread to retrieve the object
[String]::Join(",", ($VMObject.Computername, $VMObject.Name))
}
}
elseif($StopAttempted)
{
Write-Error "VM $($VMObject.Name) cannot be started because it was not successfully turned off"
}
}
}
}
PROCESS {
if($Name -eq $null -and $VM -eq $null)
{
throw("Must select at least one virtual machine to restart.")
}
if($AsJob -and $Passthru)
{
throw("AsJob and Passthru cannot be specified together")
}
# if submitted by VM object, use as-is. otherwise retrieve VM objects
if(-not $VM.Count)
{
$VM = @()
}
foreach($VMHost in $ComputerName)
{
foreach($VMName in $Name) # $Name is the input parameter for virtual machine name(s)
{
try
{
Write-Verbose -Message "Checking for $VMName on $VMHost"
$VM += Get-VM -ComputerName $VMHost -Name $VMName -ErrorAction Stop
}
catch
{
Write-Verbose -Message "No VM with the name $VMName is present on host $VMHost"
}
}
}
foreach($VMObject in $VM)
{
Write-Verbose -Message "Performing restart of $($VMObject.Name) on $($VMObject.ComputerName)"
if($PSCmdlet.ShouldProcess("$($VMObject.Name) on $($VMObject.ComputerName)", "Restart"))
{
$JobList += Start-Job -ScriptBlock $RestartScript -Name "Restart-VM-$($VMObject.ComputerName)-$($VMObject.Name)-$($VMObject.VMId)" -ArgumentList $VMObject, $Timeout, $ForceTimeout, $Force, $Passthru
}
}
}
END {
if($JobList)
{
if($AsJob)
{
$JobList
}
else
{
$ResultsArray = @()
Wait-Job -Job $JobList | Out-Null
foreach($Job in $JobList)
{
$ResultsArray += Receive-Job -Job $Job
}
$JobList | Remove-Job
if($Passthru)
{
foreach($Result in $ResultsArray)
{
try
{
$VMItem = $Result.Split(",")
Get-VM -ComputerName $VMItem[0] -Name $VMItem[1] -ErrorAction Stop
}
catch
{
; # really nothing to do about it
}
}
}
else
{
$ResultsArray
}
}
}
}
}
Refer to:
http://www.altaro.com/hyper-v/free-script-restart-virtual-machines-hyper-v/
If there is anything else regarding this issue, please feel free to post back.
Best Regards,
Anna Wang