Powershell – Resumable Powershell Workflow, Run On the Machine That Resumes It

azureazure-powershellpowershell

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 :\

Best Answer

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