Powershell - перезагрузка и продолжение скрипта
Я ищу способ продолжить сценарий Powershell с того места, где он остановился после вызова перезагрузки в сценарии. Например, я создаю DC с помощью автоматизации Powershell, и после переименования ПК в TESTDC01 необходимо перезагрузить компьютер, но после перезагрузки продолжите работу со сценарием, чтобы перейти к dcpromo и т. Д.
Это возможно?
Ура!
4 ответа
На TechNet есть отличная статья из серии Hey, Scripting Guy, в которой рассказывается о ситуации, очень похожей на ту, которую вы описываете: переименование компьютера и возобновление работы сценария после перезагрузки. Волшебство заключается в использовании новых рабочих процессов, которые являются частью версии 3:
workflow Rename-And-Reboot {
param ([string]$Name)
Rename-Computer -NewName $Name -Force -Passthru
Restart-Computer -Wait
Do-MoreStuff
}
После того, как рабочий процесс был объявлен (вы не назначаете его переменной), вы можете вызвать его, как если бы это был обычный командлет. Настоящая магия -Wait
параметр командлета Restart-Computer.
Rename-And-Reboot PowerShellWorkflows
Если PowerShell v3 или более поздней версии недоступен, вы можете разбить существующий сценарий на несколько меньших сценариев и получить мастер-сценарий, который запускается при запуске, проверяет где-то сохраненное состояние (файл, реестр и т. Д.), А затем начинает выполнение новый сценарий, чтобы продолжить там, где это необходимо. Что-то вроде:
$state = Get-MyCoolPersistedState
switch ($state) {
"Stage1" { . \Path\To\Stage1.ps1 ; break }
"Stage2" { . \Path\To\Stage2.ps1 ; break }
"Stage3" { . \Path\To\Stage3.ps1 ; break }
default { "Uh, something unexpected happened" }
}
Просто не забудьте правильно установить свое состояние при переходе по более мелким сценариям.
Приведенный выше ответ верен, но он будет применяться только к удаленному выполнению сценариев powershell. Согласно веб-порталу Windows, способ возобновления работы локально выполняемого сценария с того места, на котором он остановился после перезапуска локальной машины, выглядит следующим образом:
workflow Resume_Workflow
{
.....
Rename-Computer -NewName some_name -Force -Passthru
Restart-Computer -Wait
# Do some stuff
.....
}
# Create the scheduled job properties
$options = New-ScheduledJobOption -RunElevated -ContinueIfGoingOnBattery -StartIfOnBattery
$secpasswd = ConvertTo-SecureString "Aa123456!" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ("WELCOME\Administrator", $secpasswd)
$AtStartup = New-JobTrigger -AtStartup
# Register the scheduled job
Register-ScheduledJob -Name Resume_Workflow_Job -Trigger $AtStartup -ScriptBlock ({[System.Management.Automation.Remoting.PSSessionConfigurationData]::IsServerManager = $true; Import-Module PSWorkflow; Resume-Job -Name new_resume_workflow_job -Wait}) -ScheduledJobOption $options
# Execute the workflow as a new job
Resume_Workflow -AsJob -JobName new_resume_workflow_job
Обратите внимание, что [System.Management.Automation.Remoting.PSSessionConfigurationData]::IsServerManager
Флаг должен быть установлен в true, только если действия рабочего процесса должны выполняться локально после перезапуска.
Проверьте PS 3.0 с рабочими процессами. Я еще не работал с ними, но они должны восстановиться после перезагрузки.
Если это кому-нибудь поможет, я перезагружаю сервер \\server\c$
отключается Следующий цикл While (-not(Test-path "\\$server\c$"))
чтобы подтвердить, что сервер снова подключен и просто продолжите мой сценарий.
Этот код работает, но определенно может быть улучшен. Он генерирует журнал CSV перезагружаемых серверов. Он также должен работать в PowerShell v2 и новее.
Param([Parameter(Mandatory=$true)][string]$server)
$ErrorActionPreference = "SilentlyContinue"
Try{
$LastReboot = Get-EventLog -ComputerName $server -LogName system | Where-Object {$_.EventID -eq '6005'} | Select -ExpandProperty TimeGenerated | select -first 1
(Invoke-WmiMethod -ComputerName $server -Path "Win32_Service.Name='HealthService'" -Name PauseService).ReturnValue | Out-Null
Restart-Computer -ComputerName $server -Force
#New loop with counter, exit script if server did not reboot.
$max = 20;$i = 0
DO{
IF($i -gt $max){
$hash = @{
"Server" = $server
"Status" = "FailedToReboot!"
"LastRebootTime" = "$LastReboot"
"CurrentRebootTime" = "FailedToReboot!"
}
$newRow = New-Object PsObject -Property $hash
$rnd = Get-Random -Minimum 5 -Maximum 40
Start-Sleep -Seconds $rnd
Export-Csv D:\RebootResults.csv -InputObject $newrow -Append -Force
"Failed to reboot $server"
exit}#exit script and log failed to reboot.
$i++
"Wait for server to reboot"
Start-Sleep -Seconds 15
}#end DO
While (Test-path "\\$server\c$")
$max = 20;$i = 0
DO{
IF($i -gt $max){
$hash = @{
"Server" = $server
"Status" = "FailedToComeOnline!"
"LastRebootTime" = "$LastReboot"
"CurrentRebootTime" = "FailedToReboot!"
}
$newRow = New-Object PsObject -Property $hash
$rnd = Get-Random -Minimum 5 -Maximum 40
Start-Sleep -Seconds $rnd
Export-Csv D:\RebootResults.csv -InputObject $newrow -Append -Force
"$server did not come online"
exit}#exit script and log failed to come online.
$i++
"Wait for [$server] to come online"
Start-Sleep -Seconds 15
}#end DO
While (-not(Test-path "\\$server\c$"))
$CurrentReboot = Get-EventLog -ComputerName $server -LogName system | Where-Object {$_.EventID -eq '6005'} | Select -ExpandProperty TimeGenerated | select -first 1
$hash = @{
"Server" = $server
"Status" = "RebootSuccessful"
"LastRebootTime" = $LastReboot
"CurrentRebootTime" = "$CurrentReboot"
}
$newRow = New-Object PsObject -Property $hash
$rnd = Get-Random -Minimum 5 -Maximum 40
Start-Sleep -Seconds $rnd
Export-Csv D:\RebootResults.csv -InputObject $newrow -Append -Force
}#End Try.
Catch{
$errMsg = $_.Exception
"Failed with $errMsg"
}
Требуется перезагрузить мой локальный компьютер и продолжить сценарий после этого. Пробовал решение от @adaml, но я просто не мог получить запланированное задание (которое выполнялось после перезагрузки), чтобы найти приостановленное задание рабочего процесса, которое должно быть возобновлено. Следовательно, он остался приостановленным.
Get-Job не вернул работу ни с учетными данными, ни с повышенными правами. Еще одна странность заключалась в том, что если я запустил рабочий процесс, пометив код в Powershell ISE и запустил раздел с помощью F8, задание никогда не было приостановлено... Приходилось запускать весь сценарий с помощью F5 или вызывать его из другого места.
Чтобы возобновить работу, мне пришлось зарегистрировать запланированное задание вместо запланированного задания:
workflow test-restart {
Write-Output "Before reboot" | Out-File C:/Log/t.txt -Append
Restart-Computer -Wait
Write-Output "$Now2 After reboot" | Out-File C:/Log/t.txt -Append
}
$PSPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$Args = '-NonInteractive -WindowStyle Hidden -NoLogo -NoProfile -NoExit -Command "& {Import-Module PSWorkflow ; Get-Job | Resume-Job}"'
$Action = New-ScheduledTaskAction -Execute $PSPath -Argument $Args
$Option = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -WakeToRun
$Trigger = New-JobTrigger -AtStartUp -RandomDelay (New-TimeSpan -Minutes 5)
Register-ScheduledTask -TaskName ResumeJob -Action $Action -Trigger $Trigger -Settings $Option -RunLevel Highest
test-restart -AsJob
Do it remotely:
Rename-Computer -ComputerName $computer -NewName "TESTDC01" -DomainCredential $domain\$username -Force -Restart
And continue your script from that 8)
Мысли вслух, чтобы люди делали это в AWS/Your Cloud Provider...
У меня такая же проблема с экземплярами AWS, которые нужно будет переименовать в стандартное имя сервера клиента, + присоединение к домену, + установка сертификата, + установка Tentacle. Я собираюсь поместить сценарий запуска сервера в поле user_data экземпляра через Terraform.
Я установлю теги "Переименованные" экземпляра EC2 в PS на экземпляре после каждой части настройки, поэтому при перезапуске сервера после переименования сценарий будет искать значение тега IF "Renamed = Done" и пропустить эту часть в следующей время загрузки экземпляра. Такая же логика для тегов DomainJoined, TentacleInstalled и т. Д.
Код для чтения тегов выглядит так:
$instanceId = (Invoke-RestMethod -Method Get -Uri http://169.254.169.254/latest/meta-data/instance-id)
$instance = ((Get-EC2Instance -region $region -Instance $instanceId).RunningInstance)
$myInstance = $instance | Where-Object { $_.InstanceId -eq $instanceId }
$Renamed = ($myInstance.Tags | Where-Object { $_.Key -eq "Renamed" }).Value