Public/Update-Office365Modules.ps1

function Update-Office365Modules {
    param (
        [switch]$AllowPrerelease,
        [switch]$Refresh
    )

    $local:Functions = Get-Office365ModuleInfo
    $local:UsePre = if ($AllowPrerelease.IsPresent) { $true } else { [bool]$script:myOffice365Services['AllowPrerelease'] }
    if ($Refresh) { $script:myOffice365Services['OnlineVersionCache'].Clear() }

    $local:IsAdmin = Test-IsAdministrator
    if ( $local:IsAdmin) {
        if ( (Get-Process -Name powershell, pwsh -ErrorAction SilentlyContinue | Measure-Object).Count -gt 1) {
            Write-Host ('Running multiple PowerShell sessions, successful updating might be problematic.') -ForegroundColor $script:myConsoleColors.Warning
        }
    }
    $local:ProgramFilesPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ProgramFiles)

    # Pre-fetch all online versions in parallel (PS 7+) to avoid N sequential network calls
    # in the loop below. Cache is shared with Show-Office365Modules (60-min TTL).
    if ($PSVersionTable.PSVersion.Major -ge 7) {
        $local:UsePSRG = $script:myOffice365Services['PSResourceGet']
        $local:ToFetch = $local:Functions.Module | Where-Object {
            $local:e = $script:myOffice365Services['OnlineVersionCache'][$_]
            $null -eq $local:e -or ([datetime]::Now - $local:e.Fetched).TotalMinutes -ge 60
        }
        if ($local:ToFetch) {
            $local:ToFetch | ForEach-Object -Parallel {
                $local:n = $_
                $local:o = if ($using:UsePSRG) {
                    Find-PSResource -Name $local:n -Prerelease:$using:UsePre -ErrorAction SilentlyContinue
                }
                else {
                    Find-Module -Name $local:n -AllowPrerelease:$using:UsePre -ErrorAction SilentlyContinue
                }
                [PSCustomObject]@{ Name = $local:n; Version = if ($local:o) { [string]$local:o.Version }else { $null } }
            } -ThrottleLimit 10 | ForEach-Object {
                $script:myOffice365Services['OnlineVersionCache'][$_.Name] = [PSCustomObject]@{
                    Version = $_.Version; Fetched = [datetime]::Now
                }
            }
        }
    }

    $local:AllInstalled = Get-Module -ListAvailable -ErrorAction SilentlyContinue

    if ( -not $local:IsAdmin) {
        Write-Warning 'Running non-elevated: modules installed in AllUsers scope cannot be upgraded and will be skipped.'
    }

    foreach ( $local:Item in $local:Functions) {

        $local:Module = Get-InstalledRepoModule -Name $local:Item.Module -Repo $local:Item.Repo -AllInstalled $local:AllInstalled

        if ( ($local:Module).RepositorySourceLocation) {

            if ( -not $local:IsAdmin -and ($local:Module.ModuleBase -like "$local:ProgramFilesPath*")) {
                Write-Host ('{0}: Skipped' -f $local:Item.Description) -ForegroundColor $script:myConsoleColors.Warning
                continue
            }

            $local:ModuleScope = if ($local:Module.ModuleBase -like "$local:ProgramFilesPath*") { 'AllUsers' } else { 'CurrentUser' }

            $local:Version = Get-ModuleVersionInfo -Module $local:Module
            Write-Host ('Checking {0}' -f $local:Item.Description) -NoNewline

            $local:NewerAvailable = $false
            $local:OnlineVer = Get-OnlineModuleVersion -Name $local:Item.Module
            if ( $local:OnlineVer) {
                Write-Host (' v{0} (Online v{1})' -f $local:Version, $local:OnlineVer) -NoNewline
                if ( (Compare-TextVersionNumber -Version $local:Version -CompareTo $local:OnlineVer) -eq 1) {
                    Write-Host (' Update available') -ForegroundColor $script:myconsoleColors.Error
                    $local:NewerAvailable = $true
                }
                else {
                    Write-Host ''
                }
            }
            else {
                # Not installed from online or cannot determine
                Write-Host (' v{0} (Online N/A)' -f $local:Version) -ForegroundColor $script:myconsoleColors.Warning

            }

            if ( $local:NewerAvailable) {
                $local:UpdateSuccess = $false
                try {
                    Update-myModule -Name $local:Item.Module -Scope $local:ModuleScope
                    $local:UpdateSuccess = $true
                }
                catch {
                    Write-Host ('Problem updating {0}: {1}' -f $local:Item.Module, $_.Exception.Message) -ForegroundColor $script:myConsoleColors.Error
                }

                if ( $local:UpdateSuccess) {

                    Write-Host ('Updated {0} to version {1}' -f $local:Item.Description, $local:OnlineVer) -ForegroundColor $script:myConsoleColors.OK

                    # If we just updated ourselves, the new version is now on disk but the old
                    # in-memory code is still executing. Deleting the old module folder would
                    # break the running session, so skip the uninstall step and ask the user
                    # to restart PowerShell to load the new version.
                    if ( $local:Item.Module -eq $MyInvocation.MyCommand.Module.Name) {
                        Write-Warning ('{0} was updated to v{1}. Restart PowerShell to load the new version.' -f $local:Item.Module, $local:OnlineVer)
                        continue
                    }

                    # Uninstall all older versions; use OnlineVer as the new baseline so we
                    # correctly identify old versions regardless of which package manager ran.
                    $local:ModuleVersions = Get-Module -Name $local:Item.Module -ListAvailable -ErrorAction SilentlyContinue |
                    Where-Object { $_.RepositorySourceLocation -and ([System.Uri]($_.RepositorySourceLocation)).Authority -ieq ([System.Uri]($local:Item.Repo)).Authority }
                    $local:LatestVersion = $local:OnlineVer

                    # Uninstall all old versions of module & dependencies
                    if ( $local:OnlineVer) {
                        foreach ( $DependencyModule in $Module.Dependencies) {

                            $local:DepModuleVersions = Get-myModule -Name $DependencyModule.Name -ListAvailable
                            $local:DepModule = $local:DepModuleVersions | Sort-Object -Property @{e = { [System.Version]($_.Version -replace '[^\d\.]', '') } } -Descending | Select-Object -First 1
                            $local:DepLatestVersion = ($local:DepModule).Version
                            $local:OldDepModules = $local:DepModuleVersions | Where-Object { $_.Version -ne $local:DepLatestVersion }
                            $local:OldDepModules | ForEach-Object {
                                $DepModule = $_
                                Write-Host ('Uninstalling dependency {0} version {1}' -f $DepModule.Name, $DepModule.Version)
                                try {
                                    Uninstall-myModule -Name $DepModule.Name -Version $DepModule.Version -IsPrerelease:$DepModule.IsPrerelease
                                }
                                catch {
                                    Write-Warning ('Problem uninstalling {0} v{1}: {2}' -f $DepModule.Name, $DepModule.Version, $_.Exception.Message)
                                }
                            }
                        }
                        $local:OldModules = $local:ModuleVersions | Where-Object { $_.Version -ne $local:LatestVersion }
                        if ( $local:OldModules) {
                            foreach ( $OldModule in $local:OldModules) {
                                Write-Host ('Uninstalling {0} version {1}' -f $local:Item.Description, $OldModule.Version)
                                try {
                                    Uninstall-myModule -Name $OldModule.Name -Version $OldModule.Version -IsPrerelease:$OldModule.IsPrerelease
                                }
                                catch {
                                    Write-Warning ('Problem uninstalling {0} v{1}: {2}' -f $OldModule.Name, $OldModule.Version, $_.Exception.Message)
                                }
                            }
                        }
                    }
                }
                else {
                    # Problem during update
                }
            }
            else {
                # No update available
            }
        }
        else {
            # Not installed
        }
    }
}