Update-PSModules.ps1


<#PSScriptInfo
 
.VERSION 1.0
 
.GUID 555960ba-78c6-4b4f-a788-371139d7d44a
 
.AUTHOR Jimmy Briggs
 
.COMPANYNAME Jimmy Briggs
 
.COPYRIGHT Jimmy Briggs | 2022
 
.TAGS PowerShell Modules Management Utility Update Cleanup
 
.LICENSEURI
 
.PROJECTURI https://github.com/jimbrig
 
.DESCRIPTION
    A script for updating and cleaning up old versions of your installed PowerShell Modules.
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>

<#
.EXAMPLE
    .\Update-PSModules.ps1
    Updates Modules.
.PARAMETER AllowPrerelease
    Allows the script to update to prerelease versions of modules.
#>

[CmdletBinding()]
Param (
    [Parameter(Mandatory=$false)]
    [switch]$AllowPrerelease
)

$ErrorActionPreference = 'Stop'

Function Test-IsAdmin {
    <#
    .SYNOPSIS
        Test if the current user is an administrator.
    .DESCRIPTION
        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 Administrative privileges.
    .EXAMPLE
        PS> Test-IsAdmin
        True
    #>

    [CmdletBinding()]
    Param ()

    # Get the Principal Object
    $Principal = New-Object `
        System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())

    # Check if the Principal Object is in the Administrator Role
    $IsAdmin = $Principal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)

    If (-not $IsAdmin) {
        $ParentFunction = (Get-PSCallStack | Select-Object FunctionName -Skip 1 -First 1).FunctionName
        Write-Warning ("Function {0} needs admin privileges. Break now." -f $ParentFunction)
        return $false
    }
    Else {
        return $true
    }    
}

Function Update-Modules {
    <#
    .SYNOPSIS
        Script to update powershell modules.
 
    .DESCRIPTION
        A script for updating and cleaning up old versions of your installed PowerShell Modules.
 
    .PARAMETER AllowPrerelease
        Should you allow the updating to Pre-Release versions of modules?
 
    .EXAMPLE
        PS> .\Update-PSModules.ps1 -AllowPrerelease
        Update modules updating to any available pre-release versions.
    #>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$false)]
        [switch]$AllowPrerelease
    )    

    If (!Test-IsAdmin) {
        Write-Warning "You must be an administrator to run this script."
        throw
    }

    # 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
        return
    }
    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
        }
    }
}

If ($AllowPrerelease) { Update-PSModules -AllowPreRelease }
Else { Update-PSModules }

# End of script