Windows PowerShell: Sharing Your Scripts - Made Easy

Don Jones

One limitation of Windows PowerShell v1 is that it didn’t do much to make script sharing easier. Sure, you could easily copy a .ps1 script file to another computer, or even zip it up and e-mail it to a colleague, but you could do that with VBScript more than a decade ago. If your script included reusable functions, however, whoever received it from you would have to know how to dot-source it, or would wind up actually having to modify it in order to execute those functions.

All in all, it was an acceptable situation—even if it wasn’t ideal. The situation became less acceptable for scripts that were accompanied by custom format views or type extensions, because those additional files had to be manually loaded into the shell in order to be used by the script.

With Windows PowerShell v2, however, we’ve moved to a nearly ideal situation, thanks to the introduction of modules.

Self-Contained Chunks of Shell Goodness

A module is simply a collection of files that relate to one another. There are two broad categories of modules: Binary and Script.

A binary module consists of one or more DLL files, which are compiled from a Microsoft .NET Framework language like C# or Visual Basic. In the v1 days, we called these PSSnapins, and actually writing one in Visual Studio hasn’t changed much. Snapins, however, required that you also write an installer to register your DLL with the shell. With a module, no installation is necessary. Instead, the module is accompanied by a .psd1 file—a module manifest. The manifest is simply some XML that indicates which DLL(s) should be loaded. The manifest can also specify accompanying type extension files (.ps1xml) or view files (.format.ps1xml).

Here’s how it works: The module must be installed in a subdirectory within the Windows PowerShell \modules folder. By default, this is in c:\windows\system32\windowspowershell\v1.0\modules. So, a module named “MyModule” would go into c:\windows\system32\windowspowershell\v1.0\modules\mymodule, and the manifest file would be mymodule.psd1. Any files related to the module would normally be grouped into that same folder, keeping everything self-contained.

To load the module, you simply run Import-Module MyModule. The shell looks in the \modules folder by default (though you can also pass a complete path to Import-Module if your module is located elsewhere), sees that a .psd1 file exists, reads it and loads the files referenced within. Distributing the module is easy: Just zip up all the files and copy the .zip file to another computer—no installation necessary.

Roll Your Own Modules

So how does this help you distribute your scripts more easily? The second type of module, a script module, is the answer. This is simply a normal Windows PowerShell script, with a .psm1 filename extension rather than the usual .ps1 filename extension. Putting mymodule.psm1 into the \modules folder allows you to run Import-Module MyModule, and your script will execute.

Normally, a script module consists entirely of functions. That is, when the module is imported, nothing actually executes—the functions within the script module are loaded into the shell, and become available throughout the shell. Suppose you have a script module that looks something like this:

Function Get-Inventory {
 # (some code goes here)
}
Function Test-Connectivity {
 # (some code goes here)
}
Function Write-Inventory {
 # (some code goes here)
}

Importing this module would make the Get-Inventory, Test-Connectivity and Write-Inventory functions available throughout the shell, much like cmdlets (in fact, next month, I’ll show you how to write a function that behaves almost exactly like a “real” cmdlet). Your functions can even include comment-based help (which I demonstrated in my last column), so someone could import the module and run Help Get-Inventory to see instructions for using that function.

Sometimes You Want a Little Privacy

Sometimes you may have a complicated script module that includes functions intended to be used only by other functions, rather than by a user. For example, I might intend Test-Connectivity and Write-Inventory to be “private” to the module. That means they would be called by Get-Inventory, but I don’t expect them to be called directly by a user of the shell.

By default, Import-Module imports everything in the module, making every function visible to the shell user. You can override that behavior by simply specifying a list of the functions you intend to be visible; everything else will be hidden from the shell user. To do so, just execute Export-ModuleMember at the end of your script module:

Export-ModuleMember –function Get-Inventory

You can also export cmdlets, variables and aliases that your script defines, if needed. Run Help Export-ModuleMember, or see Export-ModuleMember for more details.

Module Downsides

For me, the only bummer about v2 modules is that the shell seemed to have only one default location for them, and that location is under the Windows system folder—which isn’t something you want to get into the habit of modifying. But then I looked at the PSModulePath environment variable and discovered that the shell will also look in your Documents folder, under a subfolder called WindowsPowerShell\Modules, and this is where I now keep all of the modules I write.

In the future, you may well see cmdlets designed to download additional modules from Internet-based repositories, not unlike the Pear functionality used in Unix systems. Such cmdlets would be more likely to download to your Documents folder or some other non-OS location, and having the shell search your Documents folder for modules is a smart default.

Modules, Modules, Everywhere

Because they don’t require installation in order to be “seen” by the shell, modules are being used a lot more. In fact, almost every Windows PowerShell extension in Windows Server 2008 R2 is packaged as a module—the only exception being the PSSnapin for automating Windows Server Backup (run Get-PSSnapin –registered to see if it’s installed on a server). More third-party code is being shipped as modules, too, including the cmdlets that access the community code repository at PoshCode.org.

In fact, if you’re a hardcore Windows PowerShell user interested in writing your own cmdlets, but don’t want to dig into .NET Framework programming in Visual Studio, the combination of advanced functions (again, that’ll be next month’s column) and modules gives you the ability to write your own shell “snapins” entirely in script. Just package your advanced functions—which look and act like cmdlets—into a script module, and you have an easy-to-distribute library of reusable code.

Windows PowerShell v2 Now Generally Available

Although it shipped preinstalled with Windows Server 2008 R2 and Windows 7, Windows PowerShell v2—and its companion Management Framework components—is now available for Windows XP, Windows Server 2003, Windows Vista and Windows Server 2008. Just visit support.microsoft.com/kb/968929 to get the download link for whatever OS you’re using. In most cases, this should be compatible with your v1 scripts; my future columns will assume you’re using 2.0.

Don Jones* is a founder of Concentrated Technology, and answers questions about Windows PowerShell and other technologies at ConcentratedTech.com. He’s also an author for Nexus.Realtimepublishers.com, which makes many of his books available as free electronic editions.*

·      Windows PowerShell: PowerShell and Active Directory

·      Windows PowerShell: Filter Left, Format Right

·      Windows PowerShell: Stay Seated