Introduction
Gone are the days where daily reboots of Windows were needed. However, when dealing with system maintenance or installing multiple applications from script,
rebooting is sometimes unavoidable. This article will describe a PowerShell script capable of running through a number of steps, rebooting the computer,
and continuing the script at another step. Simple, yet very useful.
Background
The ideas shown in this article stem from a real life script for setting up a developer PC with everything from the right version of the .NET Framework,
enabling the right features in IIS, installing Visual Studio and MS SQL Server locally, plus a lot more. The advantages of setting up a developer PC in this way are many:
- It is a lot faster than letting every developer go through the steps themselves
- It is a lot more flexible than using a disc image
- It documents very clearly which technologies are used
- It can be used for updating existing developer PCs as well as installing from scratch
The main disadvantage of the above mentioned setup script is the upfront time investment in getting such a script in place. This article will however
help you to get started and you should really take up the challenge and try creating your own script - you will be impressed with just how powerful PowerScript really is.
Running the Test Script
The simple test script covered in this article is shown below:
param($Step="A")
# -------------------------------------
# Imports
# -------------------------------------
$script = $myInvocation.MyCommand.Definition
$scriptPath = Split-Path -parent $script
. (Join-Path $scriptpath functions.ps1)
Clear-Any-Restart
if (Should-Run-Step "A")
{
Write-Host "A"
Wait-For-Keypress "The test script will continue after a reboot, press any key to reboot..."
Restart-And-Resume $script "B"
}
if (Should-Run-Step "B")
{
Write-Host "B"
}
if (Should-Run-Step "C")
{
Write-Host "C"
}
Wait-For-Keypress "Test script Complete, press any key to exit script..."
The script will execute step A through C, only when done with step A, it will reboot, and then continue at step B. Below are two screenshots showing what to expect:
Making the Script Step Aware
Making a PowerShell script to execute in sequential steps can be done in a number of ways. The only thing required in this example is that the starting step
must be specified on the command line, as in:
>.\testscript.ps1 -Step B
As seen from the test script above, we declare a script parameter $Step
for taking in the starting step from the command line. We then create
a simple guard method Should-Run-Step
which will return false until the starting step specified on the command line is encountered, and from there on, it will return true:
$global:started = $FALSE
$global:startingStep = $Step
function Should-Run-Step([string] $prospectStep)
{
if ($global:startingStep -eq $prospectStep -or $global:started) {
$global:started = $TRUE
}
return $global:started
}
This stepping mechanism could of course be way more sophisticated, including endpoints and step ranges, but that is not really the focus of the article and hence
left as an exercise for the reader.
A Few Registry Helper Functions
As much as I like the super general ???-ItemProperty
functions of PowerShell, I tend to think these methods can clutter the scripts and make them less readable.
Therefore I will introduce four simple helper methods for dealing with the Registry:
function Test-Key([string] $path, [string] $key)
{
return ((Test-Path $path) -and ((Get-Key $path $key) -ne $null))
}
function Remove-Key([string] $path, [string] $key)
{
Remove-ItemProperty -path $path -name $key
}
function Set-Key([string] $path, [string] $key, [string] $value)
{
Set-ItemProperty -path $path -name $key -value $value
}
function Get-Key([string] $path, [string] $key)
{
return (Get-ItemProperty $path).$key
}
Rebooting from PowerShell
Restarting a computer from PowerShell is done simply with the command Restart-Computer
. Making Windows execute a command on startup is handled
via the Registry key "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run". Putting this information together leads us to define a Restart-And-Run
function which will reboot and then launch whatever is passed in the $run
parameter.
$global:RegRunKey ="HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
function Restart-And-Run([string] $key, [string] $run)
{
Set-Key $global:RegRunKey $key $run
Restart-Computer
exit
}
If you do not want to launch the command specified every time you start Windows, you better remember to clear that Registry key. As we plan to resume our script,
we can easily do that in a dedicated function which is to be placed at the top of our script.
$global:restartKey = "Restart-And-Resume"
function Clear-Any-Restart([string] $key=$global:restartKey)
{
if (Test-Key $global:RegRunKey $key) {
Remove-Key $global:RegRunKey $key
}
}
As you may have noticed, the Clear-Any-Restart
function takes a default key of "Restart-And-Resume", and resuming the script was what this article
set out to accomplish. Guess what, all we need to do is restart PowerShell with the wanted step parameter:
$global:powershell = (Join-Path $env:windir "system32\WindowsPowerShell\v1.0\powershell.exe")
function Restart-And-Resume([string] $script, [string] $step)
{
Restart-And-Run $global:restartKey "$global:powershell $script -Step $step"
}
That is it, we are all done, you are now ready to make your own setup scripts. Enjoy, and please do let me know what you think and what crazy things you use this for.
Troubleshooting
If you are having trouble executing the script, make sure you have not specified the restricted
execution policy:
>Set-ExecutionPolicy RemoteSigned
History
- July 08, 2011: Initial version.