Neustart einer Hyper-V VM initiieren und abwarten bis das Windows Serverbetriebssystem geladen ist.
In einem größeren Projekt wird mittels eines leicht angepassten Image Factory Script per Task wöchentlich eine mit Updates versogte Windows Server 2016 VHDX erstellt und später in einem Deployment Prozess per PowerShell weiterverarbeitet. Beim Rollout diverse VMs wird natürlich auch diverses an Software bzw. Applikationen in den VMs benötigt. Die Installation der Applikationen benötigen hin und wieder leider auch Reboots. Gewisse Schritte müssen dann auch noch auf andere Applikation oder Dienste warten. Ebenfalls passiert es ab und zu, dass ein Reboot länger verzögert bis z.B. Dienste beendet sind. Der Bootvorgang kann durchaus auch schon abgeschlossen sein und direkt erneut booten, da noch weitere Updates oder Features konfiguriert werden müssen.
Für dieses Problem gab es bereits z.B. waitForPSDirect oder auch Invoke-CommandWithPSDirect. Bei beiden Scripts kann es passieren, dass die Hyper-V VM bereits per PowerShell Direct angesprochen werden kann, obwohl noch ein weiterer Reboot aussteht. Aus diesem Grund habe ich die beiden Scripte kombiniert und ein wenig erweitert. Im Groben fährt das Script die Hyper-V VM herunter, startet diese neu, überprüft den Status des Taktes (Heartbeat) Get-VMIntegrationService und wartet bis die „winlogon.exe“ und der „Lokaler Sitzungs-Manager (LSM)“ laufen.
Wichtig: Wenn während dem Deployment die Software / Applikation in der Hyper-V VM installiert wird, diese nicht über die Installationsroutinen neu starten. Zum kontrollierten Reboot nur die PowerShell Funktion „RebootAndWaitForServer“ nutzen.
# RebootAndWaitForServer
Beispiel für die Variablen:
[string]$VMName = "SERVER-VM01"
[System.Management.Automation.PSCredential] $tempCred = new-object -typename System.Management.Automation.PSCredential ("Domain\Admin", (ConvertTo-SecureString P@ssw0rd! -AsPlainText -Force))
Oder ggfs. die Variablen abfragen:
$VMName = Read-Host "Bitte den Namen des virtuellen Computers eingeben"
$tempCred = Get-Credential
#>
function RebootAndWaitForServer {
param (
[Parameter(Mandatory=$true)]
[String]
$VMName,
[Parameter(Mandatory=$true)]
[System.Management.Automation.PSCredential]
$Credentials
)
$VM = Get-VM -Name $VMName
If ($Vm.State -eq "Running") {
Write-Host "[$($VMName)]:: Fahre Computer herunter" -ForegroundColor Yellow -NoNewline
Invoke-Command -VMName $VMName -Credential $Credentials -ScriptBlock {
Stop-Computer -Force -Confirm:$false
}
do {
Write-Host "." -ForegroundColor Yellow -NoNewline
Sleep -Seconds 5
} until ($VM.State -eq "Off")
Write-Host " -> Ok!" -ForegroundColor Yellow
}
If ($Vm.State -eq "Off") {
Write-Host "[$($VMName)]:: Starte Computer neu" -ForegroundColor Yellow -NoNewline
Start-VM -VM $VM
do {
Write-Host "." -ForegroundColor Yellow -NoNewline
Sleep -Seconds 5
$VMStatus = Get-VMIntegrationService -VM $VM | ? Id -match "84EAAE65-2F2E-45F5-9BB5-0E857DC8EB47"
} until($VMStatus.PrimaryStatusDescription.ToUpper() -eq "OK" -and $VMStatus.SecondaryStatusDescription.ToUpper() -eq "OK")
Write-Host " -> Ok!" -ForegroundColor Yellow
Write-Host "[$($VMName)]:: Warte auf Winlogon.exe und LSM Dienst" -ForegroundColor Yellow -NoNewline
Invoke-Command -VMName $VMName -Credential $Credentials -ScriptBlock {
do {
Write-Host "." -ForegroundColor Yellow -NoNewline
Sleep -Seconds 5
$Process = Get-Process | ? ProcessName -eq "winlogon" -ErrorAction SilentlyContinue
$LSM = Get-Service LSM -ErrorAction SilentlyContinue
if ($Process.ProcessName -eq "winlogon" -and $LSM.Status -eq "Running") {
$Winlogon = 1
}
else {
$Winlogon = 0
}
} until ($winlogon -eq 1)
}
}
Write-Host " -> Ok!" -ForegroundColor Yellow
}
[string]$VMName = "SERVER-VM01"
[System.Management.Automation.PSCredential] $tempCred = new-object -typename System.Management.Automation.PSCredential ("Domain\Administrator", (ConvertTo-SecureString P@ssw0rd! -AsPlainText -Force))
RebootAndWaitForServer $VMName $tempCred
Link zum Download: RebootAndWaitForServer
Schreibe einen Kommentar