0

Longish version: There are a hand full of stack exchange questions about writing a Powershell script that can tolerate a reboot mid script as well as Microsoft official blogs that are either missing information, wrong, or a thwarted by a bug.

I need to run a Powershell script in two halves; the first half installs prerequisites for the second half that require a reboot on installation. The research suggests Powershell workflows are the approach for this. This needs to be done;

  1. With zero interactive logon, so "you log on for the second half of it and type..." is not allowable as this is for an Azure custom script extension and will be run by Azure not a person
  2. Wholly contained in the machine itself (also an Azure ARM custom script extension requirement), so having a second machine using Powershell remoting and some recurring test that fails until the machine is back up, at which point it then passes, at which point more remote Powershell is hosed at the target, is not allowable

I think the author of this question https://stackoverflow.com/q/15166839/721425 was after the same thing, and the accepted answer probably works but fails point 2 above. An answer underneath, https://stackoverflow.com/a/34494197/721425 , acknowledges this and offers a solution for my question, but it doesn't work. Nor does any of the similar ones on stack exchange sites, Microsoft's Technet blog or elsewhere. They all (to various extents), rely on running the Workflow as a job, and creating a scheduled job or task to resume all suspended jobs (because after reboot the job is in Suspended state.)

I think the linked answer to the linked question doesn't work because of permissions or user account contexts.

Workflow Resume_Workflow {
# do something like install a prerequisite with a required reboot
restart-computer
# do something else after the reboot
}

$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-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

Resume_Workflow -AsJob -JobName new_resume_workflow_job

I largely think this because they set credentials they never seem to use, and when testing this and variants of it, the workflow does eventually complete but only when I log on interactively and run resume-job with the job ID.

TL;DR

How do you resume suspended jobs of Powershell workflows, with a given username and password, without having any user logged on?

UPDATE:

The following sort of works;

Step 1: Create the workflow the same as the above example, do something, reboot, do something else.

Step 2: Create a resume.ps1 that contains;

Import-Module PSWorkflow

Get-Job -State Suspended | Resume-Job -Wait| Wait-Job

And put it in the root volume or download it with SAS as a blob.

Step 3: Create a scheduled task that runs resume.ps1 AtStart

$TaskName = "ResumeWorkflows"
$Action = New-ScheduledTaskAction -Execute 
"C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe" -Argument " -executionpolicy bypass c:\resume.ps1"
$Trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName $TaskName -Action $Action -Trigger $Trigger -User "$env:Computername\Administrator" -Password "SuperS3cretP@ssword" -RunLevel Highest

Resumable_Workflow -AsJob -JobName $(get-date -Format hhmmss)

The "sort of" is if you run resume.ps1 while logged in as the user the scheduled task is created as, it works. It doesn't run as a scheduled task, so I guess I've got a scheduled task problem now instead :\

Elomis
  • 313
  • 1
  • 2
  • 12

1 Answers1

0

On your scenario, I suggest you could execute two Azure Custom Script Extension. In the script, you really no need to login your VM, the script is executed as administrator role. You could restart VM by using Azure Power Shell, no need do it in Power Shell.

###execute script 1 and install prerequisite.
Set-AzureRmVMCustomScriptExtension -ResourceGroupName myResourceGroup `
    -VMName myVM `
    -Location myLocation `
    -FileUri myURL `
    -Run 'myScript.ps1' `
    -Name DemoScriptExtension

###Restart your VM
Restart-AzureRmVM -ResourceGroupName myResourceGroup -VMName myVM

###I suggest you could wait for a minute
Start-Sleep

###execute script 2, no need uninstall script 1
Set-AzureRmVMCustomScriptExtension 
Shui shengbao
  • 3,503
  • 1
  • 10
  • 20
  • If my understanding is not right, please point me. – Shui shengbao Feb 01 '18 at 02:16
  • Need a single script, that reboots and resumes. An administrator could run two scripts using Set_AzureRmVMCustomScriptExtension but that's not really different to an administrator logging on to the machine and issuing get-job -state Suspended | resume-job. – Elomis Feb 01 '18 at 03:27
  • A script I don't think it is possible. When reboot your VM, the script exit. Maybe you could write a script, wait for a moment, judge your prerequisite. if it is done. don't restart your VM and execute following commands. – Shui shengbao Feb 01 '18 at 04:20
  • Hi, any update about this? – Shui shengbao Feb 02 '18 at 02:05
  • Can you write a script that is simply idempotent? Idempotency is a fancy word for being able to start over from the beginning, recognizes what's already been done, and continues where it left off. You can first check if the pre-requisites are already installed, and if so skip that part the next time around. You can also save off when you installed them, and compare the last time the OS was rebooted to that timestamp. This can let you build a very lightweight resume without the overhead of workflow. See also: https://stackoverflow.com/questions/1077412/what-is-an-idempotent-operation – Matthew Wetmore Feb 03 '18 at 05:43
  • Idempotency is also the power behind `DSC` resources with a `get`, `test`, `set` pattern. Get the current values, test if they're in the desired state, and if not, set them. You can run this over and over, as often as necessary. You may also be able to use DSC, as there are resources for installing software, rebooting, and a variety of other operations. It's built for exactly this sort of thing. – Matthew Wetmore Feb 03 '18 at 05:49