Michael Aitken

IT Engineer, Tinkerer, Educator


PowerShell: Module Management

Posted on: December 16th, 2024


Managing your PowerShell modules is simple, though you may overlook all you can do with these cmdlets and how you can help out your colleagues by including the management of modules into your scripts. Keep reading for some information on cmdlets and the useful ways I've integrated them into larger scripts.

How Are These Things Stored?

Before we dive into managing your modules, I feel it's important to understand where these modules live. Use the line below to see where on your disk your installed modules are located.

PowerShell

$env:PSModulePath.Split(";")

This environment variable without the .Split(";") will output a semicolon separated list. The split makes it a little more digestible. These are the storage locations for all of your modules. Note that they will differ based on whether you are using PowerShell 5.1 or PowerShell 7.

When installing a module, which we'll look at a little further down, you can specify a scope for CurrentUser (you, running the command), or AllUsers. Modules installed for CurrentUser will be located in your user object's local home directory, within $HOME\Documents\PowerShell\Modules (PS 5.1) or $HOME\Documents\WindowsPowerShell\Modules (PS 7+). Modules installed for AllUsers will be located in the Program Files folder under $env:ProgramFiles\PowerShell\Modules (PS 5.1) or $env:ProgramFiles\WindowsPowerShell\Modules (PS 7+). Finally, the built-in modules that Windows ships with are located within $PSHOME\Modules (PS 5.1), which will be in your C:/Windows folder, or $env:SystemRoot\System32\WindowsPowerShell\1.0\Modules (PS 7+).

If you are uncertain what the value of any of these variables are, it never hurts to run them through your PS CLI:

PowerShell

### Display your $HOME directory
$HOME
### Display the $env:ProgramFiles environment variable
$env:ProgramFiles
### Display the $PSHOME directory
$PSHOME

Show Installed Modules

Let's start with Get-InstalledModule. This cmdlet will answer the question of "What did I install?" All modules installed with Install-Module will be shown. You can limit your output with the -Name parameter, which accepts wildcards like * and ?.

PowerShell

### Show all installed modules
Get-InstalledModule
### Example, display all installed Microsoft.Graph modules
Get-InstalledModule -Name Microsoft.Graph*

You may think back to what you read just a moment ago and think it would be nice to see these modules alongside their storage location. Your friend here will be Get-Module -ListAvailable. This will output ALL installed modules on your system, categorized by their storage directory. This cmdlet also takes wildcards with the -Name parameter.

PowerShell

### Show all installed modules
Get-Module -ListAvailable
### Example, display all installed Microsoft.Graph modules
Get-Module -ListAvailable -Name Microsoft.Graph*

Installing Modules

Not finding what you're looking for? Let's install it! For simplicity, we'll stick with PSGallery as our repository. Your org may host their own repo and you can build your own repo as well with Azure DevOps.

If you want to see your currently registered repos, you can use Get-PSRepository. PSGallery should be registered by default. If the InstallationPolicy is set to Untrusted, you may be asked to confirm installation of all modules. This won't affect you installing modules manually, but you may want unprompted installation in certain scenarios. You can change this and other values with Set-PSRepository Obligatory "Please be aware of what you are installing and where you are getting it from." Note that your org may prohibit this value from changing.

PowerShell

### Show all registered repositories
Get-PSRepository
### Update InstallationPolicy
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

Ready to install? Not quite. Lets say you need to confirm the module name and that the repo you're targeting has it. We can use Find-Module for this:

PowerShell

### Example, Show the SqlServer module in PSGallery
Find-Module -Repository PSGallery -Name SqlServer

You've looked through your installed modules, confirmed you do not have it installed, then confirmed it is hosted through PSGallery. Now we're ready to install. Install-Module will get this done for you. You'll want to specify the repository and module name at a minimum. You may also specify a specific version if you have a need to do so. You may also pipe the output of the previous Find-Module command into Install-Module.

PowerShell

### Example, Install SqlServer
Install-Module -Repository PSGallery -Name SqlServer
### Example, Install SqlServer from Find-Module output
Find-Module -Repository PSGallery -Name SqlServer | Install-Module

Updating Modules

Now you've installed your module. Some time has passed and there is likely an update available. You can apply updates to installed modules using Update-Module. No repository needs to be specified. If you look back to the output of Get-InstalledModule, you'll see that the repository each module is installed from is saved. Update-Module will pull from that repository automatically. Version numbers can be specified. Not doing so will pull the latest version.

PowerShell

### Example, Update SqlServer
Update-Module -Name SqlServer

Bringing It All Together

Let's bring everything we've learned here together to automate managing our modules. You've built a script for your team or department. They don't necessarily use PowerShell often and may not have the required modules installed or keep them up to date. You can build consideration for this at the front of your script. You could also save it as a standalone script, which could help keep modules up to date or come in handy if your system gets reimaged and you need to reinstall all of your modules. In the below scriptblock, we will put required modules into a variable and query our own installed modules. If they are installed, update if an update is available or pass it over. Otherwise, if it is not found, install it.

PowerShell

$installedModules = Get-InstalledModule
$requiredModules = @(
    'Microsoft.Graph.Authentication'
    'Microsoft.Graph.Users'
    'Microsoft.Graph.Users.Actions'
)

foreach ($module in $requiredModules) {
    if ($installedModules.Name -notcontains $module) {
        Write-Host "Module not found" -ForegroundColor Red
        Install-Module -Repository PSGallery -Name $module -WhatIf
    } else {
        Write-Host "Module found" -ForegroundColor Green
        if (($installedModules | where {$_.Name -eq $module}).Version -lt (Find-Module -Name $module).Version) {
            Update-Module -Name $module -WhatIf
        }
    }
}

Feel free to use any part of this and modify as needed. I'll be around next week with a new topic.