Writing Re-usable Scripts with PowerShell

Continuing on from last time, I will now talk about writing re-usable scripts in PowerShell. Any command that we have executed at PowerShell command line can be dropped into a script file. I have lots of little PowerShell scripts for common tasks sitting in c:\Utilities\Scripts, which I include in my path. Let’s say that I want to stop all running copies of Cassini (aka the Visual Studio Web Development Server aka WebDev.WebServer.exe).

Stop-Process -name WebDev.WebServer.exe -ErrorAction SilentlyContinue

This will terminate all running copies of the above-named process. ErrorAction is a common parameter for all PowerShell commands that tells PowerShell to ignore failures. (By default, Stop-Process would fail if no processes with that name were found.)

We’ve got our command. Now we want to turn it into a script so that we don’t have to type it every time. Simply create a new text file with the above command text called “Stop-Cassini.ps1” on your desktop using the text editor of your choice. (The script can be in any directory, but we’ll put it on our desktop to start.) Let’s execute the script by typing the following at the PowerShell prompt:

Stop-Cassini

Current dirctory not in search path by default

What just happened? Why can’t PowerShell find my script? By default, PowerShell doesn’t include the current directory in its search path, unlike cmd.exe. To run a script from the current directory, type the following:

.\Stop-Cassini

Another option is to add the current directory to the search path by modifying Computer… Properties… Advanced… Environment Variables… Path. Or you can modify it for the current PowerShell session using:

$env:Path += ‘.\;’

($env: provides access to environment variables in PowerShell. Try $env:ComputerName, $env:OS, $env:NUMBER_OF_PROCESSORS, etc.)

You could also modify your PowerShell startup script, but we’ll talk about that in a future instalment. Let’s run our script again:

ExecutionPolicy error

No dice again. By default, PowerShell does not allow unsigned scripts to run. This is a good policy on servers, but is a royal pain on your own machine. That means that every time you create or edit a script, you have to sign it. This doesn’t promote the use of quick scripts for simplifying development and administration tasks. So I turn off the requirement for script signing by running the following command from an elevated (aka Administrator) PowerShell prompt:

Set-ExecutionPolicy Unrestricted

Set-ExecutionPolicy RemoteSigned

Set-ExecutionPolicy succeeded

If this command fails with an access denied error:

Set-ExecutionPolicy failed

then make sure that you launched a new PowerShell prompt via right-click Run as administrator…

Third time is the charm…

Success!

We are now able to write and use re-usable scripts in PowerShell. In my next instalment, we’ll start pulling apart some more complicated scripts that simplify common developer tasks.

UPDATE: As pointed out by Josh in the comments, setting your execution policy to RemoteSigned (rather than Unrestricted) is a better idea. Downloaded scripts will require you to unblock them (Right-click… Properties… Unblock or ZoneStripper if you have a lot) before execution. Thanks for the correction.

About James Kovacs

James Kovacs is a Technical Evangelist for JetBrains. He is passionate in sharing his knowledge about OO, SOLID, TDD/BDD, testing, object-relational mapping, dependency injection, refactoring, continuous integration, and related techniques. He blogs on CodeBetter.com as well as his own blog, is a technical contributor for Pluralsight, writes articles for MSDN Magazine and CoDe Magazine, and is a frequent speaker at conferences and user groups. He is the creator of psake, a PowerShell-based build automation tool, intended to save developers from XML Hell. James is the Ruby Track Chair for DevTeach, one of Canada’s largest independent developer conferences. He received his Bachelors degree from the University of Toronto and his Masters degree from Harvard University.
This entry was posted in PowerShell. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.jameskovacs.com james.kovacs

    Thanks for the comments. I have updated the post to recommend using RemoteSigned rather than Unrestricted. Good catch.

    @Alastair – No, I haven’t investigated modules. I’m trying to stick to PowerShell v1 as that is what most people will have available on their machines. I’ll add modules to my rapidly growing list of things to investigate in v2. Thanks.

  • http://www.josheinstein.com Josh Einstein

    I agree with wekempf. Personally I use RemoteSigned which basically requires signing for any scripts downloaded from the internet or run from a UNC but doesn’t for “unblocked” local scripts. (Blocked as in what IE does to a file it downloads. Right click -> properties -> unblock.)

    Hans: The RunAs command doesn’t work the way UAC does, but using a utility from Wintellect I wrote a Start-PowerShell command that spawns off a second PowerShell session, prompting for UAC elevation, and restores your current working directory and optionally runs a scriptblock. You can get it on my SkyDrive at http://www.josheinstein.com under PowerShell\Modules\Host

  • http://www.pseale.com/blog/ Peter

    As long as you point out that you’re using PowerShell for productivity/automation and not to run your Enterprise (which you did), I think the lo-fi approach works well, especially to start out. And now I’m curious about how modules work in v2.

  • http://wekempf.spaces.live.com wekempf

    Not sure you should tell readers to set their security policy to unrestricted without explaining what that means and the alternatives available (even if you just want to link to some documentation).

  • http://www.alastairsmith.me.uk/ Alastair Smith

    @Hans, you can use the runas command. It’s a little verbose, but generally it works well.

    @James, have you investigated modules in PoSh v2? They’re a replacement for the snap-in stuff in PoSh v1, and allow cmdlets to be written in PowerShell itself (what were called Script Cmdlets in an earlier CTP). They’re pretty lightweight and easy to write, and support authoring all the script metadata that you’re used to using as a PowerShell user (such as help, examples, etc.).

    Converting your library of utility scripts to a module would also get around the path issues you described, as PowerShell checks the module repositories as part of the discovery mechanism.

  • Hans Halim

    Is there some sort of sudo command for PowersShell so that you don’t have to launch via right-click then Run as admin?