
In this third part I'm going to show a demo of a powershell provider I created in dead moment on a Thursday evening (grin). This post is part of a series consisting of currently four parts (not all published, but that doesn't matter).
The first two parts can be found here:
PowerShell providers
PowerShell works with a provider model for the various drives that are defined for the user. This provider model allows to extend PowerShell so that it can access stores that contain browsable resources and possibly resources that can be manipulated using commandlets or applications.
If a user for example invokes the get-childitem command on a drive, PowerShell is going to look up the provider that the drive belongs to and asks the provider if the path the user wants to get the child-items of exists and invokes the GetChildItems method of the provider to retrieve the items at the provided path.
PowerShell has some standard providers for various stores included, the following providers are included in PowerShell 1.0:
- Filesystem Provider
- Registry Provider
- Certificate Store Provider
- Alias provider
- Function provider
- Variable provider
This is a fairly complete set of providers for most common system management scenario's. You are free however to extend this with your own providers.
More functionality and more complexity
PowerShell offers a wide range of base classes each providing more functionality build on top of the previous base class. Each layer you add offers extended functionality, but also makes it more complex to build a provider.
The following base classes exist for creating custom providers:
- CmdletProvider
The most basic provider base class PowerShell exposes. This class does nothing. Yep I know, it's boring but that's the way it is. Actually it does not really nothing, it contains all the basic methods required to implement a provider in PowerShell. And you can access the runspace session state and register for events that may occur in the PowerShell runtime. So this one is while not offering any drive capabilities still useful for other stuff that you want to attach to the runspace.
- DriveCmdletProvider
Build on top of the CmdletProvider is the DriveCdmletProvider. This provider offers the possibility to create a drive that points to a store that is accessible through the provider. If you want to make a store accessible through a custom provider, start by inheriting from this class.
- ItemCmdletProvider
You need the ItemCmdletProvider to access items in a store, this provider enables the retrieval of items from a store or manipulation of items in a store.
- ContainerCmdletProvider
A lot of the providers Microsoft delivers with PowerShell use this class as a base. This provider base class offers the possibility to list childitems of a location in a store. The variable provider and function provider use this clas to implement their functionality.
- NavigationCmdletProvider
The last level of base classes is the most complete base class you can use for building a custom provider. This class offers navigation possibilities. In practice it means it has methods to combine a parent and child path to a new location and a way to move up one level in a store. This provider is aware of the location it is currently at. Good examples of providers which use this base class are the Registry provider and the Filesystem provider.
You will need a different level of base class depending on which functionality you want to implement. One of the easiest ways to start implementing a provider is by inheriting DriveCmdletProvider and work your way up to the navigationCmdletProvider. Implement the functionality required by the base class and test the functionality. Once you are satisfied, replace the base class with the next one and implement the functionality required by that base class. This way you have more control over what is happening. It's advisable to use this trick for the first time, as debugging providers can be quite hard.
Extending functionality with interfaces
Besides inheriting from a base class there's a second way to extend the functionality of your custom provider. This is done by implementing one of the many provider related interfaces that PowerShell exposes. The following interfaces are useful for providing extended functionality:
- IContentCmdletProvider
By implementing this interface you tell PowerShell that the provider offers a way to read and write the content of the items exposed by the provider.
- IPropertyCmdletProvider
This interface allows PowerShell to retrieve and manipulate properties of items exposed by the custom provider.
- ISecurityDescriptorCmdletProvider
Implementing this interfaces allows PowerShell to retrieve information about the security of items exposed by the provider. It also allows the user to manipulate the security of items exposed by the provider.
Provider capabilities
One of the things that is really great when implementing your own custom provider is the provider capabilities. When creating a provider you can specify extra capabilities implemented by a provider. This is done in the attribute declaration, a sample of this is shown below:
[CmdletProvider("Package", ProviderCapabilities.None)]
The following capabilities can be added:
- ShouldProcess
PowerShell will ask the user for confirmation when performing possibly dangerous operations. When you want to use this extra capability you will have to invoke ShouldProcess() and only continue working on a dangerous operation if this method returns true.
- Credentials
When a provider requires credentials to access a store you can specify this requirement by setting this capability or by combining this capabilities with other already defined capabilities. PowerShell will popuplate a Credential object with credentials when the user creates a provider like this:$credential = get-credential DOMAINwillemm
new-psdrive –root C:userswillemmdoc1.docx –name doc –provider package –credential $credential
There are other capabilities which offer other functionality like filtering. I will not discuss those here. Check MSDN for more information on drive capabilities if you want to know more.
What is in the demo
The demo I've attached to the post implements a provider to access Office Packages (also known as word documents, powerpoint presentations and excel workbooks). While this demo is primarily meant to display how to build a custom provider, it also offers some pretty useful stuff for people that use openXML more frequently.
The provider in the demo allows to retrieve a list of related items from the package or a list of items that are related to the item at the current location in the package.
For example:
ls doc:worddocument.xml
Will return a list of items including a possible numbering style and the images that you added to the document. Furthermore you can ask for the contents of an item by invoking:
get-content doc:worddocument.xml
Which will return the content of the main document part when you have word document mounted.
Registering a provider
When you have build a provider you need to register it with PowerShell. This is done by registering the PowerShell snap-in and activating the snap-in (See part 1 of the series for a full description). After you have done that, you can mount a drive by invoking the following command:
New-psdrive –root <path to the store> -provider <name of the provider> -name <name of the drive>
Example:
New-psdrive –root C:userswillemmdocumentstest.docx –provider package –name doc
More information
There's loads more I could write down about providers, but I have somewhat reached the limits of what is comfortable to read on a weblog. If you want more information here's a list of sources where to find out more about custom providers:
- Overview of provider capabilities: http://msdn2.microsoft.com/en-us/library/system.management.automation.provider.providercapabilities(VS.85).aspx
- MSDN article on how to create a custom powershell provider: http://msdn2.microsoft.com/en-us/library/ms714636(VS.85).aspx