Powershell - 重启并继续脚本

时间:2013-03-01 21:03:23

标签: powershell powershell-v2.0 powershell-v3.0

我正在寻找一种方法,可以在调用脚本中的重新启动后从其停止的位置继续运行Powershell脚本。例如,我通过Powershell自动化构建DC,在将PC重命名为TESTDC01之后,需要重新启动,但在重新启动后,继续使用脚本继续执行dcpromo等。

这可能吗?

干杯!

7 个答案:

答案 0 :(得分:26)

来自Hey,Scripting Guy系列的TechNet上有一篇很棒的文章介绍了与你所描述的非常相似的情况:重命名计算机并在重启后重新启动脚本。神奇之处在于使用属于版本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

来源: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" }
}

请务必记住在移动较小的脚本时适当设置状态。

答案 1 :(得分:14)

以上答案是正确的,但它仅适用于PowerShell脚本的远程执行。 根据{{​​3}},在本地计算机重新启动后从本地运行的脚本恢复的方式恢复的方式是这样的:

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。

答案 2 :(得分:5)

查看带有工作流程的PS 3.0。我还没有与他们合作,但他们假设从重新启动恢复。

答案 3 :(得分:1)

如果这有助于任何人,我的工作是重新启动服务器然后循环直到\\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"
}

答案 4 :(得分:1)

远程执行:

Rename-Computer -ComputerName $computer -NewName "TESTDC01" -DomainCredential $domain\$username -Force -Restart

然后从8开始继续执行脚本

答案 5 :(得分:0)

需要重启我的本地计算机,然后继续执行脚本。尝试了来自@adaml的解决方案,但我只是无法获得计划的作业(在重新启动后运行)来查找应该恢复的暂停的工作流作业。因此,它保持暂停状态。

Get-Job不会返回作业,无论其凭证或提升权限。 另一个奇怪的事情是,如果我通过在Powershell ISE中标记代码来运行工作流并使用F8运行该部分,则该工作永远不会被暂停...必须使用F5运行整个脚本或从其他地方调用它。

要获得工作的履历,我必须注册一个计划任务而不是计划工作:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;

public class App extends Application {

  @Override
  public void start(Stage primaryStage) {
    Rectangle rect = new Rectangle(100, 100);

    TextField field = new TextField();
    field.setOnAction(event -> {
      event.consume();
      setFillOfShape(rect, field.getText().strip());
    });

    HBox root = new HBox(25, field, rect);
    root.setPadding(new Insets(10));

    primaryStage.setScene(new Scene(root));
    primaryStage.show();
  }

  private void setFillOfShape(Shape shape, String colorName) {
    try {
      shape.setFill(Color.web(colorName));
    } catch (IllegalArgumentException ex) {
      Alert alert = new Alert(AlertType.ERROR);
      alert.initOwner(shape.getScene().getWindow());
      alert.setHeaderText(null);
      alert.setContentText("Unrecognized color: " + colorName);
      alert.showAndWait();
    }
  }
}

答案 6 :(得分:0)

为了让人们在AWS /您的Cloud Provider中这样做而受益,请大声思考...

我在AWS实例上遇到了同样的问题,需要将其重命名为客户端标准服务器名称,+域联接,+ cert安装,+触手安装。我将通过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 |哪里对象{$ .InstanceId -eq $ instanceId} $ Renamed =($ myInstance.Tags | Where-Object {$ .Key -eq“ Renamed”})。Value