param( [Parameter(Mandatory=$false)][int]$time=30 ) write-host -ForegroundColor Green " ---------------------------------------------------------------------------- ____ __. .______________ | |/ _|___________ ____ _____ ___________ | \__ ___/ | < \_ __ \__ \ _/ __ \ / \_/ __ \_ __ \ ______ | | | | | | \ | | \// __ \\ ___/| Y Y \ ___/| | \/ /_____/ | | | | |____|__ \|__| (____ /\___ >__|_| /\___ >__| |___| |____| Script: Hyper-V Reboot for SmartUpdate Version: 1.2 Datum: 04.04.2022 Abteilung Systemhaus Ersteller: Nico Krämer " <# Beschreibung: Es werden alle VMs nach Priorität (festgesetzt in CSV) heruntergefahren, dann der Hyper-V neu gestartet und anschließend alle VMs in umgekehrter Prio hochgefahren. Es werden nur VMs gestartet, die zuvor auch liefen. Änderungen an aktiven VMs werden berücksichtigt. Neue VMs werden berücksichtigt. folgende Parameter werden benötigt: $time -> Zeit, die eine VM maximal zum herunterfahren benötigen darf, bevor sie abgeschaltet wird. #>write-host -ForegroundColor green "---------------------------------------------------------------------------" #-------------------Script-------------------------- function Reboot_HV { $servers = import-csv "C:\vms.csv" #sort by priority to shutdown $servers = $servers | Sort-Object {[int]$_.prio} -Descending #Shut down VMs array $down=@() #setting up switch case ($false=shutdown,$true=start) $b = Test-Path 'HKLM:\SOFTWARE\ShutdownScript' #set max time to shutdown $t = $time*4 + 1 switch ($b) { $false { foreach ($server in $servers){ #shut down VM stop-vm -name $server.name -force #loop $t times (eq. max. $time minutes) for ($i=1; $i -le $t; $i++){ #check if vm is down, if true add it to $down, else wait 15sec and check again if ((get-vm -name $server.name).state -eq "Off"){ $down += $server.name Start-Sleep -s 2 $i = $t + 1 }else{ Start-Sleep -s 15 } } #do something, if VM is still running $time minutes after shutdown initiation if (!($down -contains $server.name)){ Stop-VM -Name $server.name -TurnOff } } #add and register scheduled task $para = "-ExecutionPolicy unrestricted -NonInteractive -WindowStyle Hidden -NoLogo -NoProfile -NoExit -File " + '"' + $file + '"' $Action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $para $Option = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -WakeToRun $Trigger = New-JobTrigger -AtStartUp -RandomDelay (New-TimeSpan -Minutes 5) Register-ScheduledTask -TaskName RebootHVResumeJob -Action $Action -Trigger $Trigger -Settings $Option -RunLevel Highest -User "System" #create regkey New-Item -Path HKLM:\SOFTWARE\ -Name ShutdownScript -Force #wait 3sec then reboot Start-Sleep -s 3 #Reboot Hyper-V $Comment = "Hyper V Reboot for Smart Updates" $reason = "P" $major = 0 $minor = 0 $Time = 1 $patchrun = "C:\Program Files (x86)\Server-Eye\triggerPatchRun.cmd" $FileToRunpath = "C:\WINDOWS\system32\shutdown.exe" $argument = '/r /t {0} /c "{1}" /d {2}:{3}:{4}' -f $Time, $Comment, $reason, $major, $minor $startProcessParams = @{ FilePath = $FileToRunpath ArgumentList = $argument NoNewWindow = $true } Start-Process $patchrun -ArgumentList "force" -Wait Start-Process @startProcessParams } $true { #sort by priority to boot $servers = $servers | Sort-Object {[int]$_.prio} #Running VMs array $up=@() foreach ($server in $servers){ #boot VM start-vm -name $server.name #loop 60 times (eq. max. 15min) for ($i=1; $i -le 61; $i++){ #check if vm is up, if true add it to $up, else wait 15sec and check again if ((get-vm -name $server.name).state -eq "Running"){ $up += $server.name $i = 61 #wait 120sec after successful boot Start-Sleep -s 120 }else{ Start-Sleep -s 15 } } } #remove regkey Remove-Item -Path HKLM:\SOFTWARE\ShutdownScript -Recurse #remove job Unregister-ScheduledTask -TaskName RebootHVResumeJob -Confirm:$False } } } function check_for_new_vm { #Import CSV $servers = import-csv "C:\vms.csv" $vmprio = 10 #names of currently active vms $cav = (Get-VM | Where-Object { $_.State -eq 'Running' }).name foreach ($vm in $servers) { if(!($cav.contains($vm.name))){ #delete not active vm from csv $servers | where-object {$_.name -NotLike $vm.name} | export-csv "C:\vms.csv" -NoTypeInformation $servers = import-csv "C:\vms.csv" } } #name of servers in $servers $servernames=@() foreach($n in $servers){$servernames += $n.name} foreach ($vm in $cav) { if(!($servernames.contains($vm))){ #add new vm to list with highest prio $NewLineVM = "{0},{1}" -f $vm,$vmprio $NewLineVM | add-content -path "C:\vms.csv" $servers = import-csv "C:\vms.csv" } } } #function to create vms.csv if not existent (does only run once)(all prios are set to 10) function create_CSV { $activevms = Get-VM | Where-Object { $_.State -eq 'Running' } New-Item C:\vms.csv -ItemType File Set-Content C:\vms.csv 'name,prio' $prio=10 foreach($activevm in $activevms) { $NewLineVM = "{0},{1}" -f $activevm.name,$prio $NewLineVM | add-content -path "C:\vms.csv" } } function replace_quotes { $result=Get-content -Path "C:\vms.csv" $result | ForEach-Object { $_-replace '"', ""} | Set-Content "C:\vms.csv" } function replace_empty_rows { $result = Get-content -Path "C:\vms.csv" $result | ForEach-Object Trim | Where-Object length -gt 0 | Set-Content "C:\vms.csv" } $file = $MyInvocation.MyCommand.Path #START if(!(Test-Path C:\vms.csv)){ create_CSV exit } if(!(Test-Path HKLM:\SOFTWARE\ShutdownScript)) { check_for_new_vm } replace_quotes replace_empty_rows Reboot_HV