3

A Best Practice Guide To Creating A Powershell Module

Building a Powershell Module might be a daunting task for someone without much PS experience. But what if I told you, creating a module can be as simple as grouping multiple functions together and renaming the extension to psm1. It sounds a lot less complicated when you put it that way.

Say you’re working on a project to gather information for a specific system and you’ve created several individual functions in their own .ps1 file. You can simply consolidate all those functions into a module and import that module to make the commands available to you. More on that later. For now, let’s take a step back and cover the basics first.

 

What is a Function

A Function, which is what a module is comprised of, can be best described as a block of code that will run a specific task. They’re especially useful for running repetitive blocks of code without having to necessarily write the same code multiple times. We can simply call the function.

Furthermore, Functions are not specific to Powershell so we can think of it as something universal to any programming language. It is one of the most basic fundamental concepts you learn when getting into the programming world.

 
A while back I wrote a Powershell Template For Creating The Perfect Function which covers some of the most fundamental concepts for composing a function. Now we’re going to take that knowledge we learned from there and build on top of that.

How To Import and Call a Function

A big reason I like to create Powershell Modules instead of having the functions in their own file is the fact that modules are so much easier (and less complicated) to load. We’ll cover how to load a module later in the article, however let’s take a dive into how can we load a function.

In order to load a function in Powershell, we can accomplish this by dot sourcing the file. At first, I’ll admit it was kind of confusing and it took me a while to get the hang of it. Consequently as time went on I started growing my knowledge base and progressed from functions to modules. To summarize what dot sourcing looks like in code. I’ll use my Get-Something sample function.

PS C:\> . .\_Scripts\Get-Something.ps1
PS C:\> Get-Something

The Get-Something function was called
PS C:\>

Dot Sourcing a function

The caveat here is the use of relative or absolute paths. Whoa.. big words. Let’s say your script is in the C:\_Scripts directory as shown above and your current directory is the root of the C drive. The Relative path would be <dot> <space> <dot>\_Scripts\script.ps1. Alternatively, if you can use the absolute path regardless of what directory you’re in. An example would be <dot> C:\_Scripts\script.ps1.

 
Once the function is dot sourced (loaded into memory) you can now call the function with the intended parameters. Now that we know the basic concepts of loading a function and how to use it, let’s take the next step and look into modules.

What is a Module

Microsoft describes a module as a package that contains Powershell members, such as cmdlets, providers, functions, workflows, variables, and aliases. The members of this package can be implemented in a PowerShell script, a compiled DLL, or a combination of both. These files are usually grouped together in a single directory.

In simple terms, it’s a way to group existing code into a consolidated format for easier use.

How To Create A Powershell Module

As I mentioned earlier creating a Powershell Module is as simple as saving multiple [valid] functions into a single .psm1 file. Things can get much more complex when you dig deeper but I’m going to try relay the information as simply as I can.

Using our example above let’s say we have multiple functions called Get-Something, Set-Something and New-Something. We’re going to consolidate all those functions and save it into a single file called something.psm1. As an example, I’ll summarize that using a block of code.


Function Get-Something {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string] $UserPrincipalName
    )

    Write-Output "The Get-Something function was called"
}

Function Set-Something {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string] $UserPrincipalName
    )

    Write-Output "The Set-Something function was called"
}

Function New-Something {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string] $UserPrincipalName
    )

    Write-Output "The New-Something function was called"
}

Create a Powershell Module

 

How To Import and Call a Module

I’m sure many of you reading this have probably downloaded or used a module once or twice. Some of the most common ones are the ActiveDirectory module, the Exchange Online Powershell Module or other ones that can be used for your job. The major difference here is that it is so much easier to load a module so let’s take a look at how to do that.


PS C:\> Import-Module C:\_Scripts\Something.psm1
PS C:\>
PS C:\> Get-Something -UserPrincipalName [email protected]

The Get-Something function was called for [email protected]
PS C:\>
PS C:\> New-Something -UserPrincipalName [email protected]

The New-Something function was called for [email protected]
PS C:\>

Import-Module for Something tools

 

How To Find Commands In a Module

It’s important to know what’s generally available to you from a command perspective. This is the case whether you’re creating your own module or importing one from the internet.

To find what commands are available you can simply run the Get-Command cmdlet and specify the -Module parameter. Let’s take that to our code block and use our something.psm1 module as an example.

Get-Command -Module Something

Get Command Something

 

How To Auto Load A Module

Ever wonder how some modules can automatically be ran without you explicitly importing the module? We can bypass the import-module command by simply setting up the folder structure with the appropriate name.

In order to accomplish this, the module would need to be located in the $env:PSModulePath environment variable path. A subfolder needs to be created with the same name of the module name. Then, the .psm1 file needs to be inside that newly created folder. I’ll try to illustrate this with a drawing.

FolderTree

 

Different Locations In The PSModulePath

The $env:PSModulePath is built into Windows and has the ability to add or remove whatever folders you see fit. The reason for the environment variable is so that Windows can call any code from what ever directory you’re currently in.

Environment Variables

 
In our example above, I have the C:\_Scripts folder added to the module path. To check what is currently in the module path, we can open Powershell and run the command:

$env:PSModulePath.Split(';')

PSModulePath Powershell

By default, Windows typically has 3 locations automatically added to the Powershell Module Path.

  • C:\Users\<username>\Documents\WindowsPowerShell\Modules
    • This is scoped to the current user and not need administrator permissions to install here
  • C:\Program Files\WindowsPowerShell\Modules
    • This is scoped to all users and DOES need administrator permissions to install here
  • C:\Windows\system32\WindowsPowerShell\v1.0\Modules
    • This is scoped to all users and DOES need administrator permissions to install here

 

Get Available Modules On Your Computer

If you ever wanted to see how to get available modules on your computer you can do that with a simple command.

Get-Module -ListAvailable

Get-Module ListAvailable

Powershell adds this automatically since this is pulled from a collection of all modules that are located within your Module path environment variable.

 

Reloading a Module for Updated Code

An important thing to remember when building or adding to your own modules is that even though you save the .psm1 file, Powershell doesn’t know its updated until your reimport the module. Knowing this now will save you some headaches wondering why your code is still not working as intended. It still happens to me from time to time so it’s always a good reminder.

With that said, let’s look at how to reimport the module into Powershell. I’ll use my something.psm1 module as an example.

#To remove the module we'll run the following command.
Remove-Module Something

#To load the module again, we can explicitly reimport it
Import-Module Something

#-or- If the module is added to the $env:PSModulePath we can call a function within the module.
Get-Something -UserPrincipalName [email protected]

 

Powershell Module Manifest

The next logical step in creating a Powershell module is the ability to create a Module manifest. This is a separate file that’s used encompass the basic settings that are used by the module. The details of this and how to create one would actually require a different post so I’ll make sure to add that ones it’s completed.

 

Conclusion

Hopefully you were able to learn something about modules. Specifically how to create a Powershell module and how to add/update/remove one as needed. Once you get the hang of consolidating functions into a module it actually helps with the overall structure of your Powershell code.

By using the environment variables and placing the module in the Powershell Module Path, we can set our selves up for automation because it’s easier to call the functions within the modules.

If you want some more real world examples, be sure to check out our Powershell Gallery. It’s full of actual scripts that you can use in your organization.

Finally, don’t forget to check out our Youtube Page for sysadmin video content.

5/5 - (23 votes)

Paul Contreras

Hi, my name is Paul and I am a Sysadmin who enjoys working on various technologies from Microsoft, VMWare, Cisco and many others. Join me as I document my trials and tribulations of the daily grind of System Administration.

3 Comments

  1. Great article! Did you ever write an article about module manifests? We have many (many) scripts and we’re trying to come up with the best way to organize them so we can use them in Runbooks. I have a software development background so I’m trying to merge that with the powershell world. Thanks!

  2. Grouping all the functions into a single .psm1 file is probably the worst advice that can be given to someone starting out with modules. It is not difficult to understand a best practice approach to creating modules with public, private and tests folders.
    Module Folder
    module.psd1 – Manifest, can use New-ModuleManifest to create
    module.psm1 – Contains functions to import all .ps1 files into memory and export public functions
    public – Contains functions that are exported
    private – Contains internal module functions
    tests – Contains Pester unit tests for module

    To load all the .ps1 files from the module.psm1 file use:
    Get-ChildItem -Path $PSScriptRoot\private, $PSScriptRoot\public -Filter *.ps1 | ForEach-Object { . $_ }
    To export the public functions from the module.psm1 file use:
    Get-ChildItem -Path $PSScriptRoot\public\*.ps1 | ForEach-Object { Export-ModuleMember -Function $_.Basename }

    Then you just add new .ps1 files to the public or private folders to create new private or public functions.
    Yes your post was “basic”, but not providing the best practice approach is doing a disservice.

    • thank you so much, ive searched sooo many post trying to figure out why my module wouldnt load

Leave a Reply

Your email address will not be published.