The estimated reading time 10 minutes

Von Zeit zu Zeit kann es hilfreich sein, die aktuell installierten PowerShell Module zu prüfen und ein Update zu installieren. Ja ich weiß, dass es in neueren PowerShell Versionen dafür ein cmdlet gibt: Update-Module (PS-Version 5.1).
https://docs.microsoft.com/en-us/powershell/module/powershellget/update-module?view=powershell-5.1

Allerdings wollte ich eine Funktion bzw. einen Mechanismus haben, bei dem ich steuern kann ob ein Update gemacht wird oder nicht und welcher die Versionsnummern vergleichen kann. Versionsnummer vergleichen kann auch in anderen Bereichen von Vorteil sein. Also habe ich etwas Recherche betrieben und bin mit einer .Net Framework Klasse fündig geworden. Einige Seiten weiter gab es dann die quasi fertige Anwendung der Klasse.

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"
      }

Mit dieser relativ einfachen “IF” Abfrage kann eine Versionsnummer abgefragt und verglichen werden, ob höher oder gleich. Sieht schon mal gar nicht so schlecht aus.

UPDATE, der einfachere Weg als meine Lösung:

[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'

Diese Beispiele geben jeweils immer TRUE zurück, sodass keine weitere Unterscheidung der Versionsnummer gemacht werden muss.

Aktualisiertes Script am Ende des Artikels.


DIE NACHFOLGENDEN PUNKTE können ignoriert werden

Wer also in der PowerShell Get-Module -ListAvailable eintipp, stellt relativ schnell fest, dass es verschiedene Versionierungsnummer gibt. Manchmal wird 1.0.0.0 verwendet, manchmal 1.0.0 also keine einheitliche Nummerierung.

Wie kann dies abgefangen werden?
Leider weiß ich nicht so genau ob meine Methode ein komplett gangbare ist, in meinem Szenario hat die nachfolgende Methode gut funktioniert. Kurz beschrieben: die Versionsnummer wird in einen String konvertiert und dann die Punkte gezählt. Los geht’s.

#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” ist nun die Anzahl der Punkte in der Versionsnummer.
Also geht’s nun mit der Anzahl der Punkte weiter und es wird ein sogenannter “Switch Case” erstellt. Dieser kann so aussehen:

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('.'))) {...}

}

Mit dem Switch-Case kann entsprechend auf die Anzahl der Versionen reagiert werden und dann auch die entsprechend richtige .Net Klasse angesteuert werden. Als nächstes Verpacken wir das Ganze noch eine Foreach-Schleife, somit können mehrere Module geprüft werden.

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

Alles zusammen gewürfelt ergibt dann folgendes Skript:

$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"
      }  
    }
   }
}

Gar nicht mal so schlecht, als nächsten Schritt soll noch eine Abfrage kommen, ob das Modul bei einer älteren Version ein Update erhalten soll oder nicht. Das habe ich folgendermaßen gelöst:

#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"
                  }

Wie den Screenshots zu entnehmen ist, kann hier tatsächlich nur Y oder N eingegeben werden.
-> Nochmals alles zusammen in einem Skript sieht dann so aus:

$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"
                  }
      }  
    }
   }
}

HINWEIS: das Skript kann aktuell nicht überprüfen ob das Modul existiert oder nicht. Es kann nur bereits installierte Module aktualisieren.

Das ganze Skript kann dann auch noch in eine Funktion integriert werden, sollte eigentlich kein großes Problem sein. Damit hat man eine kleine Routine die PS Module updated oder eben nicht.

Solltet ihr Fragen /Anregungen zum Skript oder auch Funktionsanfragen haben, benutzt einfach das Kommentarfeld am Ende des Artikels. Hat euch der Beitrag gefallen, klickt auf “Helpful”.
Viel Spaß mit PowerShell.

UPDATE 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"
      }

Das komplette Skript (reduziert):

$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"
                  }
  }
 
}
Print Friendly, PDF & Email
  • Was this Helpful ?
  • yes   no