Check latest PowerShell Module version with PowerShell

The estimated reading time 10 minutes

Sometimes it is necessary to check if your powershell module is still up to date. Yes in newer PowerShell Versions you can choose the following cmdlet: Update-Module (PS-Version5.1)

https://docs.microsoft.com/en-us/powershell/module/powershellget/update-module?view=powershell-5.1

But I wanted to have a function which can compare versions of any powershell module and can also compare any other version. Therefor I did some research in google and found .Net Framework class [version]. Some blogposts later I got the comparing mechanism to check if one version is older than another.

if ([version]('{0}.{1}' -f $a.split('.')) -gt [version]('{0}.{1}' -f $b.split('.'))) {
         Write-Host "Installed $a is greater than $b"
      }
      else {
          Write-Host "Installed Module:$a is lower version than $b"
      }

This quite simple “if case” can check the version an also can do something if it greater or not. Looks fine so far.

UPDATE (Roberts Comment):
Simple way to use the .Net Framework Class

[version]'1.1.0' -gt [version]'1.0.0.0'
[version]'1.1.0' -gt [version]'1.0'
[version]'1.1.0.0' -gt [version]'1.0'

This version compare return TRUE in all this examples, so you can use this method or my example.

See the new Script at the end of the article


CAN BE IGNORED see the version compare above, or to be used for powershell training.
If you type in “Get-Module -ListAvailable” you can see that there are different modules with different numbering. Sometimes it’s 1.0.0.0 or 1.0.0 so not an unique version numbering at all.

How can we do that?

Don’t know if there is a proper solution for that, in my case I decided to convert the version to string and count the dots to find out which version numbering is used. Here we go.

#get version of the module (selects the first if there are more versions installed)
$version = (Get-Module -ListAvailable AzureAD) | Sort-Object Version -Descending  | Select-Object Version -First 1
#convert version to string and create a new object ModuleVersion
$stringver = $version | Select-Object @{n='ModuleVersion'; e={$_.Version -as [string]}}
$ver = $stringver | Select-Object Moduleversion -ExpandProperty Moduleversion
#count the dots 
$charCount = ($ver.ToCharArray() | Where-Object {$_ -eq '.'} | Measure-Object).Count
"--"
$stringver
"--"
$ver
"--"
$charCount
“3” is the nuber of dots

OK we can now count the dots in version and create a switchcase to operate the .Net class version. See how this can look like.

switch($charCount){
    {$charCount -eq 1}{ 
      if ([version]('{0}.{1}' -f $ver.split('.')) -ge [version]('{0}.{1}' -f $exampver.split('.'))) {
        Write-Host "Installed $ver is greater than or equal $exampver"
      }
      else {
        Write-Host "Installed Module:$ver is lower version than available $exampver"
      }  
    }
.
.
.
{$charCount -eq 3}{ 
      if ([version]('{0}.{1}.{2}.{3}' -f $a.split('.')) -ge [version]('{0}.{1}.{2}.{3}' -f $b.split('.'))) {...}

}

As you can see with this switch parameter it is possible to check which version format you get and react on this.
The next step is to integrate that script into a foreach loop so you can check multiple modules.

$update = "AzureAD","OneDrive","ImportExcel"
foreach($mod in $update){...}

Next step is to put it all together: (checking three modules)

$update = "AzureAD","OneDrive","ImportExcel"
foreach($checkmodule in $update){
  #getting version of installed module
  $version = (Get-Module -ListAvailable $checkmodule) | Sort-Object Version -Descending  | Select-Object Version -First 1
  #converting version to string
  $stringver = $version | Select-Object @{n='ModuleVersion'; e={$_.Version -as [string]}}
  $a = $stringver | Select-Object Moduleversion -ExpandProperty Moduleversion
  #getting latest module version from ps gallery 
  $psgalleryversion = Find-Module -Name $checkmodule | Sort-Object Version -Descending | Select-Object Version -First 1
  #converting version to string
  $onlinever = $psgalleryversion | select @{n='OnlineVersion'; e={$_.Version -as [string]}}
  $b = $onlinever | Select-Object OnlineVersion -ExpandProperty OnlineVersion
  #check version format 0.0.0 or 0.0 ...
  $charCount = ($a.ToCharArray() | Where-Object {$_ -eq '.'} | Measure-Object).Count
  switch($charCount){
    {$charCount -eq 1}{
      ##version format 1.1 
      if ([version]('{0}.{1}' -f $a.split('.')) -ge [version]('{0}.{1}' -f $b.split('.'))) {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed $a is equal or greater than $b"
      }
      else {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed Module:$a is lower version than $b"
      }  
    }
    {$charCount -eq 2}{
      ##version format 1.1.1  
      if ([version]('{0}.{1}.{2}' -f $a.split('.')) -ge [version]('{0}.{1}.{2}' -f $b.split('.'))) {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed $a is equal or greater than $b"
      }
      else {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed Module:$a is lower version than $b"
      }  
    }
    {$charCount -eq 3}{ 
      ##version format 1.1.1.1
      if ([version]('{0}.{1}.{2}.{3}' -f $a.split('.')) -ge [version]('{0}.{1}.{2}.{3}' -f $b.split('.'))) {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed $a is equal or greater than $b"
      }
      else {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed Module:$a is lower version than $b"
      }  
    }
   }
}

OK now let’s check if there is a way to ask if you want to do an update of the module or not. This can be done like this:

#ask for update  
        do { $askyesno = (Read-Host "Do you want to update Module $checkmodule (Y/N)").ToLower() } while ($askyesno -notin @('y','n'))
              if ($askyesno -eq 'y') {
                  Write-Host "Selected YES Updating module $checkmodule"
                  Update-Module -Name $checkmodule -Verbose -Force
                  
                  } else {
                  Write-Host "Selected NO , no updates to Module $checkmodule were done"
                  }

As you can see this little loop accepts only Y or N. Really nice I think.

Put it all together and voila

$update = "AzureAD","OneDrive","ImportExcel"
foreach($checkmodule in $update){
  #getting version of installed module
  $version = (Get-Module -ListAvailable $checkmodule) | Sort-Object Version -Descending  | Select-Object Version -First 1
  #converting version to string
  $stringver = $version | Select-Object @{n='ModuleVersion'; e={$_.Version -as [string]}}
  $a = $stringver | Select-Object Moduleversion -ExpandProperty Moduleversion
  #getting latest module version from ps gallery 
  $psgalleryversion = Find-Module -Name $checkmodule | Sort-Object Version -Descending | Select-Object Version -First 1
  #converting version to string
  $onlinever = $psgalleryversion | select @{n='OnlineVersion'; e={$_.Version -as [string]}}
  $b = $onlinever | Select-Object OnlineVersion -ExpandProperty OnlineVersion
  #check version format 0.0.0 or 0.0 ...
  $charCount = ($a.ToCharArray() | Where-Object {$_ -eq '.'} | Measure-Object).Count
  switch($charCount){
    {$charCount -eq 1}{
      ##version format 1.1 
      if ([version]('{0}.{1}' -f $a.split('.')) -ge [version]('{0}.{1}' -f $b.split('.'))) {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed $a is equal or greater than $b"
      }
      else {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed Module:$a is lower version than $b"
          #ask for update  
        do { $askyesno = (Read-Host "Do you want to update Module $checkmodule (Y/N)").ToLower() } while ($askyesno -notin @('y','n'))
        if ($askyesno -eq 'y') {
            Write-Host "Selected YES Updating module $checkmodule"
            Update-Module -Name $checkmodule -Verbose -Force
            
            } else {
            Write-Host "Selected NO , no updates to Module $checkmodule were done"
            }

      }  
    }
    {$charCount -eq 2}{
      ##version format 1.1.1  
      if ([version]('{0}.{1}.{2}' -f $a.split('.')) -ge [version]('{0}.{1}.{2}' -f $b.split('.'))) {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed $a is equal or greater than $b"
      }
      else {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed Module:$a is lower version than $b"
        #ask for update  
        do { $askyesno = (Read-Host "Do you want to update Module $checkmodule (Y/N)").ToLower() } while ($askyesno -notin @('y','n'))
              if ($askyesno -eq 'y') {
                  Write-Host "Selected YES Updating module $checkmodule"
                  Update-Module -Name $checkmodule -Verbose -Force
                  
                  } else {
                  Write-Host "Selected NO , no updates to Module $checkmodule were done"
                  }
      }  
    }
    {$charCount -eq 3}{ 
      ##version format 1.1.1.1
      if ([version]('{0}.{1}.{2}.{3}' -f $a.split('.')) -ge [version]('{0}.{1}.{2}.{3}' -f $b.split('.'))) {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed $a is equal or greater than $b"
      }
      else {
        Write-Host "Module: $checkmodule"
        Write-Host "Installed Module:$a is lower version than $b"
        #ask for update  
        do { $askyesno = (Read-Host "Do you want to update Module $checkmodule (Y/N)").ToLower() } while ($askyesno -notin @('y','n'))
              if ($askyesno -eq 'y') {
                  Write-Host "Selected YES Updating module $checkmodule"
                  Update-Module -Name $checkmodule -Verbose -Force
                  
                  } else {
                  Write-Host "Selected NO , no updates to Module $checkmodule were done"
                  }
      }  
    }
   }
}

NOTE: the script does not check if the module is available or not. It can only update a installed module.
Putting this skript to a small function isn’t that complicated, so you have a small routine to check your modules and update them if you want.

If you have some feature requests or any other questions, just write me a comment or email. And if you liked the article please click on “helpful”. Have fun with PowerShell.

UPDATED SCRIPT BLOCK 29/11/2020:

#get version of the module (selects the first if there are more versions installed)
$version = (Get-Module -ListAvailable AzureAD) | Sort-Object Version -Descending  | Select-Object Version -First 1
#get version of the module in psgallery
$psgalleryversion = Find-Module -Name AzureAD | Sort-Object Version -Descending | Select-Object Version -First 1
#convert to string for comparison
$stringver = $version | Select-Object @{n='ModuleVersion'; e={$_.Version -as [string]}}
$a = $stringver | Select-Object Moduleversion -ExpandProperty Moduleversion
#convert to string for comparison
$onlinever = $psgalleryversion | select @{n='OnlineVersion'; e={$_.Version -as [string]}}
$b = $onlinever | Select-Object OnlineVersion -ExpandProperty OnlineVersion
#version compare
if ([version]"$a" -ge [version]"$b") {
         Write-Host "Installed $a is greater or equal than $b"
      }
      else {
          Write-Host "Installed Module:$a is lower version than $b"
      }

Complete Script (reduced size):

$update = "AzureAD","OneDrive","ImportExcel"
foreach($checkmodule in $update){
  #getting version of installed module
  $version = (Get-Module -ListAvailable $checkmodule) | Sort-Object Version -Descending  | Select-Object Version -First 1
  #converting version to string
  $stringver = $version | Select-Object @{n='ModuleVersion'; e={$_.Version -as [string]}}
  $a = $stringver | Select-Object Moduleversion -ExpandProperty Moduleversion
  #getting latest module version from ps gallery 
  $psgalleryversion = Find-Module -Name $checkmodule | Sort-Object Version -Descending | Select-Object Version -First 1
  #converting version to string
  $onlinever = $psgalleryversion | select @{n='OnlineVersion'; e={$_.Version -as [string]}}
  $b = $onlinever | Select-Object OnlineVersion -ExpandProperty OnlineVersion
 
  if ([version]"$a" -ge [version]"$b") {
    Write-Host "Module: $checkmodule"
    Write-Host "Installed $a is equal or greater than $b"
  }
  else {
    Write-Host "Module: $checkmodule"
        Write-Host "Installed Module:$a is lower version than $b"
        #ask for update  
        do { $askyesno = (Read-Host "Do you want to update Module $checkmodule (Y/N)").ToLower() } while ($askyesno -notin @('y','n'))
              if ($askyesno -eq 'y') {
                  Write-Host "Selected YES Updating module $checkmodule"
                  Update-Module -Name $checkmodule -Verbose -Force
                  
                  } else {
                  Write-Host "Selected NO , no updates to Module $checkmodule were done"
                  }
  }
 
}
Was this article helpful?
YesNo
0 0 votes
Article Rating
Subscribe
Notify of
guest
5 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
trackback
3 years ago

[…] Check latest PowerShell Module version with PowerShell available first on […]

Robert Eder
Robert Eder
4 years ago

Unless I am missing something, using the version data type, there is no need to differentiate between version notations of 2, 3, or 4 numbers. Even comparing between these different notations works as expected.

[version]’1.1.0′ -gt [version]’1.0.0.0′
[version]’1.1.0′ -gt [version]’1.0′
[version]’1.1.0.0′ -gt [version]’1.0′

All of these return true as expected.

Casting the version return from any of the module cmdlets works no matter the version notation.

[version]$(Find-Module Pester).Version

Olivier
Olivier
4 years ago

Hi Alexander
as you kwow, update module – and particulary lot of modules – takes a long time. Then I’ve another solution to update my installed module : using a job to to this (this doesn’t block me during execution)
Second point : why do this boring task manually, do it easily and automatically. Script planned by scheduled Task ? Possible, but i haven’t choose this way. I’ve choose this way : using my powershell Profile.
Then i propose to add the the following code in your PS profile (or different PS profiles PS, ISE, VSCode) :
$Date = Get-Date
if ($Date.DayOfWeek -eq “friday”)
{
Write-Host “Updating modules in background (Get-Job to check)” -ForegroundColor ‘DarkGray’
Start-Job -Name “UpdateModule” -ScriptBlock {
# this cmdlet is on the PowershellGet module (current version 2.2.5)
Get-InstalledModule |
foreach {
# find the lastest version of the current processed module
$NewVersion = (find-module $_.name).version
# comparing latest version to current processed module
if ($NewVersion -gt $_.version)
{
Write-Host ” the module $($_.name) has a update from $($_.version) to $NewVersion” -ForegroundColor green
Write-Host “updating module $($_.name) to version $NewVersion” -ForegroundColor Yellow
Update-Module -Name ($_.name) -Force -AcceptLicense -Scope CurrentUser
Write-Host “Uninstalling version $($_.version)” -ForegroundColor Yellow
Uninstall-Module -Name $_.name -RequiredVersion $_.version -force
Write-Host “The module $($_.name) has been updated to version $NewVersion” -ForegroundColor Yellow
} # end if
} # end foreach
} # end scriptblock
} # end if

I don’t care about the runtime, this is a background job. When the job is over, i’ve pass the cmdlet Receive-Job UpdateModule and this show the result of the execution.

Hope this help too the readers of your interesting site.