How to automate Windows with PowerShell

PowerShell provides plenty of sorting and filtering options, then, but it's not just a passive reporting tool. Take a look at this:

Get-Service | Out-GridView -Title 'Select service to restart!' -OutputMode Single | Restart-Service -WhatIf

We're getting a list of installed services, and displaying them with a custom window title as a user prompt. The -OutputMode Single switch tells PowerShell that we're allowed to select one item in the list. If we do this, and click 'OK', our chosen service is passed along the pipeline to the next cmdlet, Start-Service, which stops and starts it for us, which is very useful as a way to try to revive any services that are misbehaving.

Or, at least, it would restart the service if we hadn't included the -WhatIf switch, which tells PowerShell to simply display its action instead. This is a handy safety option, which means you can see how a cmdlet might work without the risk of, in this case, accidentally stopping a service that really should be left alone. But if you want to try it for real, enter the same cmdlet without the -WhatIf, and you'll have created your very own custom service-restarting tool.

How to automate Windows with PowerShell

PowerShell isn't just about the command line. New-OSC WindowsTile creates tiles to launch scripts

You can, of course, do something similar with processes, services, and any other objects PowerShell can manipulate. But even that's not the end of the story:

Get-Service -ComputerName MyPC | Out-GridView -OutputMode Single | Restart-Service -WhatIf

Cmdlets like Get-Service and Get-Process aren't restricted to your local system. Use the -ComputerName switch with the name of a network computer and you're able to see what it's running, too (assuming your Windows user account has the privileges to access them). PowerShell can then manage remote systems in exactly the same way as your own PC.

PowerShell ISE

So far we've been working only in the PowerShell console, entering commands one by one and seeing the results right away. There is another way to run code, though – in the PowerShell Integrated Scripting Environment (ISE). It's a little more complex, but much better when you'd like to string several cmdlets together, or create some code for reuse later. Launch it by searching for PowerShell and clicking 'Windows PowerShell ISE', entering Powershell-ISE.exe in the Run box, or by entering ISE at the PowerShell console.

The ISE opens with a two-pane interface. On the left is the console, where you can enter PowerShell commands. On the right is the Commands Add-On, a handy tool that can help you build commands with the mouse.

Type process in the Commands 'Name' box; you'll see various matching cmdlets. Select 'Get-Process' to see its parameters, helping you understand what the cmdlet can do. Click the 'Name' tab, for instance, and you'll find a Module box. What does this do? Check it and click 'Run'. The Commands Add-On builds the cmdlet Get-Process -Module, runs it in the console, and displays the results – a list of all your processes, where each one includes its loaded modules (DLLs and other support files).

While this can be helpful, the ISE console also has some extra tricks to speed up your PowerShell coding. Begin typing a cmdlet (try Get-Process again) and ISE displays possible matches. By the time you've reached Get-Pro, the correct cmdlet should be highlighted, and you can press [Tab] to automatically enter the remaining characters.

It's a similar story when it comes to entering parameters. Tap the space bar, then a hyphen, and ISE lists the various Get-Process options. Use the cursor keys to scroll down, then select '-Module', press [Enter] and again it is automatically added to your command, no typing required.

As you can see, there's more to learn in the ISE, but it does also make it easier to explore what PowerShell has to offer. Now we just have to use it to build a script.


Click 'View > Show Script Pane' to reveal the script pane. This is a separate area where you can enter a string of commands, across as many lines as necessary, without having them executed immediately. Instead, you can run all the commands in the Script pane at any time by pressing [F5] or clicking 'Debug > Run'.

To give this a try, enter the following four commands into the Script pane.

$computername = read-host "Which computer name would you like to check?"

$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername

$lastbootuptime = $os.ConvertToDateTime


Write-output "$computername last boot time was $lastbootuptime"

This is a simple script, which tries to find out the last boot time for whatever network computer you specify. Although very short, it's much more advanced than our previous code, and introduces several new concepts.

The first line, for example, uses the read-host cmdlet to display a prompt, asking the user to enter a computer name. This is then stored in a variable called $computername.

The second line uses WMI to retrieve the operating system for the specified computer, while the third then obtains its boot time and converts it into a readable format. (Don't worry about the technical details here; all you really need to remember is that Get-WmiObject can return useful information about your system configuration.)

Finally, the last Write-output cmdlet sends a message to the console. The variables will be replaced by their actual values so, for example, you might see "MyServer last boot time was 06/10/2014 08:30".

Press [F5] to launch the script. If you can access a networked PC, enter its name, otherwise enter localhost or just a period to check the local system. And that's it – your first multi-line script. Click 'File > Save As' and save it as C:\Scripts\LastBootTime.ps1 (creating the folder, if necessary), ready to be recalled whenever you like.

Our sample ISE script was very small, but the principles can be used to run whatever you like. Visit the Microsoft Scripting Centre – or search for PowerShell Scripts – to locate more examples, copy and paste them into the scripting pane, and press [F5].

There is still one issue remaining, though: how can you run the script outside of PowerShell? Double-clicking it seems an obvious solution, but try this and the file opens in Notepad; less than helpful.

You could relaunch PowerShell and enter C:\Scripts\LastBootTime.ps1 at the command line, but that won't work, either. You'll just see a message complaining that "running scripts is disabled on this system". This is normal; the default security settings place strict limits on scripts to prevent their abuse by malware.

To get around this problem, you need to find out more about PowerShell's execution policy. The following cmdlets will help:


Set-ExecutionPolicy RemoteSigned

The first line should tell you that your policy is set to 'restricted', blocking scripts. If so, entering the second line sets execution policy to 'RemoteSigned', instead. This means your own scripts will run immediately, but any scripts you download will need to be digitally signed by a trusted publisher.

Test the new policy by entering C:\Scripts\LastBootTime.ps1 again, and this time your script should run. If it's too much hassle to enter the full path each time, just add C:\Scripts (or whatever folder you choose for your scripts) to your PATH environment variable (press [Win]+[X], click 'System > Advanced System Settings > Environment Variables', double-click 'Path' in 'System Variables', then add a semi-colon and the folder – ;C\Scripts – to the end of your path).

This isn't quite the end of the story. The official PowerShell library has some useful details on executing scripts, and there's a neat trick you can use to launch scripts from a shortcut but otherwise you now know how to test, write and run PowerShell code. It's time now to begin some serious scripting.