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

Источник: http://blogs.technet.com/b/heyscriptingguy/archive/2013/01/23/powershell-workflows-restarting-the-computer.aspx

Если 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
Другие вопросы по тегам