Updating your PowerShell modules to the latest version plus cleaning up older versions

You installed a PowerShell module on your machine and used it for a long time and suddenly… It doesn’t connect anymore, shows warnings that some commands are deprecated, and now what?! In this blog post, I will show you a way to update all your modules to the latest version and also remove unused older versions.

Requirements

The script should be able to update all modules to the latest version, but it should also update them to the latest prerelease version if specified. It should also show the current version and the new version when updated. And to keep things nice and tidy, it should also remove any previous versions.

Running the script

When running the script with no parameter, it will update all modules to the latest production version and remove older versions if any. With the -AllowPreRelease parameter, it will update all modules to the latest Prerelease version if available and to the latest Production version if not.
Note: The script requires running it as Administrator.
Warning: Updating all your modules to the PreRelease version could break things for you!

The output of the script when starting the Update-Modules function:

The output of the script when removing older versions:

Example output stating the updated modules at the end of the script:

It will show an error in red if the module can’t be updated, it will also report if modules can’t be updated because they are in use:

or

Note: If you have a lot of modules… This could take a while 🙂

The script

Below is the script, save it to a location (c:\scripts for example) and add it to your PowerShell profile by:

notepad $profile
add ". c:\scripts\Update-modules.ps1"
quit/save and start new PowerShell session

Special thanks go out to ScrambledBrain for updating the script through a pull request on GitHub twice 🙂

function Update-Modules {
	param (
		[switch]$AllowPrerelease
	)

	# Test admin privileges without using -Requires RunAsAdministrator,
	# which causes a nasty error message, if trying to load the function within a PS profile but without admin privileges
	if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")) {
		Write-Warning ("Function {0} needs admin privileges. Break now." -f $MyInvocation.MyCommand)
		break
	}

	# Get all installed modules
	Write-Host ("Retrieving all installed modules ...") -ForegroundColor Green
	$CurrentModules = Get-InstalledModule | Select-Object Name, Version | Sort-Object Name

	if (-not $CurrentModules) {
		Write-Host ("No modules found.") -ForegroundColor Gray
		break
	}
	else {
		$ModulesCount = $CurrentModules.Count
		$DigitsLength = $ModulesCount.ToString().Length
		Write-Host ("{0} modules found." -f $ModulesCount) -ForegroundColor Gray
	}

	# Show status of AllowPrerelease Switch
	''
	if ($AllowPrerelease) {
		Write-Host ("Updating installed modules to the latest PreRelease version ...") -ForegroundColor Green
	}
	else {
		Write-Host ("Updating installed modules to the latest Production version ...") -ForegroundColor Green
	}

	# Loop through the installed modules and update them if a newer version is available
	$i = 0
	foreach ($Module in $CurrentModules) {
		$i++
		$Counter = ("[{0,$DigitsLength}/{1,$DigitsLength}]" -f $i, $ModulesCount)
		$CounterLength = $Counter.Length
		Write-Host ('{0} Checking for updated version of module {1} ...' -f $Counter, $Module.Name) -ForegroundColor Green
		try {
			Update-Module -Name $Module.Name -AllowPrerelease:$AllowPrerelease -AcceptLicense -Scope:AllUsers -ErrorAction Stop
		}
		catch {
			Write-Host ("{0$CounterLength} Error updating module {1}!" -f ' ', $Module.Name) -ForegroundColor Red
		}

		# Retrieve newest version number and remove old(er) version(s) if any
		$AllVersions = Get-InstalledModule -Name $Module.Name -AllVersions | Sort-Object PublishedDate -Descending
		$MostRecentVersion = $AllVersions[0].Version
		if ($AllVersions.Count -gt 1 ) {
			Foreach ($Version in $AllVersions) {
				if ($Version.Version -ne $MostRecentVersion) {
					try {
						Write-Host ("{0,$CounterLength} Uninstalling previous version {1} of module {2} ..." -f ' ', $Version.Version, $Module.Name) -ForegroundColor Gray
						Uninstall-Module -Name $Module.Name -RequiredVersion $Version.Version -Force:$True -ErrorAction Stop
					}
					catch {
						Write-Warning ("{0,$CounterLength} Error uninstalling previous version {1} of module {2}!" -f ' ', $Version.Version, $Module.Name)
					}
				}
			}
		}
	}

	# Get the new module versions for comparing them to to previous one if updated
	$NewModules = Get-InstalledModule | Select-Object Name, Version | Sort-Object Name
	if ($NewModules) {
		''
		Write-Host ("List of updated modules:") -ForegroundColor Green
		$NoUpdatesFound = $true
		foreach ($Module in $NewModules) {
			$CurrentVersion = $CurrentModules | Where-Object Name -EQ $Module.Name
			if ($CurrentVersion.Version -notlike $Module.Version) {
				$NoUpdatesFound = $false
				Write-Host ("- Updated module {0} from version {1} to {2}" -f $Module.Name, $CurrentVersion.Version, $Module.Version) -ForegroundColor Green
			}
		}

		if ($NoUpdatesFound) {
			Write-Host ("No modules were updated.") -ForegroundColor Gray
		}
	}
}

Download the script(s) from GitHub here.

2 thoughts on “Updating your PowerShell modules to the latest version plus cleaning up older versions

  1. Your methodology is different than others that I have seen where it uses Get-InstalledModule. It is more elegant than others I have seen. However, it will not update modules that are native to PowerShell that have not previously been updated. For example, PSDesiredStateConfiguration.

    The PSDesiredStateConfiguration brings up other issues between PowerShell 5x and 7x. In PowerShell 5, the Find-Module lists a version not compatible with this version of PowerShell. Attempting to install this version does not produce any errors and has an end result in no change.

    • It also doesn’t update modules when they are not installed using install-module. It’s not perfect, I could expand it to try and catch these exceptions too in the future

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.