Issue:
Updating your PowerShell modules is a common task and one you should do regularly when utilising any cloud based modules.
But how to maintain current versions without bloat or getting versions confused?
Solution:
As always read and understand the code before running.
Learn and improve is the goal of this blog.
EDIT:
Oh dear. Updated version with some improved logic and verbose logging.
# requires -version 4.0
# requires –runasadministrator
function Remove-LegacyModuleVersions {
<#
.Synopsis
Removes older versions of PowerShell Modules.
.DESCRIPTION
Removes older versions of PowerShell Modules.
Enforce administrator mode for a clean uninstall.
.EXAMPLE
Remove-LegacyModuleVersions
.EXAMPLE
Remove-LegacyModuleVersions -Confirm:$false -Verbose
.NOTES
AUTHOR : Steve Rackham
BLOG : https://siliconwolf.net
GIT : https://github.com/siliconWOLF
LINKEDIN : https://nz.linkedin.com/in/steverackham
CREATED : 27.06.2018
UPDATED : 31.01.2020
#>
[cmdletbinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param () # END PARAMS
begin {
# DEFINITIONS: --------------------------------------------------------
[int]$Counter = 0
[int]$CounterTotal = 0
[int]$UninstalledModules = 0
# $StringDelimiter = (Get-Culture).TextInfo.ListSeparator
# Status Flag:
$Status = @{
Success = "[ SUCCESS ]"
Error = "[ ERROR ]"
Warning = "[ WARNING ]"
Information = "[ INFO ]"
End = "[ END ]"
} # END $Status
# GET -----------------------------------------------------------------
# Capture the installed modules.
try {
$Modules = Get-InstalledModule -ErrorAction Stop
$OffSet = 0 - ($Modules.Name | Measure-Object -Maximum -Property Length).Maximum
$CounterTotal = $Modules.Count
Write-Verbose ("{0} , {1} , {2, $Offset} , {3}" -f "$($Status.Information)", "[ $(Get-Date -Format HH:mm:ss.fff) ]", "TARGET: [ $env:COMPUTERNAME ]", "ACTION: Capture All Modules [ $CounterTotal ]." )
Write-Verbose ("{0} , {1} , {2, $Offset} , {3}" -f "$($Status.Information)", "[ $(Get-Date -Format HH:mm:ss.fff) ]", "TARGET: [ $env:COMPUTERNAME ]", "ACTION: Processing Modules. This may take some time..." )
}
catch {
Write-Warning ("{0} , {1} , {2, $Offset} , {3}" -f "$($Status.Error)", "[ $(Get-Date -Format HH:mm:ss.fff) ]", "TARGET: [ $env:COMPUTERNAME ]", "FAILURE! $($Error[0].Exception.Message)" )
Return
} # END-TRY/CATCH
}
process {
# SET -----------------------------------------------------------------
foreach ($Module in $Modules) {
# Capture latest version.
$LatestVersion = Get-InstalledModule $Module.Name
# Capture all versions for comparison.
$ModuleVersions = Get-InstalledModule $Module.Name -AllVersions
# Check versions and if more than one remove the older version.
if ($ModuleVersions.Count -gt 1) {
foreach ($ModuleVersion in $ModuleVersions) {
if ($PSCmdlet.ShouldProcess(
"[ $($Module.Name) ] Uninstalling old version [ $($ModuleVersion.Version) ]",
"[ $($Module.Name) ] Old version detected. Uninstall [ $($ModuleVersion.Version) ]? ",
'IMPORTANT!')) {
if ($ModuleVersion.Version -ne $LatestVersion.Version) {
try {
$ModuleVersion | Uninstall-Module -Force -Confirm:$false -ErrorAction Stop
$UninstalledModules++
Write-Verbose ("{0} , {1} , {2, $Offset} , {3}" -f "$($Status.Success)", "[ $(Get-Date -Format HH:mm:ss.fff) ]", "TARGET: [ $($Module.Name) ]", "ACTION: Uninstalled Version [ $($ModuleVersion.Version) ]." )
}
catch {
Write-Warning ("{0} , {1} , {2, $Offset} , {3}" -f "$($Status.Error)", "[ $(Get-Date -Format HH:mm:ss.fff) ]", "TARGET: [ $($Module.Name) ]", "FAILURE! $($Error[0].Exception.Message)" )
}
} # END if ($ModuleVersion.Version -ne $LatestVersion.Version)
} # END if $PSCmdlet.ShouldProcess
} # END FOREACH ($version in $modVersions)
} # END if ($ModuleVersions.Count -gt 1)
# STATUS OUTPUT: --------------------------------------------------
$Counter++
$Activity = "Processing PowerShell Module Versions..."
$CurrentOperation = "Processing Module: $($Module.Name)"
$PercentComplete = (($Counter / $CounterTotal) * 100)
$Progress = "PROCESSING: $Counter of $CounterTotal"
Write-Progress -Activity $Activity -CurrentOperation $CurrentOperation -PercentComplete $PercentComplete -Status $Progress
} # END FOREACH ($mod in $modules)
Write-Output ("{0} , {1} , {2, $Offset} , {3}" -f "$($Status.End)", "[ $(Get-Date -Format HH:mm:ss.fff) ]", "TARGET: [ $env:COMPUTERNAME ]", "ACTION: Uninstalled Old Modules [ $UninstalledModules ]." )
} # End process block.
} # END FUNCTION Remove-LegacyModuleVersions ##########################################