Open Source MIT License v3.0.1 Technical Poster

PSModuleMaintenance

Keeps every PowerShell module updated and cleans up old versions, with built-in monitoring and failsafes.

Runs weekly/Monitoring-ready/Respects your pins

PowerShell 7+ PSResourceGet Windows 10/11 Task Scheduler Healthchecks.io
1
Task a Week
0
Modules to Install
8
Built-in Failsafes

Quick start.

Clone, try a dry run, install the task. There is nothing to install first: PSResourceGet ships with PowerShell 7.4 and later. From then on it runs every Sunday at 03:00, and catches up when the machine was asleep.

NO CONFIG FILE NEEDED
1$ git clone https://github.com/haakonwibe/psmodulemaintenance.git
2$ .\Invoke-PSModuleMaintenance.ps1 -WhatIf
3$ .\Install-ModuleMaintenance.ps1
 # step 3 as Administrator, it registers the weekly task
// 01

Built differently.

× A one-liner in a scheduled task
# The usual answer: one line, once a week

PS> Update-PSResource -Name *

# New versions land next to the old ones
# Nothing ever removes the old ones
# One slow module holds up all that follow
# Errors go to a window nobody sees
# No log, no summary, no alert
  • Old versions pile up, side by side
  • One module that hangs blocks the rest of the run
  • A run that checked nothing looks like a quiet week
  • A task that never starts leaves no trace at all
✓ PSModuleMaintenance
PS> .\Invoke-PSModuleMaintenance.ps1

[INFO] Found 64 installed modules (excluding: Northwind.Data)
[WARN] Network fault on Contoso.Tools (attempt 1 of 3): ...
[SUCCESS] Updated: Contoso.Tools (took 9s)
[INFO] Updating kept line 5 of Fabrikam.Core: 5.5.0 -> 5.6.1
[SUCCESS] Removed: Fabrikam.Core v5.5.0
[INFO] Healthchecks ping sent: Success
[SUCCESS] PSModuleMaintenance completed successfully
  • Every update has a timeout, and a retry after a network fault
  • Old versions are pruned, except the ones you asked to keep
  • The log, the toast and the ping always agree on how it went
  • A missing ping raises the alarm when nothing ran at all
// 02

What it does.

Microsoft.Graph and Az

Works with the large module collections. Updates and cleans up every sub-module.

Az // 100+ modulesMicrosoft.Graph // about 40

Automatic updates

Updates all installed modules via PSResourceGet.

Runs weekly

Version cleanup

Removes old module versions, keeps only the latest.

Every week

Pinning and exclusions

Hold a module at a chosen version, keep an older version, or skip the module.

Set in config.json

Timeout and retry

Time limit on every update. Network errors are retried.

10 minutes // 3 attempts

Failsafes

Touches nothing if config.json can't be read. Skips a module whose entry is unclear.

8 built in

Error reporting

Errors show up in the log, the toast and the monitoring.

Log // Toast // Ping

Monitoring

Optional Healthchecks.io monitoring. Alerts if a run fails or never starts.

Off by default

Logging

Log file, transcript and JSON summary for every run.

Opens in CMTrace

OneDrive migration

Moves modules out of OneDrive-synced folders to AllUsers scope.

One-time script
// 03

How it works.

What one weekly run does, in order. The summary is saved after every phase, so a run that is cut short still leaves its results behind.

01
Load config
config.json
or the defaults
02
Look up
One query
to PSGallery
03
Update
Timeout and retry
per module
04
Prune
Newest, pin and
kept lines stay
05
Report
Log, summary
and toast
06
Ping
Success
or fail
// 04

Eight built-in failsafes.

What the run does when something breaks, and how you find out. The log is always written, the toast and the ping are optional.

What happens What the run does How you hear about it
PSGallery cannot be reached ✓Retries the lookup, then prunes only. Nothing is called up to date Log, toast and fail ping
The network drops during an update ✓Tries again after 5 and then 15 seconds A warning in the log. A failure only if all three attempts fail
A module takes longer than its timeout ✓Gives up on that module and goes on with the next Log, toast and fail ping
The config file is unreadable, empty or has an invalid setting ✓Touches no module and removes no log Log, toast and fail ping
One config entry is not understood ✓Leaves that module alone and maintains the rest Log, toast and fail ping, until the entry is put right
A pinned version is not installed ✓Installs it, and prunes nothing of that module if it cannot A line in the log. A failure only if the install does not succeed
PowerShell moves to another folder ✓The task finds pwsh.exe through PATH at every run A warning if an older task still has a fixed path
The task never starts ✓Nothing runs, so nothing on the machine can report it Healthchecks alerts on the missing ping
// 05

Three ways to make an exception.

Every module is updated and pruned unless config.json says otherwise. Pinning and keeping combine, and excluding wins over both.

Leave it alone
ExcludedModules
"ExcludedModules": [
  "Contoso.Tools"
]

The module is not updated and not pruned. For a module you manage yourself.

NOTHING CHANGES
Hold one version
PinnedModules
"PinnedModules": {
  "Contoso.Tools": "2.19.0"
}

The pinned version is installed if it is missing, and newer versions are pruned. For a release that broke something.

ONE VERSION
Keep an older line
KeepVersions
"KeepVersions": {
  "Fabrikam.Core": ["5"]
}

The newest version and the 5 line are both kept, and both are updated, each within itself. For a breaking major release.

TWO LINES, BOTH CURRENT