Constructing your First PowerShell Provider

Introduction

I think it's safe to say that PowerShell will be a staple on the Microsoft platform for the foreseeable future. Version 2.0 is shipping standard with Windows 7 and Windows Server 2008 R2. Exchange leverages PowerShell, SQL Server 2008 leverages Powershell, and future server products will be leveraging PowerShell. If you're not building a product's administration features on top of PowerShell you soon will be.

There is, however, a PowerShell learning curve. As a developer you need to master two major PowerShell concepts. The first is familiarity with the PowerShell environment. The second is learning how to build CmdLets and Providers, the components that plug into PowerShell. Much has already been written about building CmdLets. So, in this article, I'm going to demonstrate some basic Provider construction.

Provider Overview

A complete introduction to PowerShell and PowerShell Providers is beyond the scope of this article. So I'll focus on a few of the major PowerShell Provider concepts.

First, I think of a Provider as a storage place for an application's data. A Provider plugs into PowerShell and through the standard or custom CmdLets navigates and modifies the application's data. Typically a Provider is represented by a path which looks similar to the one you would see from the Windows command line. Most of the Microsoft Server products have some type of Provider.

Like CmdLets, Providers can emit .NET Objects. Because Providers and CmdLets are using the Common Language Runtime and the .NET Framework, objects from different providers can interact in new and interesting ways. PowerShell commands can be joined through a Pipeline, so the results of a particular command can feed the input to another command. When you consider the ecosystem of PowerShell providers already shipping with many Microsoft products and the extensibility provided by the .NET Framework; it shouldn't be hard to justify PowerShell support for your product.

Sample Overview

I developed the sample in Visual Studio 2008 and targeted PowerShell 1.0.

Like any software application a Provider's complexity depends on the problem it solves and how the provider solves the problem. The first step to building a provider is to understand how CmdLets interacting with the Provider are translated into function calls in your code. This sample arose from a need to study the Cmdlet to Provider to code interaction.

Aside from dishing up .NET objects, a Provider is responsible for validating the path information input by the user. The sample does some simple validation and emits Win32 debugging information you can view inside of the DebugView utility. Sources at the end of the article include DebugView information for downloading DebugView. The animation below shows the sample code in action.

Figure 1: PowerShell Sample in action

There are many styles of Providers. Styles are in a hierarchy of Provider functionality. The hierarchy appears below.

DriveCmdLetProvider

ItemCmdLetProvider

ContainerCmdLetProvider

NavigationCmdLetProvider

The lowest level of functionality is a Drive Provider and the highest is a Navigation Provider. I chose a Navigation Provider so I could explore all possible functionality. Since each level of Provider must supply all the functionally of the Provider a level up, I partitioned the sample code into regions so you can browse all the functions related to a particular Provider in the hierarchy. Later in the article I'll refer to the regions.

Before looking at Navigation Provider code, I want to explain how I utilized DebugView.

Trace and DebugView

.NET Trace and Debug statements are great for troubleshooting real-time software. Basically, they're useful anytime it's not feasible to step through an application with the Debugger. I built the following class to handle writing Trace statements targeted for DebugView.

Though PowerShell has its own Trace and Debug statements, I realized that I wouldn't always have the foresight to activate PowerShell verbose mode. I also realized that what I display in PowerShell may be different than what I want to display when I'm debugging. In addition, I thought it would be faster to do unit testing from a Console Application and hook my code into PowerShell once I had my code debugged. Therefore, I wouldn't always be running from within PowerShell. Finally, with DebugView filtering, I felt I had more selective control over what was displayed.

With some background on PowerShell Providers and some of the tools I used to debug my Provider, I'm ready to explain how the sample provider works.