IIS7 PowerShell support -- details of our design

After IIS team released Technical Preview of our PowerShell provider and commands, we got a few rants and grumblings from our customers. Some people pointed to complexity of IIS PowerShell provider and command parameters. Other people denied the need of provider for IIS at all, telling that just a set of commandlets with simple parameters will be sufficient. I have to admit that we did a mistake shipping preview of provider without complete set of commands. This created an impression of incomprehensible complexity of our tool.

In reality we had the following plan in mind: build base functionality first -- namespace, provider and generic cmdlets for configuration data handling, then add on top of it number of helper commands to cover most common and most convoluted tasks and actions. In our second preview release we included several dozens of commands that don’t require deep understanding of IIS configuration and structure of provider namespace. All these commands were implemented as “C# coded scripts”, i.e. they take parameters from user and generate script lines utilizing base functionality. We have to do it as compiled cmdlets, because for PowerShell v1.0 it is the only way to get full service from shell: help, parameters description, etc. In PowerShell v 2.0 these cmdlets could be implemented through pure readable script.

For the beginning I would like to explain a bit of our reasoning behind design of our PowerShell provider and base level cmdlets.

1. From my early days in IIS team I always had a feeling that we need interactive command tool that would work like shell on top of IIS configuration. I believe IIS administrators will use this tool more like a shell than like a script processor. Therefore navigation and other aspects of namespace were considered important. When Jeffrey Snover showed us the very first prototype of PowerShell, I saw what I always wanted: interactive composable shell with navigation.

2. IIS configuration is rich and quite complicated. Let me illustrate it by numbers. On my development machine I could run the following command and find total number of configuration sections with schema (I will get back to details of these commands in my later posts):

$(get-webconfiguration “//*[is-section()=’true’]” MACHINE/WEBROOT/APPHOST).count

This will produce 102 in my case. It means we have at least 102 data structures to manage. Now let’s run another command, which will show how many sections have default collections:

$(get-webconfiguration "//*[is-section()='true']" MACHINE/WEBROOT/APPHOST | where {$_.Schema.CollectionSchema -ne $null}).count

That gives me 36. And finally, let’s take a look at the total number of collections on unique elements:

$names = @{}

$elements = get-webconfiguration //* MACHINE/WEBROOT/APPHOST | where {$_.Schema.CollectionSchema -ne $null}

foreach ($el in $elements) {$names[$el.ElementTagName] += 1}

$names.Count

I got 88 here. What these numbers tell us? Our tool have to handle many data collections, and most of them are nested either inside child elements of sections, or inside parent collections.

Both considerations lead to namespace that should support navigation, operations on objects of this namespace and on properties of those objects. PowerShell naturally supports this functionality through providers. Historically IIS had hierarchy of objects that roughly follows URL path. Up to IIS 6 it was directly supported by metabase, in IIS 7 we placed all URL “related” objects into nested collections of one giant structure, configuration section ‘system.applicationHost/sites’. For PowerShell namespace I decided to abstract from details of configuration storage implementation and return back to familiar hierarchy “server/site/application/virtual directory/web directory/etc”. User could navigate along this hierarchy, change properties of objects, execute commands for them, copy objects, and current path will be used in most commands by default. This hierarchy roughly relates to commit path, as it used in configuration APIs, i. e. to concrete configuration files.

Now, let’s consider why provider is important. Imagine that we want to have set of operations on configuration objects without navigation path. It would be like using file system provider from the root of the drive, you always have to type full path. Don’t like path at all? You still need to specify full set of parameters to address nested objects: applications inside of site element, virtual directories inside of application, etc. For example, command to set user name on virtual directory would be something like

Set-username –site mysite –application myapp –virtualdirectory myvdir –value dude

Set-property –site mysite –application myapp –virtualdirectory myvdir –name username –value dude

Instead of

Set-itemproperty iis:\sites\mysite\myapp\myvdir –name user –value dude

I don’t think that provider command is more complicated than any of first two commands. Use of provider has additional benefits: you have to deal with the same commands as in other namespaces, or in other parts of IIS namespace. Do you want to change setting on the application pool? Use the same command:

Set-itemproperty iis:\apppools\mypool –name autoStart –value false

All you need is to remember how path is constructed in our namespace. This will happen naturally when you use it and navigate along it. Don’t remember property names? Use the same command, as you would do for other providers:

Get-item iis:\apppools\mypool | get-member

Or, if you already navigated to this object and use standard command aliases,

Gi . | gm

Sp . –n autostart –val true

In other words, if we want to use benefits of being one of PowerShell namespaces, we have to design namespace, path and provider. I tried to show you here, that we are not losing anything when we use set of standard commands instead of recreating them outside of namespace.

Web objects are important, but main bulk of configuration data is stored outside of them – in configuration sections. In my next post I will discuss how we use XPath queries to provide flexible and user extensible namespace.

No Comments