PowerShell Modules: Install, Import, and Create Your Own

Once you’ve written a handful of useful functions, the natural next step is making them available in every PowerShell session — without copy-pasting them into every script. That’s what PowerShell modules do: they bundle related functions into a single importable unit that can be shared, versioned, and published. This guide covers how modules work, how to install them from the PowerShell Gallery, how to create your own .psm1 module, and how to write a proper manifest.
What Is a Module (.psm1 vs .psd1)
A PowerShell module is a folder containing at least one file:
- .psm1 (Script Module) — A PowerShell script file containing function definitions. This is the module’s code.
- .psd1 (Module Manifest) — A data file that describes the module: version, author, dependencies, and which functions to export. Optional but strongly recommended.
- The folder name must match the
.psm1and.psd1filename.
PowerShell discovers modules from paths listed in the $env:PSModulePath environment variable. The typical user module path is C:\Users\Username\Documents\PowerShell\Modules for PowerShell 7+ or C:\Users\Username\Documents\WindowsPowerShell\Modules for Windows PowerShell 5.1.
Installing from PowerShell Gallery
The PowerShell Gallery (powershellgallery.com) hosts thousands of community and Microsoft modules. Install them with Install-Module:
# Install a module for the current user (no admin required)
Install-Module -Name Pester -Scope CurrentUser
# Install for all users (requires admin)
Install-Module -Name Az -Scope AllUsers
# Install a specific version
Install-Module -Name PSReadLine -RequiredVersion 2.3.4 -Scope CurrentUser
# Trust the gallery to avoid the prompt
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module -Name ImportExcel -Scope CurrentUser
Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository,
change its InstallationPolicy value by running the Set-PSRepository cmdlet. Are you sure
you want to install the modules from 'PSGallery'?
[Y] Yes [A] Yes to All [N] No ...
The “untrusted repository” prompt appears on first install unless you set the policy. For automation scripts, add -Force to suppress the prompt after trusting the repository.
Import-Module and Auto-Import
In PowerShell 3+, modules in standard PSModulePath locations auto-import when you call a function from them. You can also import explicitly:
# Explicit import
Import-Module -Name Pester
# Import with verbose output to debug issues
Import-Module -Name MyModule -Verbose
# Check what's loaded
Get-Module
# Import a specific version
Import-Module -Name Az -RequiredVersion 9.0.0
# Remove a module from the session
Remove-Module -Name Pester
VERBOSE: Loading module from path 'C:\Users\Alice\Documents\PowerShell\Modules\Pester\5.4.1\Pester.psd1'.
Creating a Simple .psm1 Module
Create a folder and a .psm1 file with your functions:
# Create module folder structure
$modulePath = "$env:USERPROFILE\Documents\PowerShell\Modules\MyTools"
New-Item -ItemType Directory -Path $modulePath -Force
# Create the module file
$moduleContent = @'
function Get-SystemHealth {
[CmdletBinding()]
param()
$os = Get-CimInstance Win32_OperatingSystem
$disk = Get-PSDrive C
[PSCustomObject]@{
FreeMemoryGB = [math]::Round($os.FreePhysicalMemory / 1MB, 2)
DiskFreeGB = [math]::Round($disk.Free / 1GB, 2)
Uptime = (Get-Date) - $os.LastBootUpTime
}
}
function Get-LogErrors {
param([string] $Path = 'C:\Logs')
Get-ChildItem -Path $Path -Filter '*.log' |
Select-String -Pattern 'ERROR' |
Select-Object Filename, LineNumber, Line
}
'@
Set-Content -Path "$modulePath\MyTools.psm1" -Value $moduleContent -Encoding UTF8
# Import it
Import-Module MyTools
Get-SystemHealth
FreeMemoryGB DiskFreeGB Uptime
------------ ---------- ------
3.82 47.23 3.05:14:22.1234567
Writing a Module Manifest (.psd1)
Generate a manifest with New-ModuleManifest:
New-ModuleManifest `
-Path "$modulePath\MyTools.psd1" `
-RootModule 'MyTools.psm1' `
-ModuleVersion '1.0.0' `
-Author 'Your Name' `
-Description 'System health and log utilities' `
-FunctionsToExport @('Get-SystemHealth', 'Get-LogErrors') `
-PowerShellVersion '5.1'
Exporting Functions with Export-ModuleMember
Add Export-ModuleMember at the bottom of your .psm1 to explicitly control what’s public. Without it, all functions are exported by default:
# At the bottom of MyTools.psm1
# Private helper — not exported
function ConvertTo-FormattedBytes {
param([long] $Bytes)
'{0:N2} MB' -f ($Bytes / 1MB)
}
# Only export these
Export-ModuleMember -Function 'Get-SystemHealth', 'Get-LogErrors'
Common Errors and Fixes
-
Module not found — PSModulePath not including custom folder: Run
$env:PSModulePath -split ';'to see where PowerShell looks. If your module folder isn’t listed, add it:$env:PSModulePath += ";C:\MyModules". To persist this across sessions, set it in your PowerShell profile. -
Execution policy blocking module import: If
Import-Modulefails with “cannot be loaded because running scripts is disabled,” set the execution policy:Set-ExecutionPolicy RemoteSigned -Scope CurrentUser.
Related Cmdlets / See Also
Wrapping Up
Modules are how PowerShell professionals share and reuse code. Start with a .psm1 file and a matching folder name, add a manifest for versioning, and install from the Gallery to tap into thousands of ready-made tools. Use Export-ModuleMember to keep internal helpers private. Your next step: take your best utility functions and package them into your first personal module.


