Wrox Home  
Search
Professional Windows PowerShell Programming: Snapins, Cmdlets, Hosts and Providers
by Arul Kumaravel, Jon White, Michael Naixin Li, Scott Happell, Guohui Xie, Krishna C. Vutukuri
February 2008, Paperback


Excerpt from Professional Windows PowerShell Programming: Snapins, Cmdlets, Hosts and Providers

Extending Windows Powershell with Snap-ins

by Arul Kumaravel

Windows PowerShell provides an extensible architecture that allows new functionality to be added to the shell. This new functionality can be in the form of cmdlets, providers, type extensions, format metadata, and so on. A Windows PowerShell snap-in is a .NET assembly that contains cmdlets, providers, and so on. Windows PowerShell comes with a set of basic snap-ins that offer all the basic cmdlets and providers built into the shell. You write a snap-in when you want your cmdlets or providers to be part of the default Windows PowerShell. When a snap-in is loaded in Windows PowerShell, all cmdlets and providers in the snap-in are made available to the user. This model allows administrators to customize the shell by adding or removing snap-ins to achieve precise sets of providers and cmdlets. (Note, however, that PowerShell built-in snap-ins, such as Microsoft.PowerShell.Host, cannot be removed.)

This article shows you step by step, how to author, register, and use both types of snap-ins. To make it more meaningful, the code examples also show the minimum coding needed for authoring cmdlets.

Note that all code examples in this article are written in C#. The code examples for this article are available from the code download page for the book, Professional Windows PowerShell Programming: Snapins, Cmdlets, Hosts and Providers (Wrox, 2008, ISBN: 978-0-470-17393-0).

Types of PowerShell Snap-ins

Any .NET assembly becomes a Windows PowerShell snap-in when the assembly implements a snap-in installer class. Windows PowerShell supports two distinct types of snap-in installer classes. The default recommended type is PSSnapin, which registers all cmdlets and providers in a single contained assembly. That's the type of snap-in you'll create in this article. The second type is CustomPSSnapin, which enables developers to specify the list of cmdlets and providers from either a single or multiple assemblies.

Creating a Standard PowerShell Snap-in

You can extend Windows PowerShell by writing your own cmdlets and providers. Before you can use those cmdlets and providers with PowerShell, however, you need to register them as PowerShell snap-ins. Chapters 4 and 5 of the book, Professional Windows PowerShell Programming: Snapins, Cmdlets, Hosts and Providers (Wrox, 2008, ISBN: 978-0-470-17393-0), describe in detail how to write cmdlets and providers. This section explains how to author and use your PowerShell snap-in.

Several steps are involved in developing and using a standard PowerShell snap-in. First, you need to write some code for your snap-in and compile the code into a .NET assembly. Second, you need to register the assembly as a snap-in with the PowerShell platform. Registering a snap-in only tells PowerShell where a snap-in is. Before you can use the cmdlets or providers in your snap-in, you need to load the snap-in into a PowerShell session. After a snap-in is loaded, you can use cmdlets or providers in your snap-in just like other built-in native cmdlets and providers. To avoid the need to manually load a snap-in every time you start Windows PowerShell, you can save your loaded snap-ins into a configuration file for use later, or you can explicitly load a snap-in from your PowerShell profile script. The following sections explain in further detail each of the aforementioned steps.

Writing a PowerShell Snap-in

If you want to create a snap-in to register all the cmdlets and providers in a single assembly, then you should create your own snap-in class, inheriting from the PSSnapIn class, and add a RunInstaller attribute to the class, as illustrated in the following sample code:

// Save this to a file using filename: PSBook-2-1.cs

using System;
using System.Management.Automation;
using System.ComponentModel;

namespace PSBook.Chapter2
{
   [RunInstaller(true)]
   public class PSBookChapter2MySnapIn : PSSnapIn
   {
       // Name for the PowerShell snap-in.
       public override string Name
       {
           get
           {
               return "Wiley.PSProfessional.Chapter2";
          }
      }

      // Vendor information for the PowerShell snap-in.
       public override string Vendor
       {
           get
           {
               return "Wiley";
           }
       }

       // Description of the PowerShell snap-in
       public override string Description
       {
           get
           {
               return "This is a sample PowerShell snap-in";
         }
     }
  }
   
   // Code to implement cmdlet Write-Hi
    [Cmdlet(VerbsCommunications.Write, "Hi")]
    public class SayHi : Cmdlet
    {
        protected override void ProcessRecord()
        {
          WriteObject("Hi, World!");
        }
    }

    // Code to implement cmdlet Write-Hello
    [Cmdlet(VerbsCommunications.Write, "Hello")]
    public class SayHello : Cmdlet
    {
         protected override void ProcessRecord()
         {
            WriteObject("Hello, World!");
         }
    }
}

System.Management.Automation comes with the PowerShell SDK, which can be downloaded from the Web. System.Management.Automation is also available on all systems on which Windows PowerShell is installed; on my machine, it is installed at C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35. It inherits from System.ComponentModel, which comes with the .NET Framework, which is why it works with the installer in .NET through installutil.exe, a tool that .NET provides for installing or uninstalling managed applications on a computer.

For each snap-in, it is required to add a public Name property. At snap-in registration time, a Registry key is created using the snap-in name as a key name. The snap-in name is also used to add or remove the snap-in. To avoid potential name collision, we recommend using the following format to specify snap-in names: <Company>.<Product>.<Component>. For example, the built-in PowerShell snap-ins are named as follows:

PS E:\PSbook\CodeSample> get-pssnapin | format-list Name
Name : Microsoft.PowerShell.Core
Name : Microsoft.PowerShell.Host
Name : Microsoft.PowerShell.Management
Name : Microsoft.PowerShell.Security
Name : Microsoft.PowerShell.Utility

The other required public property is Vendor. In the preceding example, the vendor is Wiley. Optionally, you can add a public Description property and other properties.

The preceding example also included code for two cmdlets: Write-Hi and Write-Hello. These are included for illustration purposes. For more information on how to write cmdlets, see Chapter 4 of the book, Professional Windows PowerShell Programming: Snapins, Cmdlets, Hosts and Providers. For this simple example, all code is put in a single .cs file because it is very simple. In practice, you will likely use a separate file for your snap-in class and other cmdlets and provider classes.

Compile the sample code from Visual Studio or use the following command-line option to create an assembly PSBook-2-1.dll:

csc /target:library /reference:.\System.Management.Automation.dll PSBook-2-1.cs

With that, you have created your first PowerShell snap-in. Note that you need to have the .NET Framework installed in order for this to work. Both Csc.exe and installutil.exe come with the .NET Framework. Csc.exe is a C# compiler. I have the .NET Framework 2.0 installed on my 32-bit machine, and csc.exe and installutil.exe can be found at the following location:

C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe
C:\Windows\Microsoft.NET\Framework\v2.0.50727\installutil.exe

On a 64-bit operating system, you can find them at this location:

C:\Windows\Microsoft.NET\Framework64\v2.0.50727\csc.exe
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\installutil.exe

The path to csc.exe on your machine could be different depending on what version of the .NET Framework you install and how your system is configured. If it is not there and you have the .NET Framework installed, you can use the following PowerShell command to find the path:

Get-ChildItem -Recurse -path ${env:systemroot} -Include csc.exe

In any case, make sure the locations of csc.exe and installutil.exe are included in your path. In addition, you may need to adjust the relative path to System.Management.Automation.dll if it is not in the same folder as the C# files.

In order to use a snap-in, you must register it with PowerShell first.

Registering Your PowerShell Snap-in

To register a PowerShell snap-in like the one shown in the preceding section, you can use installutil.exe. InstallUtil.exe comes with the .NET Framework. You can use the PowerShell command line mentioned earlier to find the path:

Get-ChildItem -Recurse -path ${env:systemroot} -Include installutil.exe

You must have administrator privileges in order to run installutil.exe. On Windows Vista, you can right-click on the Windows PowerShell icon and select Run as Administrator. Here is the command to register the preceding snap-in, assuming installutil.exe is in your path:

E:\PSbook\CodeSample>installutil PSBook-2-1.dll
Microsoft (R) .NET Framework Installation utility Version 2.0.50727.312
Copyright (c) Microsoft Corporation. All rights reserved.


Running a transacted installation.

Beginning the Install phase of the installation.
See the contents of the log file for the E:\PSbook\CodeSample\PSBook-2-1.dll assembly's progress.
The file is located at E:\PSbook\CodeSample\PSBook-2-1.InstallLog.
Installing assembly 'E:\PSbook\CodeSample\PSBook-2-1.dll'.
Affected parameters are:
   logtoconsole =
   assemblypath = E:\PSbook\CodeSample\PSBook-2-1.dll
   logfile = E:\PSbook\CodeSample\PSBook-2-1.InstallLog

The Install phase completed successfully, and the Commit phase is beginning.
See the contents of the log file for the E:\PSbook\CodeSample\PSBook-2-1.dll assembly's progress.
The file is located at E:\PSbook\CodeSample\PSBook-2-1.InstallLog.
Committing assembly 'E:\PSbook\CodeSample\PSBook-2-1.dll'.
Affected parameters are:
   logtoconsole =
   assemblypath = E:\PSbook\CodeSample\PSBook-2-1.dll
   logfile = E:\PSbook\CodeSample\PSBook-2-1.InstallLog

The Commit phase completed successfully.
The transacted install has completed.

Depending on the information you implement for the snap-in installer, the following registry information may be created when you register a snap-in:

  • A Registry key with SnapinName, which was defined in the PSSnapIn class, will be created under HKLM\Software\Microsoft\PowerShell\1\PowerShellSnapIns.
  • A set of values may be created under this SnapinName key.

The following table lists the possible value names, including data types, whether it is optional or required, and a description of each value.

NAME TYPE OPTIONAL OR REQUIRED DESCRIPTION
ApplicationBase REG_SZ Required Base directory used to load files needed by the PSSnapIn such as type or format files
AssemblyName REG_SZ Required Strong name of PSSnapIn assembly
ModuleName REG_SZ Required Path to assembly if the PSSnapIn assembly is not stored in GAC
PowerShellVersion REG_SZ Required Version of PowerShell used by this PSSnapIn
Types REG_MULTI_SZ Optional Path of files, which contains type information for this PSSnapIn. It can be an absolute or relative path. A relative path is relative to the ApplicationBase directory.
Formats REG_MULTI_SZ Optional Path of files, which contains type information for this PSSnapIn. It can be an absolute or relative path. A relative path is relative to the ApplicationBase directory.
Description REG_SZ Optional Non-localized string describing the PSSnapIn. If this information is not provided, an empty string is used as a description of the PSSnapIn.
DescriptionIndirect REG_SZ Optional Resource pointer to localized PSSnapIn description. This should be in the following format: ResourceBaseName,ResourceId. If this information is not provided, a language-neutral description string is used as a description for the PSSnapIn.
Vendor REG_SZ Optional Vendor name for the PSSnapIn. If this information is not provided, an empty string is used as vendor name for the PSSnapIn.
VendorIndirect REG_SZ Optional Resource pointer to the localized PSSnapIn vendor name. This should be in the following format: ResourceBaseName,ResourceId. If this information is not provided, a language-neutral vendor string is used as vendor of the PSSnapIn.
Version REG_SZ Optional Version for the PSSnapIn
CustomPSSnapInType REG_SZ Optional Name of the class that contains Custom PSSnapIn information

When a snap-in is registered, the DLLs referenced are loaded when used, so make sure you do not register DLLs from a temporary directory; otherwise, when the DLLs are deleted, PowerShell will fail to find and load the DLLs for the snap-in later.

Loading a PowerShell Snap-in to a Running Shell

Installutil.exe only puts information about a snap-in into the Windows Registry. In order to use cmdlets and providers implemented in a snap-in, you need to load the snap-in into PowerShell, which is done through another PowerShell cmdlet, Add-PSSnapIn, as shown in the following:

PS E:\PSbook\CodeSample> add-pssnapin PSBook-Chapter2-SnapIn

You can verify that the snap-in is loaded using the cmdlet Get-PSSnapIn without the parameter –registered:

PS E:\PSbook\CodeSample> get-pssnapin
Name        : Wiley.PSProfessional.Chapter2
PSVersion   : 1.0
Description : This is a sample PowerShell snap-in

You also can verify that the snap-in assembly is loaded with the following:

PS E:\PSbook\CodeSample> (get-process -id $pid).modules | where-object {$_.filename -like "*PSBook*"}
   Size(K) ModuleName               FileName
   ------- ----------               --------
        32 PSBook-2-1.dll           E:\PSbook\CodeSample\PSBook-2-1.dll

Figure 1
Figure 1

Just like built-in cmdlets, you can use get-command to list them. In Figure 1, a wild char is used to list all the cmdlets with the verb "write" and any noun starting with the letter "h". As expected, the two cmdlets we just implemented in the snap-in Write-Hello and Write-Hi are listed, along with the built-in cmdlet Write-Host. Then we invoked the cmdlets Write-Hi and Write-Hello, just as we would invoke a built-in cmdlet, and they worked as expected. In fact, as you type the cmdlet name, you can use tab-completion. Give that a try and see for yourself.

Saving Snap-in Configuration

As you have seen, you need to use add-pssnapin to load the assembly of a snap-in into PowerShell before you can use the cmdlets, providers, and so on, in the snap-in. To avoid typing add-pssnapin commands for each snap-in after you start PowerShell, you can save the loaded snap-ins into a configuration file for use later. This can be done using the Export-Console cmdlet, as shown in the following example:

PS E:\PSbook\CodeSample\PSBook> export-console MyConsole

After running the preceding command, the file MyConsole.psc1 is created in the folder. MyConsole.psc1 is an XML file that lists all the currently loaded snap-ins. The following code shows a sample configuration XML file:

<?xml version="1.0" encoding="utf-8"?>
<PSConsoleFile ConsoleSchemaVersion="1.0">
  <PSVersion>1.0</PSVersion>
  <PSSnapIns>
    <PSSnapIn Name="Wiley.PSProfessional.Chapter2" />
  </PSSnapIns>
</PSConsoleFile>

Starting PowerShell with a Saved Snap-in Configuration

To use the console file created earlier, you can start PowerShell.exe with the –psconsolefile option, as shown here:

E:\PSbook\CodeSample\PSBook>powershell -psconsolefile MyConsole.psc1

From the shell, using the following command, you can verify that the configuration files are used to create the shell:

PS E:\PSbook\CodeSample\PSBook> $consolefilename
E:\PSbook\CodeSample\PSBook\MyConsole.psc1

$consolefilename is a read-only variable containing the configuration file name used for the PowerShell session. You can also verify that the snap-ins specified in the configuration file (is this case, the Wiley.PSProfessional.Chapter2 snap-in) are actually loaded using the get-pssnapin cmdlet:

PS E:\PSbook\CodeSample\PSBook> get-pssnapin

Name        : Wiley.PSProfessional.Chapter2
PSVersion   : 1.0
Description : This is a sample PowerShell snap-in

Note that configuration files created by Export-Console are for use on the same machine where the files are created. If you want to use the same configuration file for other machines, you need to ensure that the PSSnapins specified in the configuration file have been registered on those machines.

This article is excerpted from Chapter 2, "Extending Windows Powershell" of the book, Professional Windows PowerShell Programming: Snapins, Cmdlets, Hosts and Providers (Wrox, 2008, ISBN: 978-0-470-17393-0,) by Arul Kumaravel, Jon White, Michael Naixin Li, Scott Happell, Guohui Xie, Krishna C. Vutukuri. Arul Kumaravel is currently the Development Manager of the Windows PowerShell team. He has worked with this team since its early days and led the team in shipping of version 1 of the product, and is presently leading the development of next version of PowerShell. Fascinated by computers from an early age when he first learned programming using BASIC, he went on to get his Master of Science degree in Computer Science from both the College of Engineering, Madras, India, and the University of Iowa. As a Microsoft intern, he wrote the first JavaScript/VBScript debugger for Internet Explorer 3, and was impressed by the potential to make a difference in millions of people's lives by working for Microsoft. He has been working at Microsoft for past 11 years in various groups, shipping multiple versions of products, including Internet Explorer, the Windows operating system, and Content Management Server, and has even dabbled with Software as a Service with small business online services. More recently, attracted by the business side of technology, Arul has taken on the arduous task of pursuing his M.B.A. at the Wharton Business School.