Toolmaking in the trenches: Modules

8 minute read

This is the absolute simplest blog post you will ever read on how to build a basic PowerShell module. I won’t be getting into advanced module building, automated testing, writing a build and deploy pipeline, or any of that because it isn’t relevant to most folks in the trenches and most of my module building experience is in the trenches.

Series recap

This post is the second in a series of blog posts that I’m doing on how to get started building PowerShell tools in between issue resolution, phone calls, and whatever else comes your way. This is going to be just the bare minimum you need to know to be able to successfully build tools for yourself and your colleagues. No frills or teasers, but I will be careful to mention areas that can be expanded on.

For this series I’m also going to make a few assumptions since you are here and reading this post: you definitely know some PowerShell and have written a few scripts, but you probably don’t have time to develop a whole module for every little thing you administer. If that sounds like you, then you are in the right place because those aren’t roadblocks! I want to introduce you to the simple process I used for building tools in PowerShell that I could easily share and use.

Modules

A module is a collection of PowerShell commands that fit together. A good example, from my experience, is the Active Directory module. It is the module that Microsoft maintains for managing Active Directory through PowerShell.

To find a list of all the modules on your computer:

Get-Module -ListAvailable

Or if you wanted to read Microsoft’s built in documentation on Modules:

Get-Help about_modules

What makes a module

Like I mentioned earlier, a module is made up of a collection of commands that all fit together somehow. I’m leaving their relation vague because I don’t want to limit the reasons for commands deciding to be together. Usually they serve the purpose of managing a single product or service, but you can throw together a collection of functions that you’ve written and call it MyFunctions. And you know what? That would be a module because you decided to call it one.

Naming your module

In coming up with a name for your module, the first thing you need to decide is who your audience is going to be. If you have an audience of 1, yourself, then call it GUIsDrool, or whatever the heck you want. The only person that is going to use it is you, so be creative.

Moving beyond your singular self audience, you have to start considering professional names. For instance, if you are developing a module for your friendly, neighborhood service desk, you might want to use your company name in the title. Or if you are developing a module to share with the world, you are going to want to do some research on other modules that do similar things and come up with a unique, professional name. But hey, I should stop trailing off out of scope.

In my work, I always seemed to end up managing an unfortunately large number of disparate systems. If you’re in the same boat, know that I feel for you, but there is still hope! I decided that instead of writing modules on a per-system basis and importing them as needed, I would throw everything into AnthonysFunctions and I’d only have to worry about one module. It also helped that I was usually the only PowerShell person in the departments I worked in, so anything PowerShell was my domain anyway.

Building your module files

Now that you’ve completed the most import phase, we need to meet the technical requirements to build a module. Beyond all of your functions, you need 2 additional files: The module manifest GUIsDrool.psd1 and the module file itself: GUIsDrool.psm1.

Building your manifest

A PowerShell module manifest file is the metadata for the module. The only requirement is that the .psd1 file has the same exact name as the .psm1 file, not counting the extension. It should, however, contain as much relevant data as you care to put in it. If you like using a copy/paste template, check out Microsoft’s docs on How to Write a PowerShell Module Manifest, they have an example at the bottom. However, if you prefer to use a built-in cmdlet, it is fairly easy:

$ManifestParams = @{
    Author = 'The PoSh Wolf'
    Copyright = '(c) 2018 Howell IT. All rights reserved.'
    Guid = (New-Guid).Guid
    Description = 'All of the cool functions written by The PoSh Wolf'
    ModuleVersion = '0.0.1'
    PowerShellVersion = '5.0'
    Path = 'C:\Path\To\GUIsDrool.psm1'
}
New-ModuleManifest @ManifestParams

There are many other parameters as well, be sure to check the help.

Building your module file

The .psm1 file is the file that runs when the module is imported. Typically, in a purely PowerShelll module, this is where all of the module’s functions are stored. The problem with that is that it makes it extremely difficult to debug, so you’ll see module projects that have all of their functions in separate files and then a build process that copies them all to a single .psm1 file.

Now if this is the file that runs when you import the module, you don’t need a build process, you need a way to import all of your module’s functions! So I like to create a directory for my custom functions and throw them all in there with the module files and include this snippet in my .psm1 file:

ForEach($PSScript in (Get-ChildItem -Path $PSScriptRoot\*.ps1)){
    . $PSScript.FullName
}
Export-ModuleMember -Function * -Alias *

This will import all of your .ps1 files in the directory that the .psm1 is inside of and export them as module members. It is very important all of the .ps1 files in this directory are files that you want to run when the module is imported. They should be functions or they should be scripts that need to do things to prepare for the module. Most likely you will only have functions.

Collecting your functions

Now that you have your modules files all figured out, you should hopefully have at least one function, assuming you read my last post on functions. If you need some more ideas on functions, check out my Utilities repository on Github or my TechSnips_Demos repository, it is my goal to share as much of my work as possible, but its been a slow start.

To make this easiest, your functions should all be in their own files named the same as the function itself and these files should all be in the same directory, preferably with the same name as your module, as the module files.

GUIsDrool module

Importing and testing

Now that you’ve got your module built, go ahead and import it using Import-Module:

Import-Module C:\Path\To\GUIsDrool.psm1

And you should be able to run all of your functions!

In closing

Modules are easy. They just sound difficult. I hope this gets you started on building your own modules and eventually you are writing and sharing your modules on GitHub! Maybe I should talk about Git next in my toolbuilding series?

If you liked this post, let me know! You can leave a comment, reach out on Twitter, email me, whatever. I appreciate feedback!

Leave a Comment