Scripting IIS7 with PowerShell

Often I find that the last thing I want to look at is yet another new language to learn, but PowerShell is proving itself to be very useful for writing up Windows scripts, particularly when you want to interact directly with Microsoft services. In my project I have several web applications set up in IIS, and my version control structure has the trunk and an arbitrary number of branches. Whenever I would want to switch to working on a different branch of the code, I would need to reset the IIS applications to point to the new path; this quickly became more tedious than I like.

This seems like a good example to show what a very simple PowerShell script can do. I’m not going to cover how to set up PowerShell, but I will say that if you are on Windows 7, it’s already there waiting for you. For this example, you also need to make sure you have the IIS PowerShell module set up.

With that out of the way, let’s get started. As I mentioned before, the directory structure of my repository is very simple, as shown in the picture to the right. And no, I don’t really name my projects WebApplication1 and WebApplication2. The script I wanted to build was very simple: provide a menu of versions it finds, and let you pick which one to set IIS to use.
If you’re new to using PowerShell with IIS, one interesting aspect of it is the ability to browse IIS via the command line as if it were just another drive on the system. For example, let’s take a look at the current settings before we get started:

PS C:\Users\Greg> dir 'IIS:\Sites\Default Web Site'  
Name             Application pool   Protocols    Physical Path  
----             ----------------   ---------    -------------
WebApplication1  DefaultAppPool     http         C:\svn\trunk\WebApplication1  
WebApplication2  DefaultAppPool     http         C:\svn\trunk\WebApplication2  

First things first; we import the IIS library and set up the main variables used in the script:

Import-Module WebAdministration

# set this to the root folder, which contains 2 folders: "branches" and "trunk"
$svnPath = "c:\svn"

# paths to the branches
$branches = Get-ChildItem ($svnPath + "\branches")

# path to IIS website we are looking to configure
$iisPath = "IIS:\Sites\Default Web Site\"

$options = @{}
$optionCounter = 1

Most of that is pretty straightforward, but I’ll comment on some of it. Get-ChildItem is a PowerShell Cmdlet to list the child items in a location, which in our case is the folder of branches. The syntax used to declare $options creates it as an empty hash table.

Next, we’ll add some code to print out the options you can pick from. I make the assumption that the trunk will always be there, and then list the branches found in the previous section. There is nothing particularly interesting in this part:

# Print out trunk/branch options
write-host "Select which version you want to use in IIS:"  
write-host ""

write-host "1: Trunk"  
$options.Add($optionCounter.ToString(), ($svnPath + "\trunk"))

write-host "---------------------"  
write-host "Branches:"  
write-host ""

foreach ($branch in $branches) {  
    $options.Add($optionCounter.ToString(), $branch.FullName)

    write-host "$($optionCounter): $($branch.Name)"

write-host ""  

As you can see, the write-host command is used to write out to the console. Similarly, read-host is used to get input from the user. We loop until you either pick a valid option in the menu, or decide to quit:

# Let the user pick an option
$input = ""

do {  
    $input = read-host ‘Choose a version ("quit" to cancel)’
} while ($input -ne "quit" -band $options.ContainsKey($input) -eq $False)

# if they wanted to quit, we're done
if ($input -eq "quit") {  

write-host ""  

Now we’ve displayed a menu, and chosen which version of the applications we want to use in IIS. Finally, it’s time to update the actual IIS settings. In this example, I will include a hardcoded array of projects to use, but this could just as easily be made dynamically. For now we’ll keep it static to have total control on which applications this is applied to.

# now we can start updating IIS settings
$appPath = $options.Get_Item($input)
$projects = ("WebApplication1", "WebApplication2")

foreach ($project in $projects) {  
    write-host "Updating: $($project)"

    Set-ItemProperty ($iisPath + $project) -name physicalPath -value ($appPath + '\' + $project)

write-host ""  
write-host "Done!"  

There, we use the Set-ItemProperty Cmdlet to update the physical path on each application in IIS. As I mentioned earlier, the IIS PowerShell module allows you to treat IIS applications as you would normal files in a folder, so that’s what we leverage here. You could use the same approach to set any other aspect of the application as well.

Here is sample output from running the script:

PS C:\Users\Greg> powershell.exe .\Set-IIS-Paths.ps1  
Select which version you want to use in IIS:

1: Trunk  

2: 2010-01-01  
3: 2010-01-15

Choose a version ("quit" to cancel): 2

Updating: WebApplication1  
Updating: WebApplication2


And there you have it. There is nothing groundbreaking here, and it only scrapes the surface of what you can do with both PowerShell and IIS, but it shows how simple it can be to write scripts to make your life easier, leaving more time to spend on doing the work you want to be doing. PowerShell also provides the ability to build rich user interfaces through WPK, available as part of the PowerShell Pack. I’ll leave it as an exercise for the reader to convert this into a GUI.

comments powered by Disqus