Tuesday, August 5, 2014

Getting Started with PowerShell Modules, Part 2

Modules

Just to recap, modules are the key to organizing you PowerShell code in a logical way. There are two ways to write modules:

  • .NET assemblies
  • PowerShell advanced functions

Which you use depends on what components you are interacting with and how easily you want your end users to be able to modify the finished product. In the last post, I covered .NET assemblies. In this post I will cover Advanced Functions.

Creating a PowerShell Advanced Function

PowerShell advanced functions are sometimes called script cmdlets and for good reason. Once you have created a .NET cmdlet, the pattern will be familiar.

function Verb-Noun {
    <#
        .SYNOPSIS
        Describe the function
        .DESCRIPTION
        Describe the function in more detail
        .EXAMPLE
        Give an example
        .EXAMPLE
        Give another example
        .PARAMETER ParameterName
        Describe the parameter here
    #>
    [CmdletBinding()]
    param (
         [Parameter(Mandatory=$True,
            ValueFromPipeline=$True,
            ValueFromPipelineByPropertyName=$True,
            HelpMessage='Some descriptive text here')]
        [string] $parameterName
    )

    begin { }
    process { }
    end { }
}

Of course, the begin, process and end correspond to BeginProcessing, ProcessRecord and EndProcessing methods, respectively. And that is it. Pretty straightforward.

Packaging an Advanced Function into a Module

Name the text file, that you wrote the advanced function in, with a .psm1 extension and place it in a directory of the same name. Seriously, that is it.

For example,

MyNewModule\MyNewModule.psm1

Importing Script Modules

Modules can be imported in the same three ways that scripts can be run: relative reference, absolute reference and by placing it in your path. However, the third is slightly different for modules than scripts.

Relative Reference

PS C:\SourceCode> Import-Module .\MyNewProject

Note that the actual .psm1 file is located in the MyNewProject folder. You do not need to specify it.

Absolute Reference

PS C:\SourceCode> Import-Module C:SourceCode\MyNewProject

Again, you do not specify the script itself, in the path.

Installing it in your Module Path

First, verify your module path by running the following:

PS C:\> $env:PSModulePath
C:\Users\swoogan\Documents\WindowsPowerShell\Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules\

The first path is specific to your logged in user. The second is a system wide path available to all users. Any additional paths may have been installed by third parties.

This leads to two possible options for you to install your module. You can either put it in a directory already present in your PSModulePath, or you can create a new location and add it to your path. I recommend using what is already there.

Here is an example of performing the installation:

PS C:\> $path = Join-Path -Path $env:PSModulePath.Split(';')[0] -ChildPath MyNewProject
PS C:\> mkdir $path

    Directory: C:\Users\csvingen\Documents\WindowsPowerShell\Modules

Mode        LastWriteTime      Length  Name
----        -------------      ------  ----
d----       8/1/2014   1:24 PM         MyNewProject

PS C:\> Copy-Item .\SourceCode\MyNewProject\* $path -Verbose
VERBOSE: Performing operation "Copy File" on Target "Item: C:\SourceCode\MyNewProject\MyNewProject.psm1
Destination: C:\Users\swoogan\Documents\WindowsPowerShell\Modules\MyNewProject\MyNewProject.psm1".

To make sure that you have installed your module correctly, run the following:

PS C:\> Get-Module -ListAvailable

    Directory: C:\Users\csvingen\Documents\WindowsPowerShell\Modules


ModuleType Name                                ExportedCommands
---------- ----                                ----------------
Script     MyNewProject                        {Verb-Noun}
Binary     Swoogan                             {Find-InFiles, grep}

...

Notice that the type of MyNewProject is script, indicating it is a script module and not a binary .NET module.. If you do not see your module, you know something has gone wrong with the installation.

Now it is much easier to import your cmdlets. You no longer need to figure out the relative path or keep track of a potentially long absolute path. You can simply use the name of the module’s folder. When first implementing, I like to import the module with the Verbose flag to ensure that I get what I am expecting:

PS C:\Users\csvingen> Import-Module MyNewProject -Verbose
VERBOSE: Importing cmdlet 'Verb-Noun'.

Testing and Debugging

There is one important thing to be aware of when it comes to debugging your script modules: re-importing the module into your existing session will not bring in changes that you have made. You need to remove the modules first:

Remove-Module MyNewProject

I like to write a Test.ps1 script, that I load in the PowerShell ISE, for testings:

Import-Module .\MyNewProject
Verb-Noun
Remove-Module MyNewProject

Notice that the import uses the relative path in this case, since installing it is reserved for a completed project. Also note that you import with a path, but remove with just the module name.

No comments:

Post a Comment