Test-IsModuleUpToDate.ps1

function Test-IsModuleUpToDate {
    <#
    .SYNOPSIS
        Checks whether a loaded module is up to date against its publish repository.
    .DESCRIPTION
        Compares the installed version of one or more modules against the latest
        version available in the repository recorded in the module's PrivateData
        at publish time. Silently skips modules with no PublishRepository recorded,
        or when the repository is not registered on this machine.
 
        Typical self-check usage from inside a module:
            Test-IsModuleUpToDate $ExecutionContext.SessionState.Module
 
        Pipeline usage to check all loaded modules:
            Get-Module | Test-IsModuleUpToDate
    .PARAMETER Module
        One or more PSModuleInfo objects to check. Accepts pipeline input.
    .OUTPUTS
        PSCustomObject with Name, InstalledVersion, LatestVersion, IsUpToDate.
        Nothing is output if the repository is unreachable or the module is not in the feed.
    #>

    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline)]
        [System.Management.Automation.PSModuleInfo[]]$Module
    )

    process {
        $targets = if ($Module) {
            $Module
        } else {
            $self = $ExecutionContext.SessionState.Module
            if ($self) { @($self) + @($self.RequiredModules) } else { @() }
        }
        foreach ($m in $targets) {
            if (-not $m -or [string]::IsNullOrEmpty($m.Name)) { continue }
            $repoName = if ($m.PrivateData -and $m.PrivateData['PublishRepository']) {
                $m.PrivateData['PublishRepository']
            } else {
                Write-Verbose "$($m.Name): no PublishRepository recorded, skipping."
                continue
            }

            $repo = Get-PSRepository -Name $repoName -ErrorAction SilentlyContinue
            if (-not $repo) {
                Write-Verbose "$($m.Name): repository '$repoName' is not registered, skipping."
                continue
            }

            $latest = Find-Module -Repository $repoName -Name $m.Name -ErrorAction SilentlyContinue
            if (-not $latest) { Write-Verbose "$($m.Name): not found in '$repoName'."; continue }

            [pscustomobject]@{
                Name             = $m.Name
                InstalledVersion = $m.Version
                LatestVersion    = [version]$latest.Version
                IsUpToDate       = $m.Version -ge [version]$latest.Version
            }
            if ($m.Version -lt [version]$latest.Version) {
                Write-Host "$($m.Name) update available: $($m.Version) -> $($latest.Version)." -ForegroundColor Yellow
                Write-Host " 1. Run: Install-Module $($m.Name) -Repository $repoName -Force -Scope CurrentUser" -ForegroundColor Cyan
                Write-Host " 2. Restart your shell to pick up the new version." -ForegroundColor Cyan
            }
        }
    }
}