PowerShell function to find information about module updates

I decided to update the one liner from my blog article last week and take it a step further by turning it into a reusable tool that displays information about module updates that are available regardless of where they were installed from.

#Requires -Version 3.0 -Modules PowerShellGet
function Find-MrModuleUpdate {

<#
.SYNOPSIS
Finds updates for installed modules from an online gallery that matches the specified criteria.

.DESCRIPTION
Find-MrModuleUpdate is a PowerShell advanced function that finds updates from an online gallery for locally installed modules
regardless of whether or not they were originally installed from an online gallery or from the same online gallery where the
update is found.

.PARAMETER Name
Specifies the names of one or more modules to search for.

.PARAMETER Scope
Specifies the search scope of the installed modules. The acceptable values for this parameter are: AllUsers and CurrentUser.

.EXAMPLE
Find-MrModuleUpdate

.EXAMPLE
Find-MrModuleUpdate -Name PSScriptAnalyzer, PSVersion

.EXAMPLE
Find-MrModuleUpdate -Scope CurrentUser

.EXAMPLE
Find-MrModuleUpdate -Name PSScriptAnalyzer, PSVersion -Scope CurrentUser

.INPUTS
None

.OUTPUTS
Mr.ModuleUpdate

.NOTES
Author:  Mike F Robbins
Website: https://mikefrobbins.com
Twitter: @mikefrobbins
#>

[CmdletBinding()]
[OutputType('Mr.ModuleUpdate')]
param (
[ValidateNotNullOrEmpty()]
[string[]]$Name,

[ValidateSet('AllUsers', 'CurrentUser')]
[string]$Scope
)

$AllUsersPath = "$env:ProgramFiles\WindowsPowerShell\Modules\*"
$CurrentUserPath = "$env:USERPROFILE\Documents\WindowsPowerShell\Modules\*"

switch ($Scope) {
'AllUsers' {$Path = $AllUsersPath; break}
'CurrentUser' {$Path = $CurrentUserPath; break}
Default {$Path = $AllUsersPath, $CurrentUserPath}
}

$Params = @{
ListAvailable = $true
}

if ($PSBoundParameters.Name) {
$Params.Name = $Name
}

$Modules = Get-Module @Params

foreach ($p in $Path) {

$ScopedModules = $Modules |
Where-Object ModuleBase -like $p |
Sort-Object -Property Name, Version -Descending |
Get-Unique

foreach ($Module in $ScopedModules) {

Remove-Variable -Name InstallInfo -ErrorAction SilentlyContinue
$Repo = Find-Module -Name $Module.Name -ErrorAction SilentlyContinue

if ($Repo) {
$Diff = Compare-Object -ReferenceObject $Module -DifferenceObject $Repo -Property Name, Version |
Where-Object SideIndicator -eq '=>'

if ($Diff) {
$PSGetModuleInfoPath = "$($Module.ModuleBase)\PSGetModuleInfo.xml"

if (Test-Path -Path $PSGetModuleInfoPath) {
$InstallInfo = Import-Clixml -Path $PSGetModuleInfoPath
}

switch ($Module.ModuleBase) {
{$_ -like $AllUsersPath} {$Location = 'AllUsers'; break}
{$_ -like $CurrentUserPath} {$Location = 'CurrentUser'; break}
Default {Throw 'An unexpected error has occured.'}
}

[pscustomobject]@{
Name = $Module.Name
InstalledVersion = $Module.Version
InstalledLocation = $Location
Repository = $Repo.Repository
RepositoryVersion = $Diff.Version
InstalledFromRepository = $InstallInfo.Repository
PSTypeName = 'Mr.ModuleUpdate'
}

}

}

}

}

}
Find-MrModuleUpdate

find-mrmoduleupdate1a.jpg

As shown in the previous results, the function lists modules that have updates available regardless of where they were originally installed from. It also lists the installed version and location along with the repository where the updated version resides and the updated version number. It also lists where the module was originally installed from by reading the contents of the hidden XML file in the module directory if it was installed using PowerShellGet.

You can narrow your search down to specific modules:

Find-MrModuleUpdate -Name PSScriptAnalyzer, PSVersion

find-mrmoduleupdate2a.jpg

To a specific scope:

Find-MrModuleUpdate -Scope CurrentUser

find-mrmoduleupdate3a.jpg

Use a combination of specific modules and scope to narrow the search down even further:

Find-MrModuleUpdate -Name PSScriptAnalyzer, PSVersion -Scope AllUsers

find-mrmoduleupdate4a.jpg

The function also uses custom formatting to allow for table output with more than four columns by default without having to pipe to Format-Table. The relevant portion of the PS1XML file used for the custom formatting is shown in the code example below:

<View>
<Name>Mr.ModuleUpdate</Name>
<ViewSelectedBy>
<TypeName>Mr.ModuleUpdate</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width>30</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>16</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>17</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>10</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>17</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>23</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>InstalledVersion</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>InstalledLocation</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Repository</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>RepositoryVersion</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>InstalledFromRepository</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>

The Find-MrModuleUpdate function shown in this blog article is part of my MrToolkit module which can be downloaded from my PowerShell repository on GitHub.

ยต