Skip to the main content.

ScriptRunner Blog

Der Schlüssel zu produktiver Softwareverwaltung: winget & PowerShell

Inhaltsverzeichnis 

Post Featured Image

Steigere die IT-Effizienz mit Winget und PowerShell! Lies, wie du Installationen, Updates und die Verwaltung von Anwendungen nahtlos automatisieren kannst.

In den letzten Jahren hat Microsoft Ressourcen in seinen Paketmanager winget.exe investiert. Winget ist ein Befehlszeilen-Paketmanager, mit dem du deine Lieblingsanwendungen mit einem einzigen Befehl installieren kannst. Ohne in eine unattraktive Hintergrundgeschichte einzusteigen, kannst du Winget jetzt mit PowerShell verwalten. In diesem Beitrag zeige ich, wie das Microsoft.Winget.Client Modul verwendet wird, um Winget mit PowerShell auf dem Desktop zu verwalten.

 

Vorbereitung

Natürlich muss Winget auf dem Rechner installiert sein. Die Anwendung ist ein Microsoft Open-Source-Projekt. Winget sollte in neueren Windows 11-Installationen enthalten sein. Allerdings muss es höchstwahrscheinlich aktualisiert werden. Führe winget -v aus, um die installierte Version zu überprüfen und sie mit der neuesten stabilen Version auf GitHub zu vergleichen.

Wenn es es nicht installiert ist, kannst du es aus dem Microsoft Store, der GitHub-Release-Seite oder über PowerShell herunterladen.


Invoke-WebRequest -Uri https://aka.ms/getwinget -OutFile Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle
Invoke-WebRequest -Uri https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx -OutFile Microsoft.VCLibs.x64.14.00.Desktop.appx
Invoke-WebRequest -Uri https://github.com/microsoft/microsoft-uixaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx -OutFile Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.VCLibs.x64.14.00.Desktop.appx
Add-AppxPackage Microsoft.UI.Xaml.2.8.x64.appx
Add-AppxPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle

 

Du kannst dieselben Befehle unter Windows 11 ausführen, um winget auf die neueste Version zu aktualisieren. Die Pakete VCLibs und Ui.Xaml sind Abhängigkeiten, die möglicherweise nicht aktualisiert werden müssen. Wenn du die Fehlermeldung erhältst, dass sie bereits auf der neuesten Version sind, mach dir keine Sorgen.

Für den Moment sollte winget als ein interaktives Desktop-Paketmanagement-Tool betrachtet werden. Du benötigst mindestens Windows 10 1809. Die einzige Serverunterstützung gibt es unter Windows Server 2022 und selbst das gilt als experimentell.

Ich empfehle, einige Zeit mit dem nativen winget Kommandozeilen-Tool zu verbringen. Das PowerShell-Modul ist ein Wrapper um die zugrundeliegenden winget APIs, und wenn du nicht verstehst, wie winget arbeitet, kann das PowerShell-Modul etwas verwirrend sein. Dieser Ratschlag gilt für alles, was eine PowerShell-Verwaltungsebene hat. Mache dich mit der Verwendung nativer Tools vertraut, bevor du beginnst PowerShell-äquivalenten Befehle zu verwenden.

 

Installation des Moduls

Das PowerShell-Modul für den winget Client ist ebenfalls ein Open-Source-Projekt. Du kannst das Modul in der PowerShell-Galerie finden und installieren.

Find-Module Microsoft.winget.Client

Wenn du neu mit PowerShell umgehst, wirst du möglicherweise aufgefordert, den NuGet-Anbieter zu aktualisieren. Mache das ruhig.

Nach rechts weisender Zeigefinger (Handrücken)Anmerkung: Nach rechts weisender Zeigefinger (Handrücken)Das Modul wird auf Windows PowerShell und PowerShell 7 unterstützt.

Installiere das Modul:

Install-Module Microsoft.winget.Client -Scope CurrentUser

Konzeptionell ist winget ein benutzerspezifisches Tool, daher verwende ich den Bereich CurrentUser, aber das macht keinen Unterschied. Nochmals, wenn du neu in PowerShell bist, antworte mit Ja, wenn du aufgefordert wirst, aus einem nicht vertrauenswürdigen Repository zu installieren.

 

Wichtige Modul-Befehle

Das Modul enthält viele Befehle.


PS C:\> Get-Command -Module Microsoft.`winget`.Client | Select Name 

Name
----
Add-WinGetSource
Assert-WinGetPackageManager
Deaktivieren-WinGetSetting
Aktivieren-WinGetSetting
Exportieren-WinGetPackage Finden-WinGetPackage
Get-WinGetPackage
Get-WinGetSettings
Hole-WinGetQuelle
Get-WinGetUserSettings
Get-WinGetVersion
Installieren-WinGetPackage
Entfernen-WinGetSource
Reparieren-WinGetPackageManager
Zurücksetzen-WinGetSource
Setzen-WinGetUserSettings
Test-WinGetUserSettings
Deinstallieren-WinGetPackage
Update-WinGetPackage

Ich werde nicht alle davon durchgehen, aber ich werde Ihnen einige der nützlichsten zeigen.

Eine Sache, der man sich bewusst sein sollte, zumindest zu dem Zeitpunkt, an dem ich dies schreibe, ist, dass die Hilfedokumentation des Moduls minimal ist.

Ich weiß, dass das Team hinter dem Modul eine Cmdlet-Hilfe schreibt, die hoffentlich Teil der nächsten Version sein wird. Zumindest sind die Befehlsnamen aussagekräftig und folgen der PowerShell Verb-Nomen-Namenskonvention.


PS C:\> Get-WingetVersion
v1.8.1911
PS C:\> winget -v
v1.8.1911

Denke daran, dass die PowerShell-Befehle Wrapper für das zugrunde liegende winget-Kommandozeilenwerkzeug sind. Das PowerShell-Modul fügt keine Funktionen hinzu, die du nicht mit winget ausführen kannst. Was man erhält, sind PowerShell-Funktionen wie Pipeline-Unterstützung und WhatIf.

Das bedeutet auch, dass alle Unzulänglichkeiten des Befehlszeilentools sich im PowerShell-Modul widerspiegeln werden.

 

Befehl: Find-WinGetPackage

Du kannst winget so konfigurieren, dass es mehrere Quellen verwendet, darunter auch den Microsoft Store. Für meine Demonstrationen werde ich die Standard-winget Quelle verwenden. Verwende den Befehl Find-WinGetPackage, um nach einem Paket zu suchen. Ich möchte die neueste PowerShell 7-Vorschau installieren. Es gibt mehrere Parameter, mit denen sich die Ergebnisse filtern lassen, wie -Tag oder -Id. Oder mach es so, was ich normalerweise tue, und verwenden einen allgemeinen Namen wie PowerShell.

 

Von hier aus kann ich meine Suche eingrenzen und das Paket bestätigen, das ich installieren möchte.

Find-WinGetPackage -id Microsoft.PowerShell.Preview -Source winget

Im Gegensatz zu winget, das Ihnen Text liefert, gibt das PowerShell-Modul Objekte mit definierten Eigenschaften zurück.


PS C:\> Find-WinGetPackage -id Microsoft.PowerShell.Preview -Source winget | Select *
Version : 7.5.0.3
Name : PowerShell-Vorschau
Kennung : Microsoft.PowerShell.Preview
IsUpdateAvailable : False
Quelle : winget
AvailableVersions : {7.5.0.3, 7.5.0.2, 7.5.0.1, 7.4.0.101...}

 

Bei der Suche nach Paketen muss man vorsichtig sein. Auch wenn PowerShell standardmäßig nicht zwischen Groß- und Kleinschreibung unterscheidet, kann winget heikel sein. Mit dem nativen Befehl kannst du Folgendes versuchen:


PS C:\> winget find --id microsoft.windowsterminal --source winget
Name Id Version
-----------------------------------------------------------------------
Windows-Terminal Microsoft.WindowsTerminal 1.20.11781.0
Windows Terminal Vorschau Microsoft.WindowsTerminal.Preview 1.21.1772.0

 

Die Vorschau-Version will man nicht haben, versuche es mit PowerShell zu finden:


PS C:\> Find-WinGetPackage -id Microsoft.WindowsTerminal
Name Id Version Quelle
---- -- ------- ------
Windows Terminal Microsoft.WindowsTerminal 1.20.11781.0 winget
Windows Terminal Vorschau Microsoft.WindowsTerminal.Preview 1.21.1772.0 winget

 

Dies ist nicht so spezifisch, wie du vielleicht denkst.Du musst den Parameter Equal einschließen, wie du es im nativen Befehl tun würdest.


PS C:\> winget find --id microsoft.windowsterminal --source winget --exact No package found matching input criteria.
PS C:\> winget find --id Microsoft.WindowsTerminal --source winget --exact Name Id Version
------------------------------------------------------- Windows Terminal Microsoft.WindowsTerminal 1.20.11781.0

 

Beachte, dass die Groß- und Kleinschreibung eine Rolle spielt.


PS C:\> Find-WinGetPackage -id Microsoft.WindowsTerminal -MatchOption Equals

Name Id Version Quelle
---- -- ------- ------
Windows Terminal Microsoft.WindowsTerminal 1.20.11781.0 winget

 

Auch in der Welt von winget wird zwischen dem zu installierenden Paket und seinem Manifest unterschieden. Mit dem show-Befehl kann man mehr über das Paket aus seinem Manifest erfahren.

winget show --id Microsoft.PowerShell.Preview --source winget

 

Befehl: Install-WinGetPackage

Wenn du das gewünschte Paket gefunden hast, rufe den Find-Befehl erneut auf und leiten ihn über die Pipeline an Install-WinGetPackage weiter.

Find-WinGetPackage -id Microsoft.PowerShell.Preview -Source winget | InstallWinGetPackage

Ich finde es am besten, bei der Installation so spezifisch wie möglich zu sein. Ich verwende gerne den Parameter -Id, um das zu installierende Paket anzugeben. Auf diese Weise kann ich sicher sein, dass ich das gewünschte Paket erhalte.

Install-WinGetPackage -Id Dropbox.Dropbox -Source winget

 

Warnung  Warnung  Warnung
Es gibt ein großes Problem mit dem Install-WinGetPackage Befehl, das als GitHub-Problem abgelegt wurde. Obwohl der Befehl sagt, dass er -WhatIf unterstützt, tut er das nicht. Wenn ich versuche, Install-WinGetPackage -Id Dropbox.Dropbox -Source winget -Verbose -WhatIf auszuführen, installiert der Befehl das Paket. Ich muss davon ausgehen, dass dies in einer zukünftigen Version behoben wird, da es für das PowerShell-Paradigma grundlegend ist.

 

Befehl: Get-WinGetPackage

Get-WinGetPackage zeigt bekanntlich alle installierten Pakete an. Allerdings zeigt der Befehl standardmäßig auch installierte AppX-Pakete wie "Phone Link" und "Notepad" an. Obwohl es einen -Source Parameter gibt, scheint dieser nicht zu funktionieren. Mit Where-Object lassen sich die Ergebnisse filtern.

Get-WinGetPackage | Where Source -eq 'winget' | Select Name,ID,InstalledVersion

 

Wenn du ein bestimmtes Paket wünschst, musst du wie zuvor auf die Groß- und Kleinschreibung achten.


PS C:\> Get-WinGetPackage -Name PowerShell -MatchOption Equals
Name Id Version Verfügbar Quelle
---- -- ------- --------- ------
PowerShell Microsoft.PowerShell 7.4.4.0 winget

 

Befehl: Update-WinGetPackage

Im Laufe der Zeit müssen Pakete aktualisiert werden. Die Ausgabe von Get-WinGetPackage hat eine praktische Eigenschaft, die man hier nutzen kann.


PS C:\> Get-WinGetPackage | Where {$_.Source -eq 'WinGet' -AND $_.IsUpdateAvailable}
Name Id Version Available Source
---- -- ------- --------- ------
GitHub CLI GitHub.cli 2.52.0 2.54.0 winget
Dev Home (Vorschau) Microsoft.DevHome 0.1600.561.0 0.1601.561.0 winget
Windows Terminal Microsoft.WindowsTerminal 1.12.10983.0 1.20.11781.0 winget

 

Nur einfach Update-WinGetPackage auszuführen reicht allerdings nicht, es aktualisiert nicht automatisch alles, du musst genauere Vorgaben machen.

Get-WinGetPackage | Where {$_.Source -eq 'WinGet' -AND $_.IsUpdateAvailable}

Die Paketaktualisierungen sollten still und unbeaufsichtigt erfolgen. Am Ende des Prozesses gibt der Befehl ein zusammenfassendes Ergebnis aus.

 

Totenkopf mit gekreuzten Knochen Vorsicht Totenkopf mit gekreuzten Knochen
Unglücklicherweise leidet der Update-WinGetPackage-Befehl unter dem gleichen Fehler wie Install-WingetPackage.
Die Syntax deutet darauf hin, dass er -WhatIf unterstützt, aber das tut er nicht.

 

Befehl: Uninstall-WinGetPackage

Um ein Paket zu entfernen, verwendest du den Befehl Uninstall-WinGetPackage. Um das Paket zu finden, das du entfernen möchtest, kannst du den Befehl Get-WinGetPackage verwenden. Wie bei den anderen Befehlen, muss der Befehl spezifisch sein.


PS C:\> Uninstall-WinGetPackage -id Git.Git -MatchOption Equals
Id Name Quelle UninstallerErrorCode Status RebootRequired ExtendedErrorCode CorrelationData
-- ---- ------ -------------------- ------ -------------- ----------------- --- ------------
Git.Git Git winget 0 Ok False

Wenn bei der Deinstallation ein Fehler auftritt, wird kein PowerShell-Fehler angezeigt, sondern ein oder mehrere Fehler in der Ausgabe. PowerShell gibt eine Ausnahme aus, wenn der Befehl Uninstall-WinGetPackage fehlschlägt, z. B. wenn das Paket nicht gefunden werden kann.

 

Skripterstellung WinGet Management

Wo sich dieses Modul trotz der Unzulänglichkeiten lohnt, ist bei der Skripterstellung. Verwende das Modul, um die Verwaltung deiner Desktop-Anwendungen zu automatisieren. Dies ist beim Aufbau von Testsystemen nützlich. Oder wenn du sicherstellen willst, dass dein Desktop so konfiguriert ist, wie du es brauchst. Es ist viel einfacher, Skripte mit PowerShell zu erstellen, als das native winget-Befehlszeilentool zu verwenden.

Hier kommen ein paar Beispiele dazu. Zunächst habe ich eine JSON-Datei mit den Paketen erstellt, von denen ich sicherstellen möchte, dass sie installiert und auf dem neuesten Stand sind. Ich führe einen Befehl wie den folgenden aus, um die Datei zu erstellen.


Get-WingetPackage | Where-Object { $_.Source -eq 'winget' } |
Select-Object Name,ID | ConvertTo-Json |
Out-File -FilePath D:\temp\winget.json -Encoding utf8

Dann wird die Datei so bearbeitet, dass sie nur die Pakete enthält, die installiert werden sollen.
Ich verwende JSON, aber du kannst jedes Format verwenden, das dir zusagt.


[
{
"Name": "Git", "Id": "Git.Git"
},
{
"Name": "Mozilla Firefox", "Id": "Mozilla.Firefox"
},
{
"Name": "Mozilla Thunderbird", "Id": "Mozilla.Thunderbird"
},
...

 

Ich nutze dieses Skript, das die JSON-Datei liest und die Pakete installiert, wenn sie nicht bereits installiert sind. Wenn das Paket installiert ist, dann wird es nach Updates suchen.


#requires -Version 5.1 #requires -RunAsAdministrator #requires -module Microsoft.Winget.Client

#WingetMaster.ps1

[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(HelpMessage = 'Pfad zur winget.json Datei')]
[ValidateScript({ Test-Path $_ })]
[string]$Path = '.winget.json'
)

#Piping konvertierte Ausgabe, um einen Formatierungsfehler in Windows PowerShell zu beheben
$find = Get-Content -Path $Path -Encoding utf8 |
ConvertFrom-Json |
foreach { $_ } |
Find-WinGetPackage -Source winget -match Equals

foreach ($pkg in $find) {
$r = Get-WinGetPackage -Id $pkg.Id -MatchOption Equals
if ($null -eq $r) {
#Installiere das Paket, wenn es nicht bereits installiert ist
Write-Host "Installing $($pkg.Id)" -ForegroundColor Cyan

#verwendet meinen eigenen WhatIf-Code
if ($PSCmdlet.ShouldProcess($pkg.Id, 'Install-WinGetPackage')) {
Install-WinGetPackage -Id $pkg.Id
}
}
elseif ($r.IsUpdateAvailable) {
#Update des Pakets, wenn eine neue Version verfügbar ist
Write-Host "Updating $($pkg.Id)" -ForegroundColor Yellow
if ($PSCmdlet.ShouldProcess($pkg.Id, 'Update-WinGetPackage')) {
Update-WinGetPackage -Id $pkg.Id
}
}
else {
Write-Host "$($pkg.Id) is already installed" -ForegroundColor Green
}
} #foreach

Write-Host "$($MyInvocation.MyCommand) completed" -ForegroundColor Green

 

Mein Code fügt Unterstützung für WhatIf hinzu, die funktioniert.

Das kannst du so oft ausführen, wie du möchtest. Es installiert nichts, was bereits installiert oder aktuell ist.

Ich habe auch ein Tool, mit dem ich ausgewählte Pakete aktualisieren kann. Dieses Skript benötigt PowerShell 7 und das Microsoft.PowerShell.ConsoleGuiTools Modul.


#requires -version 7.3
#requires -Module Microsoft.Winget.Client
#requires -Module Microsoft.PowerShell.ConsoleGuiTools

#UpdateWingetPackages.ps1

[CmdletBinding()]
Param()
#17 Jan 2024 Ausnahmen in eine externe Datei verschoben
[string]$Exclude = (Get-Content $PSScriptRoot\WingetExclude.txt | Where-Object {$_ -notMatch "^#" -AND $_ -match "\w+"}) -join "|"

#10 Jan 2024 Updates parallel aufrufen
$sb = {
Param($MyExclude)
Write-Progress "[$((Get-Date).TimeOfDay)] Checking for Winget package updates"
Get-WinGetPackage -Source Winget |
Where-Object {$_.Source -eq 'winget' -AND
$_.IsUpdateAvailable -AND ($_.InstalledVersion -notMatch "unknown|\<") -AND ($_.Name -notMatch $myExclude)} |
Out-ConsoleGridView -Title "Select Winget packages to upgrade" -OutputMode Multiple |

Foreach-Object -Parallel {
$Name = $_.Name
Write-Host "[$((Get-Date).TimeOfDay)] Updating $($_.Name)" -ForegroundColor Green
# 22. April 2024 Fehlerbehandlung hinzugefügt, um eine sinnvolle Ausnahmemeldung zu schreiben
Try {
Update-WinGetPackage -mode Silent -ID $_.ID -Source Winget -ErrorAction Stop |
Select-Object @{Name="Package";Expression= {$Name}},RebootRequired,InstallerErrorCode,Status
}
Catch {
Write-Warning "Failed to update $Name. $($_.Exception.Message)"
}
}
}
Try {
#Überprüfe, ob die Befehle des Winget-Moduls ausgeführt werden. Es kann Assembly-Konflikte mit dem ConsoleGuiTools-Modul geben
$null = Get-WinGetVersion -ErrorAction stop
Invoke-Command -ScriptBlock $sb -ArgumentList $Exclude
}
Catch {
#write-warning $_.Exception.message
#Ausführen der Aufgabe in einer sauberen PowerShell-Sitzung, um Assembly-Konflikte zu vermeiden
pwsh -NoLogo -NoProfile -command $sb -args $Exclude
}

 

Ich habe mehrere Pakete, die ich entweder auf einer bestimmten Version halten möchte, wegen Kompatibilitätsproblemen nicht aktualisieren möchte oder es vorziehe, Aktualisierungen mit anderen Mitteln zu verwalten. Mein Skript verwendet eine exclude-Datei, um diese Pakete zu definieren.



#wingetexclude.txt

#Winget-Pakete, die von UpdateWingetPackages.ps1 auszuschließen sind
#Diese Datei muss sich im selben Verzeichnis wie das Update-Skript befinden
#Paketnamen werden in einem Regex-Muster verwendet

MuseScore
Python
ESET
Discord
Camtasia
Dymo
Spotify
PowerShell
FoxIt

Wenn ich das Skript ausführe, werden die Pakete mit verfügbaren Updates über Out-ConsoleGridView angezeigt.

Ich kann die Pakete auswählen, die ich aktualisieren möchte, und auf OK klicken. Der andere Grund, warum ich PowerShell 7 verwende, ist, dass ich die Updates parallel ausführen kann. So lassen sich mehrere Pakete schnell aktualisieren.

 

Fazit

Ich hoffe, dass die nächste Version des Moduls Microsoft.Winget.Client eine solidere Hilfedokumentation enthält und einige Bugs behebt. Das Modul ist eine großartige Möglichkeit, die Verwaltung deiner Desktop-Anwendungen zu automatisieren, wenn du ein Winget-Benutzer bist. Du kannst es verwenden, um sicherzustellen, dass dein Desktop so konfiguriert ist, wie du es brauchst, oder du kannst es verwenden, um Labor- oder Testmaschinen schnell zu konfigurieren. Winget ist immer noch in erster Linie ein Desktop-Tool. Ich weiß, dass eine Winget DSC-Ressource in Arbeit ist, die Serverbedürfnisse ansprechen könnte, aber das ist ein Thema für einen anderen Beitrag.

Ich möchte dich ermutigen, das Modul auszuprobieren und es zu testen. Meldet Probleme und startet Diskussionen im GitHub-Repository. Je mehr Feedback das Team bekommt, desto besser wird das Modul werden und wir werden alle davon profitieren.

 

Alle unsere Goodies für dich auf einer Seite: Active Directory, Graph, Teams, Exchange, PowerShell allgemein und mehr zum Thema Sicherheit

Dein ultimativer PowerShell-Spickzettel

Entfessele das volle Potenzial von PowerShell mit unserem praktischen Poster. Egal, ob frischer Einsteiger oder erfahrener Profi, dieser Spickzettel ist so konzipiert, dass du schnell die wichtigsten und am häufigsten verwendeten Cmdlets findest.

Das Poster ist zum Download und in Papierform erhältlich.

PowerShell Poster 2023

Hol dir hier dein Poster!

 

 

Weiterführende Links 

Zusammenhängende Posts

14 min read

Der Schlüssel zu produktiver Softwareverwaltung: winget & PowerShell

Steigere die IT-Effizienz mit Winget und PowerShell! Lies, wie du Installationen, Updates und die Verwaltung von...

9 min read

Diese 10 Aufgaben löst du perfekt mit PowerShell für Microsoft Purview

Mit Microsoft Purview verstehst und verwaltest du Daten in deinem gesamten Datenbestand – wie kannst du PowerShell...

14 min read

Microsoft Teams – 3. Teil der Graph PowerShell Reihe

MVP Damien Scoles berichtet über seine Erfahrungen mit Microsoft Graph. In seinem dritten Artikel geht er näher auf...

Über den Autor: