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.
Keeps every PowerShell module updated and cleans up old versions, with built-in monitoring and failsafes.
Runs weekly/Monitoring-ready/Respects your pins
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.
# 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
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
Works with the large module collections. Updates and cleans up every sub-module.
Updates all installed modules via PSResourceGet.
Removes old module versions, keeps only the latest.
Hold a module at a chosen version, keep an older version, or skip the module.
Time limit on every update. Network errors are retried.
Touches nothing if config.json can't be read. Skips a module whose entry is unclear.
Errors show up in the log, the toast and the monitoring.
Optional Healthchecks.io monitoring. Alerts if a run fails or never starts.
Log file, transcript and JSON summary for every run.
Moves modules out of OneDrive-synced folders to AllUsers scope.
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.
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 |
Every module is updated and pruned unless config.json says otherwise. Pinning and keeping combine, and excluding wins over both.
"ExcludedModules": [ "Contoso.Tools" ]
The module is not updated and not pruned. For a module you manage yourself.
NOTHING CHANGES"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"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