Modules and the PowerShell Gallery

Reviewed & published by Brayan K

By the end of this lesson you'll load and discover modules, pull ready-made tools from the PowerShell Gallery with Find-Module and Install-Module, understand where PowerShell looks for modules, and package your own functions into a reusable .psm1 with a .psd1 manifest — turning loose scripts into shareable tools.

Part of the free PowerShell course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

What You'll Learn

💡 Real-World Analogy

A module is an app on your phone. The PowerShell Gallery is the app store: you Find-Module to browse, Install-Module to download, and Update-Module to upgrade. Once installed, the app's features appear automatically when you reach for them (that's auto-loading via $env:PSModulePath). And when you build something useful, you can package it like an app developer: a .psm1 holds the code, a .psd1 manifest is the "store listing" (name, version, author), and Export-ModuleMember decides which buttons are public.

1. Loading & Discovering Modules

A module bundles related commands into one reusable package. Get-Module shows what's loaded; add -ListAvailable to see everything installed. Import-Module loads one into your session, and Get-Command -Module <name> lists exactly what it provides. Read this worked example, then run it.

# A MODULE is a package of related commands you can load and reuse.

# See what's currently loaded:
Get-Module

# See everything INSTALLED on the machine (loaded or not):
Get-Module -ListAvailable | Select-Object -First 3 Name, Version

# Load a module so its commands become available this session:
Import-Module Microsoft.PowerShell.Archive

# List the commands a module provides:
Get-Command -Module Microsoft.PowerShell.Archive

2. The PowerShell Gallery

The PowerShell Gallery is the official public repository of community and Microsoft modules. Find-Module searches it without installing anything, Install-Module downloads and installs (use -Scope CurrentUser when you're not an administrator), and Update-Module upgrades to the latest version. Installed modules live on $env:PSModulePath, which is why PowerShell can auto-load them the moment you call one of their commands.

# The PowerShell Gallery (powershellgallery.com) is the public package repo.

# 1) Find a module online WITHOUT installing it:
Find-Module -Name PSScriptAnalyzer

# 2) Install it (use -Scope CurrentUser if you're not an admin):
Install-Module -Name PSScriptAnalyzer -Scope CurrentUser

# 3) Update it later to the newest version:
Update-Module -Name PSScriptAnalyzer

# 4) PowerShell auto-loads installed modules from PSModulePath when you
#    first call one of their commands — no Import-Module needed:
$env:PSModulePath -split ';'

Now you try. Fill in the three blanks using the hints in the comments, then run it.

# 🎯 YOUR TURN — replace each ___ then run it.
# Goal: find the 'Pester' module online, then install it just for you.

# 1) Search the Gallery for Pester (no install yet)
___ -Name Pester                      # 👉 the search cmdlet is: Find-Module

# 2) Install it for the current user only
___ -Name Pester -Scope CurrentUser   # 👉 the install cmdlet is: Install-Module

# 3) Confirm it's available
Get-Module -ListAvailable -Name ___   # 👉 the module name is: Pester

# ✅ Expected: Find-Module shows a version, Install-Module downloads it,
#    and Get-Module -ListAvailable lists Pester.

3. Authoring Your Own Module

Turning your functions into a module is straightforward. Put the code in a .psm1 file, then call Export-ModuleMember to declare which functions are public (anything you don't export stays a private helper). Describe the module with a .psd1 manifest — a metadata file holding the version, author, RootModule, and exported members — which you can scaffold with New-ModuleManifest.

# === Author your own module ===

# 1) Put your functions in a .psm1 file, e.g. MyTools.psm1
#    -------------------- MyTools.psm1 --------------------
function Get-Greeting { param([string]$Name) "Hello, $Name!" }
function Get-Secret   { "internal helper - not for export" }

# Export ONLY the public function (Get-Secret stays private):
Export-ModuleMember -Function Get-Greeting
#    ------------------------------------------------------

# 2) Describe it with a MANIFEST (.psd1). New-ModuleManifest scaffolds one:
New-ModuleManifest -Path .\MyTools.psd1 `
    -RootModule 'MyTools.psm1' `
    -ModuleVersion '1.0.0' `
    -Author 'You' `
    -FunctionsToExport 'Get-Greeting'

# 3) Import it and use it:
Import-Module .\MyTools.psd1
Get-Greeting -Name 'Ada'
Get-Command -Module MyTools

Pro Tip

List your exports explicitly in the manifest's FunctionsToExport (and use Export-ModuleMember in the .psm1) rather than relying on the * wildcard. Explicit exports load faster — PowerShell can read the manifest without executing the whole module — and they keep private helpers truly private.

Putting It Together: where modules live

To make a module auto-load like a Gallery one, drop its folder (named the same as the module) into any directory on $env:PSModulePath — most commonly your Documents\PowerShell\Modules folder. Then any command it exports just works, no Import-Module required.

# See every folder PowerShell scans for modules:
$env:PSModulePath -split [System.IO.Path]::PathSeparator

# Your personal modules folder (first on the list) is the easiest place
# to drop a MyTools\ folder so 'Get-Greeting' auto-loads next session.
$personal = ($env:PSModulePath -split [System.IO.Path]::PathSeparator)[0]
"Drop modules here: $personal"

The folder name, the .psm1 base name, and the manifest base name should all match the module name so auto-loading can find it.

Common Errors (and the fix)

📋 Quick Reference — Modules

CmdletPurposeExample
Get-ModuleList loaded / availableGet-Module -ListAvailable
Import-ModuleLoad into sessionImport-Module Pester
Find-ModuleSearch the GalleryFind-Module Az
Install-ModuleDownload & installInstall-Module Az -Scope CurrentUser
Export-ModuleMemberDeclare public membersExport-ModuleMember -Function Get-Greeting
Get-Command -ModuleList a module's commandsGet-Command -Module Pester

Mini-Challenge: build a tiny module

No blanks this time — just a brief and an outline to keep you on track. Build it, run it, and check your output against the example in the comments. Packaging functions into a reusable module is the leap from "scripts" to "tools".

# 🎯 MINI-CHALLENGE: build a tiny 'Math' module
# No code is filled in — just an outline. Build it and check the output.
#
# 1. Create MathTools.psm1 with TWO functions:
#       Get-Square  param([int]$N)  -> $N * $N
#       Get-Cube    param([int]$N)  -> $N * $N * $N
#    plus a private helper that you do NOT export.
# 2. Use Export-ModuleMember -Function Get-Square, Get-Cube to make only
#    those two public.
# 3. Create a manifest with New-ModuleManifest (RootModule, ModuleVersion,
#    Author, FunctionsToExport).
# 4. Import-Module the .psd1, then run Get-Command -Module MathTools and
#    call Get-Square 5.
#
# ✅ Example output:
#    25
#    (Get-Command shows only Get-Square and Get-Cube)

# your code here

🎉 Lesson Complete

Practice quiz

What is a PowerShell module?

  • A reusable package of related cmdlets, functions, and variables
  • A type of error
  • A keyboard shortcut
  • A single one-line command

Answer: A reusable package of related cmdlets, functions, and variables. A module bundles related commands and resources so they can be shared and reused as one unit.

Which cmdlet loads a module into the current session?

  • Add-Module
  • Use-Module
  • Import-Module
  • Load-Module

Answer: Import-Module. Import-Module makes a module's commands available in the current session.

Which cmdlet lists the modules currently imported?

  • List-Module
  • Get-Module
  • Find-Module
  • Show-Module

Answer: Get-Module. Get-Module lists loaded modules; add -ListAvailable to see installed but not-yet-loaded ones.

Which cmdlet searches the PowerShell Gallery for a module?

  • Search-Module
  • Get-Module
  • Import-Module
  • Find-Module

Answer: Find-Module. Find-Module queries the online PowerShell Gallery without installing anything.

Which cmdlet downloads and installs a module from the Gallery?

  • Install-Module
  • Get-Module
  • Save-Module
  • Add-Module

Answer: Install-Module. Install-Module downloads a module from the PowerShell Gallery and installs it locally.

What does $env:PSModulePath contain?

  • A list of cmdlets
  • The folders PowerShell searches for modules
  • Your command history
  • Installed Gallery versions

Answer: The folders PowerShell searches for modules. PSModulePath is a semicolon-separated list of directories where PowerShell looks for modules to auto-load.

Which file extension holds a script module's code?

  • A .dll file
  • A .ps1xml file
  • A .json file
  • A .psm1 file

Answer: A .psm1 file. Script modules live in a .psm1 file; a .psd1 manifest describes the module's metadata.

What is the purpose of a .psd1 module manifest?

  • It installs dependencies at runtime
  • It stores the actual function code
  • It describes metadata like version, author, and exports
  • It logs errors

Answer: It describes metadata like version, author, and exports. The .psd1 manifest declares the module's version, author, dependencies, and which members it exports.

Inside a .psm1, which command controls what the module exports?

  • Show-Module
  • Export-ModuleMember
  • Set-Export
  • Publish-Member

Answer: Export-ModuleMember. Export-ModuleMember explicitly declares which functions, variables, and aliases the module makes public.

How do you list the commands provided by a specific module?

  • Get-Command -Module <name>
  • Get-Module -Commands
  • Show-Command <name>
  • Find-Module -Commands

Answer: Get-Command -Module <name>. Get-Command -Module <name> lists every command exported by that module.

Continue this course

Frequently asked questions

Do I always need Import-Module to use a module?

Usually not. PowerShell uses module auto-loading: the first time you call a command from an installed module, PowerShell finds it on $env:PSModulePath and imports it for you automatically. You only need an explicit Import-Module when the module isn't on PSModulePath (e.g. you point at a specific .psd1 by path), when you want to force a particular version, or when you want the commands available before you call them (for tab-completion, say). For everyday installed modules, just call the command.

What is the difference between a .psm1 and a .psd1 file?

A .psm1 is the SCRIPT MODULE — it contains the actual code: your functions, variables, and the Export-ModuleMember calls that decide what's public. A .psd1 is the MANIFEST — a hashtable of metadata describing the module: its version, author, the RootModule (often the .psm1), required dependencies, and which members it exports. Best practice is to ship both: the manifest is what you point Import-Module and Publish-Module at, and it makes versioning and dependencies explicit.

Should I use -Scope CurrentUser or install for all users?

Use Install-Module -Scope CurrentUser unless you specifically need the module available to every account on the machine. CurrentUser installs into your profile folder and does NOT require administrator rights, which is the common case on a workstation. AllUsers (the default when elevated) installs into a shared Program Files location and needs an elevated session. For shared servers or build agents where many accounts run the same tools, AllUsers makes sense.

Is the PowerShell Gallery safe to install from?

The PowerShell Gallery is Microsoft's official public repository, but anyone can publish to it, so treat packages like any third-party code. Prefer modules with many downloads and a known publisher, read the project's source when it matters, and consider Save-Module to inspect a package before installing it. You can also pin to a specific version with -RequiredVersion for reproducibility, and run Install-Module from trusted, signed sources in production.

How does Export-ModuleMember decide what's public?

By default a script module exports all its functions, but the moment you call Export-ModuleMember it switches to exporting ONLY what you list. So Export-ModuleMember -Function Get-Greeting makes Get-Greeting public and hides every other function as a private helper. You can also export variables and aliases. When you ship a manifest, FunctionsToExport in the .psd1 narrows this further and improves load performance, because PowerShell can read the manifest without executing the module.