Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / PowerShell

Reboot and Resume PowerShell Script

4.71/5 (9 votes)
8 Jul 2011CPOL3 min read 123.9K   2.8K  
A first step in creating that magic Developer PC Setup Script.

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:

Script running step A and then reboots

Script continues the script starting at step B

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)