Warning: mysqli_query() [function.mysqli-query]: (HY000/2013): Lost connection to MySQL server during query in /home/powert21/public_html/wp-includes/wp-db.php on line 1924

Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at /home/powert21/public_html/wp-includes/wp-db.php:1924) in /home/powert21/public_html/wp-content/themes/parallelus-razor/framework/utilities/email-functions.php on line 3

Warning: session_start() [function.session-start]: Cannot send session cache limiter - headers already sent (output started at /home/powert21/public_html/wp-includes/wp-db.php:1924) in /home/powert21/public_html/wp-content/themes/parallelus-razor/framework/utilities/email-functions.php on line 3
Lightning Fast Online Approach to Find Most Current Module Version
Home Blog Lightning Fast Online Approach to Find Most Current Module Version
 

Lightning Fast Online Approach to Find Most Current Module Version

How can you check for the latest module version available at powershellgallery.com? Update-Module would work, but it’s slow – and it does not work without first installing PowerShellGet or using PowerShell 5+. Here is a creative approach that lets you check for latest versions fast.

It works for any module available at powershellgallery.com, including – but not limited to – ISESteroids.

Getting Available Module Versions Online – fast

Here is a function called Get-PublishedModuleVersion that returns the most current version for any module published to the PowerShellGallery:

function Get-PublishedModuleVersion($Name)
{
   # access the main module page, and add a random number to trick proxies
   $url = "https://www.powershellgallery.com/packages/$Name/?dummy=$(Get-Random)"
   $request = [System.Net.WebRequest]::Create($url)
   # do not allow to redirect. The result is a "MovedPermanently"
   $request.AllowAutoRedirect=$false
   try
   {
     # send the request
     $response=$request.GetResponse()
     # get back the URL of the true destination page, and split off the version
     $response.GetResponseHeader("Location").Split("/")[-1] -as [Version]
     # make sure to clean up
     $response.Close()
     $response.Dispose()
   }
   catch
   {
     Write-Warning $_.Exception.Message
   }
}

Get-PublishedModuleVersion -Name ISESteroids

When you run this example, the result looks similar to this:

PS> Get-⁠PublishedModuleVersion -⁠Name ISESteroids

Major  Minor  Build  Revision
-----  -----  -----  --------
2      6      3      18



PS> Get-⁠PublishedModuleVersion -⁠Name PSReadLine

Major  Minor  Build  Revision
-----  -----  -----  --------
1      2      -⁠1     -⁠1



PS> Get-⁠PublishedModuleVersion -⁠Name doesnotexist
WARNUNG: "Remoteserver returned an error message: (404) Not found."

PS> Get-⁠PublishedModuleVersion -⁠Name Carbon

Major  Minor  Build  Revision
-----  -----  -----  --------
2      3      0      -⁠1



PS>

How it works

In previous solutions, to find version information, PowerShell would retrieve webpages, then parse the raw HTML for version strings with regular expressions. HTML scraping works reasonably well, but it is slow and vulnerable to changes in the HTML structure of the web page queried.

Get-PublishedModuleVersion uses a completely different approach. It’s fast and much less a strain on ressources and data transfer. It takes advantage of the fact that when you query powershell gallery for a module name (without version), it redirects you to the page with the most current version.

So the function turns off automatic redirection, receives a “MovedPermanently” error message from the webserver, and queries for the new URL – which happens to end with the version number.

Next steps

To actually use this information for auto-updates, here is a first brain teaser that works just for ISESteroids. It does not require PowerShellGet or anything else. You get a message telling you whether ISESteroids is up to date or has updates:


$availableVersion = Get-PublishedModuleVersion -Name ISESteroids
$currentVersion = Get-SteroidsVersion
if ($availableVersion -gt $currentVersion)
{
   Write-Host "Time to update from $currentVersion to $availableVersion!" -ForegroundColor DarkYellow
}
else
{
   Write-Host 'ISESteroids is up to date.' -ForegroundColor Green
}

If you run PowerShell 5 or have installed PowerShellGet from www.powershellgallery.com, you can slightly change the example, and actually invoke an auto-update. Here is an example that updates PSReadLine. Simply change $name to “ISESteroids” or any other module that was originally installed using Install-Module:


$name = 'PSReadLine'

$availableVersion = Get-PublishedModuleVersion -Name $name
$info = Get-InstalledModule -Name $name 
if ($info -eq $null)
{
   Write-Warning "$name was not installed using PowerShellGet!"
   return
}

$currentVersion = $info.Version

if ($availableVersion -gt $currentVersion)
{
   Write-Warning "Updating $name from $currentVersion to $availableVersion..."
   $info | Update-Module -Verbose
}
else
{
   Write-Host "$Name is up to date." -ForegroundColor Green
}

The result could look similar to this (excuse the German verbose messages):

PS> . 'C:\Users\Tobias\Documents\powershell\Unbenannt6.ps1' <# script is not saved yet #>
WARNUNG: Updating PSReadLine from 1.0.0.13 to 1.2...
AUSFÜHRLICH: Checking for updates for module 'PSReadline'.
AUSFÜHRLICH: Repository details, Name = 'PSGallery', Location = 'https://www.powershellgallery.com/a
pi/v2/'; IsTrusted = 'False'; IsRegistered = 'True'.
AUSFÜHRLICH: Using the provider 'PowerShellGet' for searching packages.
AUSFÜHRLICH: Using the specified source names : 'PSGallery'.
AUSFÜHRLICH: Getting the provider object for the PackageManagement Provider 'NuGet'.
AUSFÜHRLICH: The specified Location is 'https://www.powershellgallery.com/api/v2/' and PackageManage
mentProvider is 'NuGet'.
AUSFÜHRLICH: Searching repository 'https://www.powershellgallery.com/api/v2/FindPackagesById()?id='P
SReadline'' for ''.
AUSFÜHRLICH: Total package yield:'1' for the specified package 'PSReadline'.
AUSFÜHRLICH: Ausführen des Vorgangs "Update-⁠Module" für das Ziel "Version '1.0.0.13' of module 'PSRe
adline', updating to version '1.2'".
AUSFÜHRLICH: The installation scope is specified to be 'CurrentUser'.
AUSFÜHRLICH: The specified module will be installed in 'C:\Users\Tobias\Documents\WindowsPowerShell\
Modules'.
AUSFÜHRLICH: An update for the module 'PSReadline' was found with version '1.2'.
AUSFÜHRLICH: The specified Location is 'NuGet' and PackageManagementProvider is 'NuGet'.
AUSFÜHRLICH: Downloading module 'PSReadline' with version '1.2' from the repository 'https://www.pow
ershellgallery.com/api/v2/'.
AUSFÜHRLICH: Searching repository 'https://www.powershellgallery.com/api/v2/FindPackagesById()?id='P
SReadline'' for ''.
AUSFÜHRLICH: InstallPackage' - name='PSReadline', version='1.2',destination='C:\Users\Tobias\AppData
\Local\Temp\1701878808'
AUSFÜHRLICH: DownloadPackage' - name='PSReadline', version='1.2',destination='C:\Users\Tobias\AppDat
a\Local\Temp\1701878808\PSReadline\PSReadline.nupkg', uri='https://www.powershellgallery.com/api/v2/
package/PSReadline/1.2.0'
AUSFÜHRLICH: Downloading 'https://www.powershellgallery.com/api/v2/package/PSReadline/1.2.0'.
AUSFÜHRLICH: Completed downloading 'https://www.powershellgallery.com/api/v2/package/PSReadline/1.2.
0'.
AUSFÜHRLICH: Completed downloading 'PSReadline'.
AUSFÜHRLICH: Hash for package 'PSReadline' does not match hash provided from the server.
AUSFÜHRLICH: InstallPackageLocal' - name='PSReadline', version='1.2',destination='C:\Users\Tobias\Ap
pData\Local\Temp\1701878808'
AUSFÜHRLICH: Module 'PSReadline' was installed successfully.

PS>

Things to consider

Why take this effort in the first place? Couldn’t you just run “Update-Module -Name WhatEver”? Yes you could, but:

  • When Update-Module checks for versions, it is pretty slow. So when your module is up to date, and you perform this call frequently, for example in your profile script, it slows down launch times tremendously.
  • Update-Module works only when the module was initially installed using PowerShellGet and Install-Module. It will not work with manual installs.

Some more things to keep in mind:

  • When you run Update-Module as a regular user, but the module was originally installed for all users by an Admin, it obviously fails.
  • When you run Update-Module on a module that originally was not installed via Install-Module, like PSReadLine on Windows 10, it fails. You would have to initially install it via Install-Module. Use -Force to overwrite existing module installations if necessary.
  • When you run PowerShell 3 or 4, you would need to first download and install the MSI Package for PowerShellGet from powershellgallery.com to use Update-Module and Install-Module. Even then, updates via Update-Module would probably not always run smoothly. Only PowerShell 5 and better comes with side-by-side module installs, so a new version can be installed side-by-side to an existing module version. That’s important because frequently, modules are in use and cannot be updated while being used. Side-by-side installations solve this problem easily. Again, that’s a gift brought to you by PowerShell 5 or better.
  • Updates from untrusted sources like powershellgallery.com require consent, so it won’t work unattended – unless you use Set-PSRepository to change the “InstallationPolicy” to trusted.

Happy coding! And don’t forget: psconf.eu 2017 signup starts Nov 1, 2016. Go check www.psconf.eu for details. Website will be updated  Nov 1.