![](/img/trans.png)
[英]Continue powershell script execution even if a reboot is encountered
[英]Powershell - Reboot and Continue Script
我正在寻找一种方法来在脚本中调用重启后从它停止的地方继续一个 Powershell 脚本。 例如,我正在通过 Powershell 自动化构建 DC,在将 PC 重命名为 TESTDC01 后,需要重新启动,但在重新启动后,继续执行脚本以继续执行 dcpromo 等。
这可能吗?
干杯!
TechNet 上有一篇很棒的文章,来自 Hey, Scripting Guy 系列,其中讨论了与您所描述的情况非常相似的情况:重命名计算机并在重新启动后恢复脚本。 神奇的是使用作为版本 3 一部分的新工作流程:
workflow Rename-And-Reboot {
param ([string]$Name)
Rename-Computer -NewName $Name -Force -Passthru
Restart-Computer -Wait
Do-MoreStuff
}
一旦声明了工作流(您不将其分配给变量),您就可以像调用常规 cmdlet 一样调用它。 真正的魔法是 Restart-Computer cmdlet 上的-Wait
参数。
Rename-And-Reboot PowerShellWorkflows
来源: https : //devblogs.microsoft.com/scripting/powershell-workflows-restarting-the-computer/
如果 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 web portal ,在本地机器重新启动后,让本地运行的脚本从它停止的地方恢复的方法如下:
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"
}
远程操作:
Rename-Computer -ComputerName $computer -NewName "TESTDC01" -DomainCredential $domain\$username -Force -Restart
然后继续你的脚本 8)
需要重新启动我的本地计算机并在之后继续脚本。 尝试了@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
大声思考,为了在 AWS/您的云提供商中这样做的人的利益......
我在 AWS 实例上遇到了同样的问题,需要重命名为客户端标准服务器名称、+domain join、+cert install、+Tentacle install。 我将通过 Terraform 将服务器启动脚本放入实例的 user_data 字段中。
我将在实例上的 PS 中设置 EC2 实例“重命名”标签,在设置的每个部分之后,因此当重命名后服务器重新启动时,脚本将查找 IF“重命名 = 完成”标签值,然后跳过这部分实例启动的时间。 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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.