Over a million developers have joined DZone.

Controlling IIS7 Programmatically

· Web Dev Zone

Start coding today to experience the powerful engine that drives data application’s development, brought to you in partnership with Qlik.

I am a huge advocate of automation and the automation of as much of a system as can be implemented. I like to make sure than non-developer members of staff can work effectively and try to do as much as possible to minimise the blockers in their way. IIS can be one of those blockers. When it comes to staff creating new sites and application pools, they can sometimes get it wrong. To make sure all members of my team have the exact same setup – I script the set-up.

A CI tool should be able to handle the automated rollout of configuration management to systems. This is just another example of making sure all parts of the environment have the correct set-up. Automating this rollout means a smaller chance of human error. Being able to interact with IIS means a simple script could be run to create the required setup – both locally and on a build environment.

I was able to create the following Powershell script.

import-module WebAdministration

Set-Location IIS:\AppPools

#This will create a new application pool of the name (to be passed as a parameter)
New-Item IIS:\AppPools\DemoAppPool
Set-ItemProperty IIS:\AppPools\DemoAppPool enable32BitAppOnWin64 true

Set-Location IIS:\Sites

#This will set a new website called TestSite (should be passed as a parameter)
#and will point this site at C:\test (should be passed as a parameter)
New-Item iis:\Sites\TestSite -bindings @{protocol="http";bindingInformation=":80:TestSite"} -physicalPath c:\test
Set-ItemProperty IIS:\sites\TestSite -name applicationPool -value DemoAppPool

The script basically automates a way of creating a new application pool, a new site and then assigning that application pool to that site

This script was easily able to run from either powershell or via cmd line (which invokes powershell). It’s a script that works perfectly well assuming you only need to run it once as it doesn’t take into account the site or the application pool existing. It needed a lot of refactoring. the script that was produced can be found below. It is a lot more useful as it takes parameters for setup.

<#
.SYNOPSIS
    Sets up AppPool and Site in IIS
.DESCRIPTION
	Sets up AppPool and Site in IIS (creating where necessary).  Can also be used to change parameters of existing site, i.e. changing the framework, physical path or enabled for 32bit.
	
	It is possible for a Site to share an AppPool with other sites but note any changes to the AppPool settings (i.e. Enable32 or FrameworkVersion), even if only implied by their defaults, will result in an error being raised and script termination.
	
	Should a Site be moved from one AppPool to another leaving the AppPool empty the AppPool will NOT be removed.  Therefore manual intervention will therefore be required to remove 'zombie' AppPools.
.EXAMPLE
    C:\PS> ./iis-site-creation.ps1 'TestSite' 'TestAppPool' 'C:\RootOfTestSite'
    Minimal command; sets up 'TestSite' using the app pool 'TestAppPool' using the physical path of C:\RootOfTestSite.
	
	Note 1: Can just run ./iis-site-creation.ps1 and you will be prompted to enter the three mandatory parameters.
	Note 2: These examples presume script is in current directory.
.EXAMPLE
	C:\PS> ./iis-site-creation.ps1 -SiteName 'TestSite' -AppPool 'MyAppPool' -PhysicalPath 'C:\Sites\TestSite' -Enable32 $true -FrameworkVersion 'v4.0'
	Full example with fully qualified parameters including the two optionals.
#>

param(
	[Parameter(
			Mandatory=$true,
			Position=0,
			HelpMessage="Name of the site")]
	[string]
	$SiteName,
	
	[Parameter(
			Mandatory=$true,
			Position=1,
            HelpMessage="Name of the AppPool to use.  (Will be created if doesn't already exist.)")]
	[string]
	$AppPool,
	
	[Parameter(
			Mandatory=$false,
			Position=2,
			HelpMessage="Physical location of site on system.  E.g. c:\src\ottrunk\website")]
	[string]
	$PhysicalPath = '',
	
	[Parameter(
		Mandatory=$false, 
		HelpMessage="If true will use 32Bit even on Win64 systems.  Default is false.")]
	[bool]
	$Enable32 = $false,
	
	[Parameter(
		Mandatory=$false,
		HelpMessage="Sets AppPool's framework version.  Possible values are 'v2.0' (default) or 'v4.0'")]
	[string]
	$FrameworkVersion = "v2.0"
)

function AppPoolExclusiveToSite([string] $appPool, [string] $siteName) {
	[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.Web.Administration")
	$iis = New-Object Microsoft.Web.Administration.ServerManager
	@($iis.sites |
		%{ if($_.Name -ne $siteName) { 
			$_.Applications |
				where-object { $_.ApplicationPoolName -eq $appPool } 
			}
		}).Count -eq 0
}

function UpdateAppPool([bool] $allowChange, [bool] $enable32, [string] $frameworkVersion) {
	$currentEnable32 = Get-ItemProperty "IIS:\AppPools\$AppPool" enable32BitAppOnWin64
	$currentFrameworkVersion = Get-ItemProperty "IIS:\AppPools\$AppPool" managedRuntimeVersion
	if($allowChange) {
		Set-ItemProperty "IIS:\AppPools\$AppPool" enable32BitAppOnWin64 $enable32
		Set-ItemProperty "IIS:\AppPools\$AppPool" managedRuntimeVersion $frameworkVersion
	} elseif( ($currentFrameworkVersion -ne $frameworkVersion) -or ($currentEnable32 -ne $enable32) ) {
		throw "Tried to change AppPool but cannot because AppPool is not exclusive to website"
	}
}

Import-Module WebAdministration
 
if(!(Test-Path "IIS:\AppPools\$AppPool")) { 
	New-Item "IIS:\AppPools\$AppPool"
}
$allowChange = !@(AppPoolExclusiveToSite $AppPool $SiteName)
UpdateAppPool $allowChange $Enable32 $FrameworkVersion


if(!(Test-Path "IIS:\Sites\$SiteName")) {
	New-Item "IIS:\Sites\$SiteName" -bindings @{protocol="http";bindingInformation=":80:$SiteName"}
}
Set-ItemProperty "IIS:\Sites\$SiteName" physicalPath $PhysicalPath
Set-ItemProperty "IIS:\Sites\$SiteName" applicationPool $AppPool

The trouble I had with this script started when running in different versions of the OS. X64 machines call the X64 powershell by default (as you would expect). When using X64 powershell the following error was encountered:

image

This of course worked perfectly in X86 version of powershell. Weirdly, a different error was encountered in X86 powershell. The line

Test-Path IIS:\AppPools\

command didnt like working. It threw the following error:

image

I was faced with the dilemma of fixing something I know relatively little about (powershell scripts) or continue to use the simple script and manually manipulate IIS after the initial set-up.

Strangely, I chose to ditch both methods and wrote a C# console application to manipulate IIS. It took me half the time and was very easy. Andrew Westgarth, IIS MVP, replied to me on twitter after I said I had done this

I could have told you that :-) the .net APIs rock :-)

It was as simple as referencing Microsoft.Web.Administration and writing code against that API. As it was a console application, it created an executible that I could call easily from TeamCity or via a batch script for local machine automation. I don’t have to worry about ExecutionPolicy either, which is a real bonus.

The source code for the console application is available on my github site. Feel free to take it and change pieces of it to suit you. I have also included both powershell scripts as listed above.



Create data driven applications in Qlik’s free and easy to use coding environment, brought to you in partnership with Qlik.

Topics:

Published at DZone with permission of Paul Stack, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}