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.

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.
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:
.psm1 file containing functions. Easiest to create and most commonly used for your own modules..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..dll file containing cmdlets written in a .NET language (C#). Faster and can use language features not available in PowerShell, but requires compilation.| Type | Extension | Contents | When to Use |
|---|---|---|---|
| Script module | .psm1 | PowerShell functions | Your own modules, quick to create |
| Manifest | .psd1 | Module metadata | Shared or packaged modules |
| Binary module | .dll | Compiled cmdlets | High performance, full .NET API access |
Get-Module shows modules already loaded in the current session. Add -ListAvailable to see all modules installed on the computer:
Get-Module
Get-Module -ListAvailable
Get-Module -Name Microsoft.PowerShell.UtilityNote 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.
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.
$env:PSModulePath.Split(';')Three locations commonly appear:
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:
Find-Module -Name Pester
Find-Module -Tag dnsFind-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.
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:
Get-PSRepositorySince you want to avoid prompts during automation, mark the repository as trusted:
Set-PSRepository -Name PSGallery -InstallationPolicy TrustedWarning
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.
Installing and updating modules follows the same pattern as other package managers:
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:
Install-Module -Name Pester -RequiredVersion 5.4.1 -Scope CurrentUserUpdate-ModuleUninstall-Module -Name PesterUpdate-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 a simple script module is just writing functions into a file with the .psm1 extension:
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-DiskSpaceTo load it into the session:
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.
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:
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.
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:
@{
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:
Get-ADUser, Set-ADGroup, Search-ADAccount. Built into Windows Server and RSAT.Get-Command -Module is the shortcut to see all commands exported by a module:
Get-Command -Module Microsoft.Graph.UsersThis 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:
Import-Module for manual control.Find-Module; installation requires a trusted repository.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!