Once you’ve written your fair share of PowerShell scripts there ultimately comes a time in your career where you have a need to build a PowerShell module. PowerShell modules are a great way to group lots of different functionality around a single concept. Modules make your code easily transportable, shareable and usable. Just create the module and run Import-Module -Name MyModule and all your code is immediately available to you.
Once someone starts writing modules they sometimes forget an optional yet important feature of modules; the manifest. Think of a module manifest as the module metadata and dependencies. You can create a module without one but it’s never going to be considered “professional” without it. Writing a PowerShell module without a manifest is like leaving a single ingredient out of a cake recipe. The cake will still taste like cake but won’t actually taste good.
So what does a manifest actually do? A manifest has three primary purposes.
1.To store metadata about a module.
2.To enforce module requirements.
3.To allow certain functions and variables to remain private.
Do you think it’d be helpful to track changes in your code? I do. One way to do that is through versioning. Every time you add a function to your module, change a bit of code here or there to make a few bug fixes it’d be helpful to increment the version to indicate how active that module is. The version is one attribute that is stored in the module manifest.
Other attributes like module author, a description of the module, the company name and a copyright statement are also used in module manifest.
Although not as important as other aspects of a manifest it’s always informative when your sharing this module with the public and they’re able to run Get-Module and see all this information.
Module Requirement Enforcement
Have you ever written a script that depends on something else? Perhaps it depends on another PowerShell script somewhere or maybe a module. Maybe you’ve written the module in a certain version of PowerShell and know that the functionality will break if it is ran in a previous version. Instead of coding up these dependencies in the module itself a manifest is a way to easily add these requirements in with just a few lines.
Manifests allow you to enforce all kinds of different requirements. Need to ensure the module will only load with PowerShell v4? No problem. Just use PowerShell Version = ‘4’. How about ensuring that it only loads on x64 machines? Use ProcessorArchitecture = ‘Amd64’. In large projects, you’ll sometimes have lots of different modules. You might have various calls to functions in other custom modules inside of another module. In this case, you need to ensure that other modules are available and loaded as well. Again, that’s as easy as adding the RequiredModules = @() line and adding as many different modules names in the array as you need.
Other options includes things like DotNetVersion, RequiredAssemblies which is good for any custom C# stuff you might be doing and even ScriptsToProcess which allows you to automatically run various PS1 scripts before the module is imported.
Keeping Functions and Variables Private
Best practice function design dictates that a function should be small and do only one thing. It’s important not to force a single function to accomplish multiple things. Because of this, sometimes it’s beneficial to write “helper” functions. These are functions that the “main” functions rely on to run but will never be needed by the person actually using the module itself.
For example, if I create a module called FileSystem. This module’s purpose is to contain various custom functions around doing stuff with the file system on a computer. I might have functions called Get-DirectorySize, New-TextFile and Remove-Ace. These are functions that I want the module user to use. However, I also might have functions in the module called Get-ThisInternalThing or New-TempFile. I’d then call these functions inside of the “main” functions. These “helper” functions are of no use to the module user but should only be used the the module functions themselves.
When a module user imports my module I don’t want to even give them the option of seeing Get-ThisInternalThing or New-TempFile because, at least, it may confuse them and, at worst, it might cause some harm. With a manifest, I can make this happen. I could just add the functions into the FunctionsToExport line. I could then only add the appropriate functions there.
FunctionsToExport = ‘Get-DirectorySize’,’New-TextFile’,’Remove-Ace’
Once I do this I can then hide my internal functions from the module user so they won’t see these functions.
Modules can be built without manifests but as you can see there are a lot of benefits to creating one. I don’t ever recommend building a module and sharing it with others without first creating a an accompanying manifest. It will lead to less confusion and prevent problems when dependencies don’t exist on other systems. If you want your module to look professional always include a module manifest with your modules.