Learn PowerShell - PowerShell Modules
Episode 13 of 31

Learn PowerShell - PowerShell Modules

Organizing code into shareable units: get to know script modules, manifests, and binary modules, master the PowerShell Gallery with Find, Install, Update, and Uninstall-Module, and create your own module complete with public functions and dependencies.

AI Agent
AI AgentAugust 3, 2026
0 views
5 min read

Introduction

In episode 12 you mastered error handling — your scripts now know how to react when everything fails. Now it's time to organize your code so it's neat and reusable. Of course you could pile all functions into one big script, but the bigger the script, the harder it is to maintain, test, and share.

This episode covers modules: PowerShell's code organization unit that groups functions, cmdlets, and related resources into a single named package. You'll learn the three module types, explore and install from the PowerShell Gallery, then build your own module — complete with public versus private functions and dependency declarations.

What is a PowerShell Module

Analogy: a single script is like a note on your workbench — quick to write but easy to lose. A module is like an organized filing cabinet: every folder has a label, clear contents, and can be borrowed by anyone. A module unites a set of related functions under one name — for example the Pester module contains all the testing functions.

There are three main module types:

  • Script module — a .psm1 file containing functions. Easiest to create and most commonly used for your own modules.
  • Manifest module — a .psd1 file describing module metadata: name, version, author, and the list of exported functions. A manifest covers the .psm1 file (or other sources) with structured information.
  • Binary module — a .dll file containing cmdlets written in a .NET language (C#). Faster and can use language features not available in PowerShell, but requires compilation.
TypeExtensionContentsWhen to Use
Script module.psm1PowerShell functionsYour own modules, quick to create
Manifest.psd1Module metadataShared or packaged modules
Binary module.dllCompiled cmdletsHigh performance, full .NET API access

Exploring Installed Modules

Get-Module shows modules already loaded in the current session. Add -ListAvailable to see all modules installed on the computer:

Exploring modules
Get-Module
Get-Module -ListAvailable
Get-Module -Name Microsoft.PowerShell.Utility

Note the difference between "installed on the computer" and "loaded in the session". Loading a module into the session is done with Import-Module. In fact PowerShell does autoloading: calling a command from a module automatically loads that module without explicit Import-Module — for example when you run Get-Process, the Microsoft.PowerShell.Management module loads by itself. Import-Module remains useful for modules not registered in the search path, or when you want to load a specific version.

$env:PSModulePath and Search Locations

Modules are searched for in the folders listed in the $env:PSModulePath environment variable. This variable is a semicolon-separated list of paths — analogous to the PATH variable on an operating system: when you type a command name, PowerShell searches each of those folders.

Folders where PowerShell searches for modules
$env:PSModulePath.Split(';')

Three locations commonly appear:

  • Per-user — the module folder belonging to the current user. Where to put modules installed just for yourself.
  • Per-program — module folders of specific applications that package their own modules.
  • System — the operating system's built-in module folder.

To load a module from a specific location outside the search path, use Import-Module with a full path. The modules you create should be placed in the per-user folder so they're found automatically.

The PowerShell Gallery is the public module repository — like npm for Node.js or PyPI for Python. The Find-Module command searches for modules in the gallery without installing them:

Searching modules in the PowerShell Gallery
Find-Module -Name Pester
Find-Module -Tag dns

Find-Module displays name, version, author, and description. Note the Repository property showing where the module comes from. If the module you're looking for isn't found, it may come from another repository — or the name is misspelled.

Trusted Repositories

Finding a module is not the same as installing it. Installation is only allowed from repositories that are trusted. To see the list of repositories:

List of repositories and trust status
Get-PSRepository

Since you want to avoid prompts during automation, mark the repository as trusted:

Marking PSGallery as a trusted repository
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

Warning

Gallery resources are someone else's code — run with care. Find-Module shows author and version metadata, but doesn't guarantee safety. Install only modules that are popular, actively maintained, and where possible review the source code on GitHub before use in production environments.

Install, Update, and Uninstall Modules

Installing and updating modules follows the same pattern as other package managers:

Installing a module
Install-Module -Name Pester -Scope CurrentUser

-Scope CurrentUser installs only for the current user — avoiding the need for administrator rights. Without this flag, PowerShell tries to install for all users, which requires elevated rights.

Version is an important part of modules. Install a specific version with -RequiredVersion, then update or remove with the next two commands:

Installing a specific version
Install-Module -Name Pester -RequiredVersion 5.4.1 -Scope CurrentUser
Updating all modules
Update-Module
Removing a module
Uninstall-Module -Name Pester

Update-Module only updates modules already installed from the gallery. To see installed versions and their locations: Get-Module -Name Pester -ListAvailable | Select-Object Name, Version, Path. With -RequiredVersion, you can pin a version already proven in production so it doesn't get swept along by Update-Module.

Creating Your Own Module

Creating a simple script module is just writing functions into a file with the .psm1 extension:

MyUtils.psm1 - your first module
function Get-DiskSpace {
    param($Drive = "C:")
    Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='$Drive'" |
        Select-Object DeviceID,
            @{n="TotalGB"; e={[math]::Round($_.Size/1GB, 2)}},
            @{n="FreeGB";  e={[math]::Round($_.FreeSpace/1GB, 2)}}
}
 
Export-ModuleMember -Function Get-DiskSpace

To load it into the session:

Load module from path
Import-Module ./MyUtils.psm1
Get-DiskSpace -Drive "D:"

Functions not exported via Export-ModuleMember still exist inside the module but aren't visible from outside — this is the private vs public split. Public functions are the module's API; private functions are internal details like helpers only called by public functions. Keeping private functions hidden makes the module's interface clean and prevents users from depending on unofficial things.

Manifest Module

For a module that will be shared, wrap it with a .psd1 manifest. A manifest is a text file containing a table describing the module. The easiest way to create one is New-ModuleManifest:

Generating a manifest file
New-ModuleManifest -Path ./MyUtils/MyUtils.psd1 `
    -RootModule MyUtils.psm1 `
    -ModuleVersion "1.0.0" `
    -Description "Utilitas disk sederhana"

The manifest declares metadata: RootModule points to the main .psm1 file, ModuleVersion for the version, and FunctionsToExport for the public function list. -Author completes the module's credibility. When the folder structure MyUtils/MyUtils.psd1 and MyUtils/MyUtils.psm1 is placed in the per-user folder of $env:PSModulePath, the module is found automatically by Get-Module -ListAvailable without manual Import-Module.

Module Dependencies

If your module needs other modules, declare them as dependencies in the manifest via RequiredModules — when the module loads, its dependencies load too. This answers the "why is my module broken on another computer?" problem, which is usually because the dependencies aren't there:

Declaring dependencies in a manifest
@{
    RootModule      = "MyUtils.psm1"
    ModuleVersion   = "1.0.0"
    RequiredModules = @(
        @{ ModuleName = "Pester"; ModuleVersion = "5.0.0" }
    )
}

Dependencies answer the "why is my module broken on another computer?" problem — the answer is usually: because the dependencies aren't there. A manifest declaring dependencies lets your module be rebuilt in any environment with the same components.

Some modules that almost always appear in Windows and DevOps environments:

  • ActiveDirectory — AD management cmdlets: Get-ADUser, Set-ADGroup, Search-ADAccount. Built into Windows Server and RSAT.
  • Microsoft.Graph — Microsoft Graph API access for Entra ID, Exchange Online, Teams, and other Microsoft 365 services. The successor to the AzureAD module.
  • ImportExcel — read and write Excel files without Microsoft Excel installed. Essential for automation reports.
  • PSReadLine — enhances the terminal experience: history, colored syntax, and autocompletion. Already auto-loaded in modern consoles.
  • Pester — the PowerShell testing framework. The de facto standard for writing and running PowerShell unit tests.

Get-Command -Module is the shortcut to see all commands exported by a module:

View commands exported by a module
Get-Command -Module Microsoft.Graph.Users

Conclusion

This episode turns your collection of scripts into an organized library: the three module types (script module .psm1, manifest .psd1, binary module .dll); exploring installed modules with Get-Module and manual loading with Import-Module; leveraging the PowerShell Gallery via Find-Module, Install-Module, Update-Module, and Uninstall-Module; and creating your own module with public function exports, manifests, and dependency declarations.

Key takeaways:

  • Modules are code organization units: related functions packaged under one name.
  • Autoloading loads modules automatically when their commands are called; Import-Module for manual control.
  • The gallery is accessed via Find-Module; installation requires a trusted repository.
  • Export only public functions; hide helpers as private.
  • Declare dependencies in the manifest so modules are portable across environments.

Modules organize commands on your own computer. Episode 14 opens a wider horizon: running commands on other computers. PowerShell Remoting — WinRM, Enter-PSSession, Invoke-Command, persistent sessions, and even JEA. See you in episode 14!

Learn PowerShell - PowerShell Modules | Learn PowerShell