It’s summer. Who should work all that hard anyway? I’m letting the AutoSequencer do the work for me.
With the March 2017 release of Microsoft Windows also came the 1703 version of the Windows ADK. The ADK contains a number of tools used by both developers and IT Pros and is generally updated with each OS release. When you go to get the ADK you almost always want to get the latest version – it supports features in that release but most of the time also supports prior OS releases as well. |
The two major new items in the 1703 ADK were both App-V related, however these only work with Windows 10 1607 and Windows 16, or later, operating systems.
The first new item is the App-V Sequencer. With the App-V Client moving directly into the operating system, the ADK is now the release vehicle for the Sequencer. The primary reason that you cannot install this sequencer on Windows 7 is that it depends on some of the dlls in place for the in-box App-V client (which is present but not enabled by default).
The second new component is the App-V AutoSequencer. I wrote about the tool when it was released here but basically the AutoSequencer is a component that would be used on a Hyper-V enabled machine to control a virtual machine that has the App-V Sequencer installed. Great for that package you have to touch each month if you are an IT Pro, or for an ISV to output an App-V package right from Visual Studio. You probably don’t use the command line sequencer, but in addition to the wizard based GUI sequencer interface, the sequencer also has a command-line sequencing capability that can automatically create an App-V package from an unattended installation script. So the AutoSequencer manages the VM state, copies installers into the VM, runs the command-line sequencer and finally collects the output package.
I have been using this tool since late last fall when Microsoft made some prerelease versions available to me. Even using one of my Intel NUCs I can pump out about 6 packages per hour (assuming that I already did the work for a proper silent installation of the app). Heck, I have a set of nearly 50 apps that I can package with a single line of powershell – just enough time for a round of golf and a beer afterwards. The process I use includes two installers per package, one for dependencies and one for the main install. I use the Silent-Install open-source framework up on GitHubfor writing these unattended installations. Working with the improvement scripts output by AppV_Manage, these installations are better than from the vendor and optimized.
As the bulk of the AutoSequencer tool is PowerShell based, I have been working on my own fixes to the tool to make it more useful. Last Winter I recommended a bunch of these changes to the tool to the Microsoft App-V dev team; a couple of which made it into the 1703 release version, but there has been no word on plans for the others (Update: The Windows Insiders’ build this week included an updated ADK, and although the AutoSequencer is a new build, all of the PowerShell is identical to the 1703 version). After months of pleading with Microsoft this spring/summer to make that PowerShell open source, I am resigned to the idea that we are unlikely to see this happen.
But the AutoSequencer is a really useful tool with the fixes, so how do I make those available to you? While the PowerShell doesn’t contain a copyright notice, there is that pesky click-through license you agree to when you download the bits. So I am not comfortable in just posting the updated files. Yet if you are going to use the AutoSequencer you really want these changes. So I will post the changes here and try to make it easy for you to build your own “fixed version”. On each file below, I suggest that you edit using changes from the end of the list and work backwards — that way the line numbers I reference will work out.
There are four files to change, although as you will see many of these changes are cosmetic. After installing the AutoSequencer, you will find these files in the folder:
C:\Program Files (x86)\Windows Kits\10\Microsoft Application Virtualization\AutoSequencer
Part 1: Updates to VMSetup\Runner.ps1
WHAT IT IS:
Runner.PS1 is a powershell file that is executed within the Sequencer VM to run commands. The file is copied into the VM as part of the VM creation process and is kicked off by a windows scheduled task that triggers upon login of the sequencer user.
WHY I MODIFY IT:
1) The script assumes that the “installer” is a file that you include in the folder to be copied and that your file reference is a relative reference to that folder, so it plunks “C:\users\public\Documents\” in front of your reference. I modify this to detect a colon in the path and when detected use it as an absolute reference. Thus I can use “C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe” as the installer and give it a ps1 file as an argument.
2) The script does not allow for the use of Template files. I added in support for a template file. I did not modify the input XML syntax so you don’t have to reference the file there, but if you include a file ending in the “.appvt” file extension in the folder for the installer the script will detect and apply the template.
3) Remove the digital signature since we modified the file. (For extra credit you can sign the file with your own certificate, but I just disable the signature checking on PowerShell instead).
CHANGES:
1) On Line 19 Replace:
$installer = “$publicDocFolder\ProductInstaller\$installer” |
With:
if (!($installer -like “?:\*”) -and !($installer -like “`”?:\*`””)) { $installer = “$publicDocFolder\ProductInstaller\$installer” } |
2) On line 16, Insert:
# Check if template file is present $templatefile = Get-Item “$publicDocFolder\ProductInstaller\*.appvt” |
3) Lines 73-76 replace:
log “Start the sequencing process” $local:cmd = “New-AppvSequencerPackage -name `”$appName`” -Installer `”$installer`” -InstallerOptions `”$installerOptions`” -FullLoad -Path `”$productFolder`”” log $local:cmd Invoke-Expression “$local:cmd -ErrorVariable sequencerError” |
With:
if ($templatefile) { log “Start the sequencing process using $templatefile” $local:cmd = “New-AppvSequencerPackage -name `”$appName`” -Installer `”$installer`” -InstallerOptions `”$installerOptions`” -TemplateFilePath `”$templatefile`” -FullLoad -Path `”$productFolder`”” log $local:cmd Invoke-Expression “$local:cmd -ErrorVariable sequencerError” } else { log “Start the sequencing process” $local:cmd = “New-AppvSequencerPackage -name `”$appName`” -Installer `”$installer`” -InstallerOptions `”$installerOptions`” -FullLoad -Path `”$productFolder`”” log $local:cmd Invoke-Expression “$local:cmd -ErrorVariable sequencerError” } |
Part 2 New-AppVSequencerVM\New-AppVSequencerVM.ps1:
WHAT IT IS:
Script that is used to create the Sequencer VM.
WHY I MODIFY IT:
The changes are mostly cosmetic for debugging, but I improve some error situations and change a couple of settings on the VM for improved operations.
CHANGES:
1) Improvements to logging. Modify Line 121 Replace:
Write-Host “Failed to mount image: $VhdPath” -BackgroundColor Red |
With:
Write-Host “Failed to mount image: $VhdPath onto folder $local:UnattendXml:MountRoot” -BackgroundColor Red |
2) Improvements to logging. Insert on line 124:
else { Write-host “VHD Image mounted onto folder $local:UnattendXml:MountRoot” } |
3) Improvements to logging and error handling. On line 149 Replace:
} |
With:
Write-Host “Modified unattend written into Panther folder of mounted drive for VHD.” } else { Write-Host “Failed to create $local:UnattendXml:TargetDirectory folder: $local:DismResult” -BackgroundColor Red handleDismErrorAndStop $local:UnattendXml:MountRoot } |
4) Improvements to logging. On line 251 insert :
Write-host “VM Parameter Set detected, using an existing VM.” |
5) Improvements to logging. On line 83 Replace :
start-vm $vm |
With:
Write-host “Starting VM..” start-vm $vm Write-host “VM Started.” |
6) Improvements to logging. On line 302 insert :
Write-host “VM Session found.” |
7) Improvements to logging. On line 305 insert :
Write-host “Remote command invoked.” |
8) Improvements to logging. On line 313 insert :
Write-host “Provisioned.” |
9) Improvements to logging. On line 316 insert :
Write-host “VHD Parameter Set detected, use existing VHD to create VM.” |
10) Improvements to logging. On line 373 insert :
else { Write-host ‘VM Created.’ } |
11) Improvements to VM Settings. Use standard checkpoint types and ensure VM does not start when Hypervisor starts. On line 400 insert :
# Added this line to prevent VM from starting up automatically when the hyper-v host is rebooted. Set-VM $VMName -AutomaticStartAction Nothing -CheckpointType Standard # ————————————————————————— |
12) Improvements to logging. On line 373 insert :
Write-host “VM started.” |
13) Improvements to give a second chance to connect to console. On line 434-5, Replace:
Write-host $failedGetVMSession -BackgroundColor Red onCmdletStop |
With:
Write-host $failedGetVMSession -BackgroundColor Yellow #Try again from the top $local:vmSession = GetVmSession $VMName $local:VmComputerName ([REF]$local:cred) $false $SessionSetupTimeout $reportFilePath if (!$local:vmSession) { $failedGetVMSession = “Failed to get VM session 2nd time” LogNewAppVSequencerVMStatus -TelemetryId $telemetryId -Message $failedGetVMSession Write-host $failedGetVMSession -BackgroundColor Red onCmdletStop } |
14) Improvements to logging. On line 437 Insert:
Write-host “VM Session found.” |
15) Improvements to logging. On line 442 Insert:
Write-host “VM provisioning completed” |
16) Improvements to logging. On line 460 Insert:
Write-host “Snapshot created.” |
17) Remove Digital Signature
Part 3 New-BatchAppVSequencerPackages\New-BatchAppVSequencerPackages.ps1:
WHAT IT IS:
This script is called to start a run of autosequencing; it is run on the hypervisor.
WHY I MODIFY IT:
Most of changes are all cosmetic. They provide information on the elapsed time per-package, and it modifies the titlebar on the VM to include the name of the package being sequenced so you can more easily tell how far along you are.
The one substantive change is to revert the VM immediately after completion of a package and saving it off.
CHANGES:
1) On line 256, Replace:
Write-host “– Start sequencing $appName –“ |
With:
$start_time = Get-Date $timeout = $app.TimeoutInMinutes Write-host “– $start_time — Start sequencing $appName — “ Write-host “Timeout is set to $timeout minutes” |
2) On line 284, Replace:
Write-host “Scheduling sequencing task..” |
With:
Write-host “Scheduling the dependencies and sequencing task..” |
3) On line 341, Insert:
Update-RDSClientWindowTitle $appname $procMstsc.Id |
4) On line 348, Replace:
$ret = Invoke-Command -session $s -ScriptBlock ${function:WaitForTaskComplete} -argumentlist $timeoutInMinutes |
With:
$ret = Invoke-Command -session $s -ScriptBlock ${function:WaitForTaskComplete} -argumentlist $timeoutInMinutes, $procMstsc.Id, “$appname” |
5) On line 361 , Insert
#Give a good opportunity to explore the VM before destroying it when there is an issue.
start-sleep 600
6) On line 388 , Replace
$doneSequencing = “– Done sequencing $appName –“ LogNewBatchAppVSequencerPackagesStatus -TelemetryId $telemetryId -Message $doneSequencing Write-host $doneSequencing |
With:
$end_time = Get-Date $time_span = $end_time – $start_time $doneSequencing = “– $end_time — Done sequencing $appName — ($time_span)” LogNewBatchAppVSequencerPackagesStatus -TelemetryId $telemetryId -Message $doneSequencing Write-host $doneSequencing writeToReport $reportFilePath $doneSequencingWrite-Host “Terminating session…” closeSession $s Write-Host “Session to $VMName removed.” Write-host “Rolling back to checkpoint…” RollbackVM $VMName $VMCheckpoint Write-host “$VMName rollback to checkpoint $VMCheckpoint complete.” |
7) On line 406, Insert:
Function Update-RDSClientWindowTitle($appname, $proc_Id) { $global:timerito = New-Object System.Timers.Timer $global:timerito.Interval = 1000 $global:timerito.AutoReset = $true#write-host “before register” # Make variables global so thery are available to Action $global:proc_ID = $proc_Id $global:app_Name = $appname $global:source_identifier = Get-Random $global:UpdateCounter = 0 $xx = Register-ObjectEvent -InputObject $timerito -SourceIdentifier $global:source_identifier -EventName Elapsed -Action { #Write-host “Timerito time $($global:proc_ID)”Add-Type -TypeDefinition @” using System; using System.Runtime.InteropServices;public static class Win32 { [DllImport(“User32.dll”, EntryPoint=”SetWindowText”)] public static extern int SetWindowText(IntPtr hWnd, string strTitle); } “@# fix up window name on rdp session so we know which app is being done $process = Get-Process -Id $procId $match = “*$($global:app_Name)” $process = Get-Process -Id $global:proc_ID if ($process) { if ($process.mainWindowTitle -notlike “$($match)” ) { #Write-host “Changing window title” [Win32]::SetWindowText($process.mainWindowHandle, “$($process.mainWindowTitle) Sequencing $($global:app_Name)”) $global:UpdateCounter = $global:UpdateCounter + 1 #$timerito.Stop() #$timerito.Disose() #Unregister-Event $global:source_identifier } if ($global:UpdateCounter -ge 2) { #Write-host “Setting Window Title” #Unregister-Event $global:source_identifier #Write-host “after stop” } } } $timerito.Enabled = $true #$timerito.Start() #Write-host “after register” $tempcounter = 0 while ($tempcounter -lt 60) { Start-Sleep 1 #Write-host “sleep check” if ($global:UpdateCounter -ge 2) { $tempcounter = 60 } else { $tempcounter = $tempcounter + 1 } } $global:timerito.Stop() $global:timerito.Dispose() #Write-host “after sleeps” } |
8) Remove digital signature
Part 4 sample_config.xml:
WHAT IT IS:
This is a sample file that you edit to define your sequence packaging. The example file is INCORRECT in that is uses an element named “Name” for the package name when it should be “AppName” to match the config.xsd schema.
An optional addition…
The dependencies assume that you will have a file called “run.cmd” as the installer for the dependencies. The config.xml file only lists the folder for dependencies. It is possible to edit the schema to add a new element, the new-BatchAppvSequencingPackages.ps1, scheduler.ps1, and runner.ps1 files to support it.