How to continue with an installation after reboot?

Written by Alex Marin · May 8th, 2020

Although it’s a rare scenario - you might run into the situation where you need to continue the installation of a certain application after reboot. We are talking about a silent installation that doesn't require admin rights or any input from the user.

The situation typically develops when you uninstall a previous version of an application and want to install a new one.

The issue is that some folders are still in use and need to be deleted, and the only way to remove them is to actually reboot the machine, or the application itself forces the reboot.

Infrastructure management tools like SCCM or Intune do not offer the possibility to continue the installation after a reboot (unless you use a task sequence) - the scenario is not supported within the Windows Installer either.

Based on how the applications are configured, we encounter two situations:

  • Applications that don’t require administrative rights for installation
  • Applications that require administrative rights for installation

Apps without administrative rights

Typically applications without administrative rights trigger per-user installers , and because only user information is modified on the system (files, folders or registry), no administrative rights are required at the installation.

Turns out the solution is quite simple. To trigger an installation after reboot, we use the RunOnce registry keys.
RunOnce registry keys call programs to run every time a user logs on, and given the Windows Installer package is per-user, it makes sense to make an individual install.

The difference between the Run and RunOnce is that the commands in Run registry always run on each user log on, and the commands in the RunOnce only run once per each user.

To add a RunOnce key:

  1. Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce.
  2. Create a new key with the desired name and place the installation command.

For example, to install an MSI, we created a new key called InstallMSI and this holds the commandmsiexec /i TARGETTOMSI\YourMSI.msi /qn.


Next time a user logs in, the installation will start silently and the user will not notice anything during this process.

Apps with administrative rights

Unlike per-user installers, if an application must change system information, it always asks for administrative rights.

While technically the above mentioned RunOnce is a viable solution, at login the user will be prompted with a permission to install request (UAC).

Besides the not user-friendly experience for the user, in the majority of the managed infrastructures the users do not have granted per-machine admin rights. The challenge is to find the way to run the installer on machines without triggering admin rights for their users.

Using the Task Scheduler

Task Scheduler enables sysadmins to automatically perform routine tasks on a chosen computer. Task Scheduler also provides tons of criteria to perform your tasks, and even offers you the possibility to run a command with a specific user account -- for which case use NT AUTHORITY\SYSTEM.

The NT AUTHORITY\SYSTEM is a Local System account that has the highest privileges on the local computer, meaning that it offers the possibility to run installations skipping per-machine administrative rights.

To silently manage scheduled tasks, Schtasks.exe comes in help. With it, we can query, create, delete, run or end scheduled tasks on a local or remote computer.

Scheduling tasks brings an additional layer to your installation, because it cannot be used within an MSI package. It can be placed as a Custom Action, or even added with Advanced Installer through the Scheduled Tasks page, but the challenge is that we want to install the application after reboot, so it’s impossible to perform these changes via the package.

You need to use a scripted wrapper aside from your installer package -- either a VBScript, or a more known PowerShell wrapper like PSAppDeployToolkit.

Let’s come back to the above scenario and take the following steps to create your wrapper :

  1. Uninstall previous app version
  2. Create the scheduled task
  3. Force a reboot

The code to create a specific scheduled task in VBScript:

Dim WshShell, CmdLine, ExecutionExitCode
Const WindowStyle= 0, WaitForExit = True
Set WshShell = CreateObject("WScript.Shell")
CmdLine =  "SCHTASKS.exe /create /SC ONLOGON /F /TN ""Install Program"" /TR """ &
AUTHORITY\SYSTEM"""
ExecutionExitCode = WshShell.Run(CmdLine, WindowStyle, WaitForExit)
"msiexec /i " & "PATHTOMSI\YourMSI.MSI /qn"" /RL HIGHEST /RU ""NT 
        


The arguments parsed to schtasks.exe are:

  • SC - Specifies the schedule frequency, in our case when a user logs on
  • F - Forces the task to be created even if a task with the same name exists on the system
  • TN - Name of the task that appears in Task Scheduler
  • TR - The path and filename of the program to be run at the specified above interval
  • RL - Run level of the job, in this case highest
  • RU - Specifies the user account under which the task runs, in our case we use the NT AUTHORITY\SYSTEM

NoteFor more information, you can use schtasks.exe /create /?


The code to create a specific scheduled task in PowerShell (4.0):

$Trigger= New-ScheduledTaskTrigger -AtLogon
$User= "NT AUTHORITY\SYSTEM"
$Action= New-ScheduledTaskAction -Execute "msiexec.exe /i" -Argument 
"PATHTOMSI\YourMSI.MSI /qn"
Register-ScheduledTask -TaskName "Install Program" -Trigger $Trigger -User $User -Action 
$Action -RunLevel Highest –Force
        


Starting with PowerShell 4.0 a new module scheduledtasks is available. It offers the cmdlet Register-ScheduledTask which makes it easier to create tasks on a machine.

The cmdlet Register-ScheduledTask creates an identical scheduled task like the VBScript example above which runs at user log in with the highest privileges on the NT AUTHORITY\SYSTEM account. It’s up to you on which scripting language you use.


Now, you can now uninstall your previous application, create the scheduled task, reboot the computer and install the new version silently for the user without asking for administrative rights.

TipThe task runs each time a user logs in, and as it is a per-machine installer, you should delete the task during the install sequence.
HOW? Add a custom action in the MSI that performs the scheduled task deletion.

Dim WshShell, CmdLine, ExecutionExitCode, Installcommand, iReturn
Const WindowStyle= 0, WaitForExit = True
Set WshShell = CreateObject("WScript.Shell")
Installcommand = “schtasks.exe /Query /TN “ & Chr(34) & “Install Program” & chr(34)
iReturn=WshShell.Run(Installcommand,WindowStyle,WaitForExit) 
If iReturn = 0 Then Installcommand = “schtasks.exe /Delete /TN “ & chr(34) & “Install Program” & chr(34) & “ /F” End If


First, a query is made for a task named Install Program, and if this is found, then it’s deleted.
The code to delete a scheduled task in PowerShell (4.0):

$taskExists = Get-ScheduledTask | Where-Object {$_.TaskName -like “Install Program”}
If($taskExists){
Unregister-ScheduledTask -TaskName “Install Program” -Confirm:$false}


First, use the Get-ScheduledTask cmdlet to see if the task exists, and if it returns true, run the Unregister-ScheduledTask cmdlet to delete it.

Regardless of which scripting language you chose to delete the tasks, they must be placed in a deferred Custom Action inside the MSI, in a sequence as close to InstallFinalize InstallFinalize as possible.

If the app you want to install after a reboot is not an MSI, you can use a VBScript or Powershell wrapper to perform the installation and also delete the scheduled task using the above code.

Conclusion

While at first glance this might appear as a challenge, in the end, it’s actually not that hard. Dealing with per-user installations is much easier, but per-machine installs are also manageable. The key to success is respecting the order of the steps.

The example above applies to Windows Installer packages, but you get the same results with any type of program or script you choose to execute after a reboot.

Need more useful packaging tips & tricks? Let me know in the comments.

Comments: