Einleitung
Wer nur einen Windows-PC verwaltet, kann benötigte Programme problemlos einzeln installieren:
winget install --id Mozilla.Firefox --exact
Bei einem zweiten Rechner folgen weitere Befehle:
winget install --id 7zip.7zip --exact winget install --id VideoLAN.VLC --exact winget install --id Microsoft.PowerToys --exact
Spätestens wenn regelmäßig neue Rechner eingerichtet werden, wird dieses Verfahren jedoch mühsam.
Welche Programme benötigt ein Entwickler?
Welche Anwendungen gehören auf einen Office-PC?
Welche Werkzeuge benötigt ein Administrator?
Und welche Programme sollen auf einem Gaming-Rechner vorhanden sein?
Statt diese Entscheidungen bei jedem neuen System erneut zu treffen, können wir Softwareprofile definieren.
Das Prinzip lautet:
Rechnertyp
↓
Softwareprofil
↓
Paket-IDs
↓
Winget
↓
automatische Installation
Damit wird Winget zu einem Werkzeug für standardisierte Windows-Installationen.
Was ist eine eigene Softwareliste?
Winget besitzt nicht den einen speziellen Dateityp namens „Softwareliste“. Für dieses Ziel können vielmehr verschiedene Mechanismen verwendet werden.
Die einfachste Variante ist ein PowerShell-Skript:
winget install --id Mozilla.Firefox --exact winget install --id 7zip.7zip --exact winget install --id VideoLAN.VLC --exact
Eleganter wird es mit einem PowerShell-Array:
$Packages = @(
"Mozilla.Firefox"
"7zip.7zip"
"VideoLAN.VLC"
)
foreach ($Package in $Packages) {
winget install --id $Package --exact
}
Eine weitere Möglichkeit kennen wir bereits aus Teil 8:
winget export
und:
winget import
Für umfassendere deklarative Konfigurationen steht zusätzlich winget configure zur Verfügung.
Damit haben wir mehrere Möglichkeiten, Softwareprofile aufzubauen.
Warum Paket-IDs verwenden?
Wie bereits in den vorherigen Teilen sollte bei automatisierten Installationen möglichst nicht ausschließlich mit sichtbaren Programmnamen gearbeitet werden.
Also besser nicht:
winget install firefox
sondern:
winget install --id Mozilla.Firefox --exact
Die Paket-ID ermöglicht eine eindeutige Zuordnung.
Ein Softwareprofil besteht deshalb im Kern aus einer Sammlung solcher IDs:
Mozilla.Firefox 7zip.7zip VideoLAN.VLC Microsoft.PowerToys Microsoft.VisualStudioCode Git.Git
Damit kann Winget exakt bestimmen, welche Pakete gemeint sind.
Die Paket-ID zunächst überprüfen
Bevor eine Anwendung in ein dauerhaft verwendetes Softwareprofil aufgenommen wird, sollte ihre ID kontrolliert werden.
Beispielsweise:
winget search Firefox
oder gezielt:
winget search --id Mozilla.Firefox
Anschließend können die Paketinformationen überprüft werden:
winget show --id Mozilla.Firefox --exact
Erst danach sollte die ID in die eigene Softwareliste übernommen werden.
Das verhindert Fehler und unerwartete Paketauswahl.
Ein einfaches Softwareprofil erstellen
Beginnen wir mit einem allgemeinen Windows-Arbeitsplatz.
$Packages = @(
"Mozilla.Firefox"
"7zip.7zip"
"VideoLAN.VLC"
"Microsoft.PowerToys"
)
foreach ($Package in $Packages) {
Write-Host "Installiere $Package ..."
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements
}
Das Skript arbeitet die Liste nacheinander ab.
Soll später eine weitere Anwendung hinzukommen, wird lediglich das Array erweitert.
Entwicklungsrechner automatisch einrichten
Entwickler-PCs gehören zu den interessantesten Anwendungsfällen für Winget.
Ein neuer Entwicklungsrechner benötigt häufig mehrere Werkzeuge.
Beispielsweise:
Git Visual Studio Code PowerShell Python Node.js Windows Terminal Docker Desktop 7-Zip PowerToys
Eine entsprechende Liste könnte beispielsweise so beginnen:
$DevPackages = @(
"Git.Git"
"Microsoft.VisualStudioCode"
"Microsoft.PowerShell"
"Python.Python.3.13"
"OpenJS.NodeJS.LTS"
"Microsoft.WindowsTerminal"
"Docker.DockerDesktop"
"7zip.7zip"
"Microsoft.PowerToys"
)
Vor der produktiven Verwendung sollten die IDs selbstverständlich mit der aktuell eingesetzten Winget-Quelle überprüft werden.
Die Installation erfolgt anschließend:
foreach ($Package in $DevPackages) {
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements
}
Aus zahlreichen manuellen Installationen wird damit ein reproduzierbarer Vorgang.
Unterschiedliche Entwicklungsprofile
Nicht jeder Entwickler benötigt dieselbe Software.
Deshalb können mehrere Profile erstellt werden.
Beispielsweise:
Developer
│
├── Web
│ ├── Git
│ ├── VS Code
│ ├── Node.js
│ └── Docker
│
├── Python
│ ├── Git
│ ├── VS Code
│ ├── Python
│ └── Docker
│
└── .NET
├── Git
├── Visual Studio
├── PowerShell
└── Windows Terminal
Damit muss nicht mehr ein riesiges Universalprofil gepflegt werden.
Stattdessen bekommt jeder Arbeitsplatz genau die Software, die benötigt wird.
Office-PC definieren
Ein Office-Arbeitsplatz benötigt üblicherweise eine andere Softwareausstattung.
Ein Beispiel könnte sein:
$OfficePackages = @(
"Mozilla.Firefox"
"7zip.7zip"
"VideoLAN.VLC"
"Adobe.Acrobat.Reader.64-bit"
"Microsoft.PowerToys"
)
Abhängig von Organisation und Lizenzierung könnten weitere Anwendungen ergänzt werden.
Bei kommerzieller Software ist allerdings wichtig:
Winget löst nicht automatisch die Lizenzierungsfrage.
Nur weil ein Paket über Winget installiert werden kann, bedeutet dies nicht, dass es auf beliebig vielen Rechnern eingesetzt werden darf.
Lizenzierung und Softwarefreigabe bleiben organisatorische Aufgaben.
Office-Profil installieren
Das eigentliche Installationsskript unterscheidet sich kaum vom Entwicklerprofil:
foreach ($Package in $OfficePackages) {
Write-Host "Installiere $Package"
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements
}
Dadurch kann ein neuer Office-PC nach der Windows-Grundinstallation wesentlich schneller eingerichtet werden.
Gaming-PC automatisch einrichten
Auch für private Gaming-PCs eignet sich Winget hervorragend.
Ein mögliches Profil könnte enthalten:
$GamingPackages = @(
"Valve.Steam"
"EpicGames.EpicGamesLauncher"
"GOG.Galaxy"
"Discord.Discord"
"OBSProject.OBSStudio"
"7zip.7zip"
)
Damit lassen sich viele typische Programme nach einer Windows-Neuinstallation automatisch bereitstellen.
Die eigentlichen Spiele werden dabei natürlich nicht zwangsläufig mitinstalliert. Das übernehmen anschließend die jeweiligen Plattformen.
Gaming-Profil erweitern
Ein Gaming-System könnte zusätzlich Werkzeuge für Streaming und Kommunikation enthalten:
Gaming-PC │ ├── Steam ├── Epic Games Launcher ├── GOG Galaxy ├── Discord ├── OBS Studio └── 7-Zip
Wer Streaming betreibt, könnte weitere Werkzeuge ergänzen.
Wer ausschließlich spielt, reduziert das Profil entsprechend.
Der entscheidende Vorteil:
Die persönliche Grundausstattung muss nach einer Neuinstallation nicht mehr zusammengesucht werden.
Administrator-PC definieren
Besonders interessant wird Winget für Administrator-Arbeitsplätze.
Ein mögliches Profil könnte beispielsweise enthalten:
$AdminPackages = @(
"Microsoft.PowerShell"
"Microsoft.WindowsTerminal"
"Microsoft.VisualStudioCode"
"Git.Git"
"7zip.7zip"
"WiresharkFoundation.Wireshark"
"PuTTY.PuTTY"
"WinSCP.WinSCP"
"Microsoft.Sysinternals"
)
Hier gilt besonders:
Paket-IDs und Softwarefreigaben sollten vor dem Einsatz geprüft werden.
Gerade Administrationswerkzeuge besitzen weitreichende Möglichkeiten und gehören nicht automatisch auf jeden Arbeitsplatz.
Sicherheitsprinzip: Nur notwendige Software installieren
Standardisierte Softwarelisten haben neben der Zeitersparnis einen weiteren Vorteil:
Sie verhindern unkontrolliert wachsende Softwarebestände.
Ein Administrator-PC muss beispielsweise nicht automatisch 50 verschiedene Diagnosewerkzeuge enthalten.
Das Prinzip sollte lauten:
So viel Software wie erforderlich, so wenig wie möglich.
Jede zusätzliche Anwendung vergrößert schließlich:
- den Wartungsaufwand,
- den Patchbedarf,
- die mögliche Angriffsfläche,
- den Supportaufwand.
Standardisierte Winget-Profile können daher auch Teil einer sauberen Software-Governance sein.
Basisprofil und Zusatzprofile
Eine besonders flexible Struktur entsteht, wenn Softwarelisten modular aufgebaut werden.
Beispielsweise:
Base ├── Browser ├── 7-Zip └── PDF-Werkzeug Office ├── Base └── Office-Anwendungen Developer ├── Base ├── Git ├── VS Code ├── PowerShell └── Entwicklungsumgebungen Administrator ├── Base ├── Terminal ├── PowerShell ├── WinSCP └── Diagnosewerkzeuge
Damit müssen gemeinsame Anwendungen nicht in jedem Profil separat gepflegt werden.
Modularisierung mit PowerShell
Das lässt sich auch in PowerShell umsetzen:
$BasePackages = @(
"Mozilla.Firefox"
"7zip.7zip"
)
$DeveloperPackages = @(
"Git.Git"
"Microsoft.VisualStudioCode"
"Microsoft.PowerShell"
)
$Packages = $BasePackages + $DeveloperPackages
Danach:
foreach ($Package in $Packages) {
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements
}
So entstehen wiederverwendbare Bausteine.
Eigene Listen getrennt von der Installationslogik pflegen
Bei größeren Umgebungen sollte die Paketliste nicht zwingend direkt im PowerShell-Skript stehen.
Eine einfache Textdatei könnte beispielsweise so aussehen:
Mozilla.Firefox 7zip.7zip VideoLAN.VLC Microsoft.PowerToys
Dateiname:
office-packages.txt
PowerShell kann diese Datei anschließend einlesen:
$Packages = Get-Content ".\office-packages.txt"
foreach ($Package in $Packages) {
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements
}
Der Vorteil:
Installationslogik und Softwareauswahl sind voneinander getrennt.
Mehrere Profildateien verwenden
Eine Verzeichnisstruktur könnte beispielsweise folgendermaßen aussehen:
Winget-Profiles │ ├── Scripts │ └── Install-Packages.ps1 │ ├── Profiles │ ├── base.txt │ ├── office.txt │ ├── developer.txt │ ├── gaming.txt │ └── administrator.txt │ └── README.md
Das eigentliche Skript bleibt gleich.
Lediglich die Softwareliste ändert sich.
Profil als Parameter übergeben
Das Skript kann noch flexibler gestaltet werden:
param(
[Parameter(Mandatory)]
[string]$Profile
)
$Packages = Get-Content $Profile
foreach ($Package in $Packages) {
Write-Host "Installiere: $Package"
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements
}
Aufruf:
.\Install-Packages.ps1 -Profile ".\Profiles\developer.txt"
Oder:
.\Install-Packages.ps1 -Profile ".\Profiles\office.txt"
Damit besitzt man bereits ein kleines eigenes Deployment-System auf Basis von Winget.
Bereits installierte Programme
Ein Skript sollte möglichst auch mit Rechnern umgehen können, auf denen ein Teil der Software bereits vorhanden ist.
Eine einfache Prüfung kann beispielsweise mit winget list erfolgen.
Schematisch:
winget list --id Mozilla.Firefox --exact
Für umfangreiche Automatisierungen sollte die Auswertung allerdings sauber über Rückgabewerte und Logging erfolgen.
Winget selbst erkennt bei Installationsvorgängen in vielen Fällen bereits vorhandene Anwendungen und verhält sich entsprechend.
Trotzdem sollte ein Deployment-Skript so entworfen werden, dass es mehrfach ausgeführt werden kann, ohne den Rechner in einen unerwünschten Zustand zu versetzen.
Fehlerbehandlung ergänzen
Ein einfaches foreach-Skript ist praktisch, liefert aber noch keine komfortable Übersicht über fehlgeschlagene Installationen.
Eine verbesserte Variante:
foreach ($Package in $Packages) {
Write-Host "Installiere $Package ..."
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements `
--disable-interactivity
if ($LASTEXITCODE -eq 0) {
Write-Host "$Package erfolgreich verarbeitet."
}
else {
Write-Warning "Problem bei $Package. Exitcode: $LASTEXITCODE"
}
}
Damit wird zumindest sichtbar, bei welchen Paketen Probleme aufgetreten sind.
Logging hinzufügen
Für wiederholbare Installationen empfiehlt sich zusätzlich eine Protokolldatei.
Beispielsweise:
$LogFile = "C:\Logs\Winget-Installation.log"
foreach ($Package in $Packages) {
"$(Get-Date) - Starte $Package" |
Out-File $LogFile -Append
winget install `
--id $Package `
--exact `
--silent `
--accept-package-agreements `
--accept-source-agreements `
--disable-interactivity 2>&1 |
Out-File $LogFile -Append
"$(Get-Date) - Exitcode: $LASTEXITCODE" |
Out-File $LogFile -Append
}
Damit lässt sich eine Installation später nachvollziehen.
Softwarelisten aus einem Referenzrechner erzeugen
Natürlich muss eine Paketliste nicht komplett von Hand erstellt werden.
Aus Teil 8 kennen wir:
winget export -o packages.json
Ein sauber eingerichteter Referenzrechner kann deshalb als Ausgangspunkt dienen.
Ein möglicher Workflow:
Referenz-PC einrichten
↓
Software testen
↓
winget export
↓
JSON kontrollieren
↓
unnötige Pakete entfernen
↓
Softwareprofil speichern
↓
auf weiteren Rechnern verwenden
Damit lassen sich vorhandene Systeme als Grundlage für neue Standardprofile nutzen.
JSON-Profile mit winget import
Eine exportierte und anschließend bereinigte JSON-Datei kann direkt verwendet werden:
winget import -i developer.json
Oder beispielsweise:
winget import `
-i developer.json `
--accept-package-agreements `
--accept-source-agreements
Damit benötigen wir nicht zwingend ein eigenes Installationsskript.
Für reine Softwarelisten ist export/import daher eine sehr interessante Alternative.
Textliste, JSON oder Configure?
Welche Variante sollte verwendet werden?
Eine einfache Textliste plus PowerShell ist besonders flexibel und leicht verständlich.
Eine Winget-JSON-Datei eignet sich hervorragend für:
Export Migration Softwarelisten Import
winget configure geht dagegen deutlich weiter und eignet sich für deklarative Systemkonfigurationen.
Vereinfacht:
PowerShell + Paketliste
↓
maximale eigene Kontrolle
export / import
↓
einfache Paketwiederherstellung
winget configure
↓
deklarativer gewünschter Systemzustand
Welche Variante am besten passt, hängt vom Einsatzzweck ab.
Versionsverwaltung mit Git
Softwareprofile sind Konfigurationsdateien.
Und Konfigurationsdateien sollten versioniert werden.
Git eignet sich hervorragend dafür.
Ein Repository könnte beispielsweise folgendermaßen aufgebaut sein:
winget-profiles/ │ ├── profiles/ │ ├── base.txt │ ├── office.txt │ ├── developer.txt │ ├── gaming.txt │ └── administrator.txt │ ├── scripts/ │ └── install.ps1 │ ├── exports/ │ ├── office.json │ └── developer.json │ └── README.md
Änderungen können anschließend mit Git dokumentiert werden.
Repository initialisieren
Im Projektverzeichnis:
git init
Dateien hinzufügen:
git add .
Ersten Stand speichern:
git commit -m "Initiale Winget-Softwareprofile"
Wird beispielsweise Firefox zum Basisprofil hinzugefügt:
git add profiles/base.txt git commit -m "Firefox zum Basisprofil hinzugefügt"
Damit ist nachvollziehbar, wann und warum sich eine Standardinstallation verändert hat.
Warum Versionsverwaltung so wertvoll ist
Angenommen, das Administrator-Profil enthielt ursprünglich:
PowerShell Windows Terminal WinSCP Wireshark
Später kommen weitere Werkzeuge hinzu.
Mit Git kann nachvollzogen werden:
Version 1 PowerShell Windows Terminal Version 2 + WinSCP Version 3 + Wireshark Version 4 - Wireshark
Damit wird aus einer einfachen Softwareliste eine nachvollziehbare Konfiguration.
Releases für freigegebene Profile
Für professionelle Umgebungen kann noch einen Schritt weiter gegangen werden.
Beispielsweise:
Office-PC 1.0 Office-PC 1.1 Office-PC 2.0
Git-Tags können solche freigegebenen Stände markieren:
git tag v1.0
Später:
git tag v1.1
Damit kann eindeutig dokumentiert werden, welcher Softwarestand für eine bestimmte Rechnergeneration vorgesehen war.
Versionen der Anwendungen festlegen
Neben der Version des gesamten Profils können auch konkrete Anwendungsversionen relevant sein.
Für einzelne Winget-Installationen steht beispielsweise zur Verfügung:
winget install `
--id Hersteller.Anwendung `
--exact `
--version <Version>
Das kann sinnvoll sein, wenn nur eine bestimmte getestete Version freigegeben wurde.
Allerdings gilt:
Eine festgelegte Version kann nur installiert werden, solange sie über die betreffende Source beziehungsweise den Installer noch verfügbar ist.
Eine Versionsangabe ersetzt daher keine langfristige Archivierung benötigter Installationsmedien.
Softwareprofile und Updates zusammendenken
Ein Softwareprofil beantwortet zunächst:
Welche Anwendungen sollen auf diesem Rechner vorhanden sein?
Die Update-Strategie beantwortet dagegen:
Welche Versionen dürfen auf diesem Rechner eingesetzt werden?
Beides sollte gemeinsam betrachtet werden.
Beispielsweise:
Administrator-PC
│
├── PowerShell
│ └── aktuelle freigegebene Version
│
├── Windows Terminal
│ └── automatische Updates
│
├── WinSCP
│ └── automatische Updates
│
└── Fachwerkzeug
└── Versions-Pin
Hier kommen die in Teil 6 behandelten Winget-Pins ins Spiel.
Standardinstallation und Pins kombinieren
Eine Anwendung könnte zunächst installiert werden:
winget install --id Hersteller.Anwendung --exact
Anschließend könnte ein Versionsbereich festgelegt werden:
winget pin add `
--id Hersteller.Anwendung `
--version 5.4.*
Damit wird nicht nur definiert, dass die Software vorhanden sein soll, sondern auch, innerhalb welcher Versionslinie Updates zulässig sind.
Das ist besonders für kontrollierte Unternehmensumgebungen interessant.
Eigene Profile dokumentieren
Jedes Softwareprofil sollte zumindest dokumentieren:
Name des Profils Zweck verantwortliche Stelle freigegebener Stand enthaltene Anwendungen besondere Lizenzanforderungen besondere Installationshinweise Update-Strategie
Eine README.md könnte beispielsweise erklären:
Profil: Developer Zweck: Standardinstallation für Entwicklungsarbeitsplätze. Enthalten: Git Visual Studio Code PowerShell Python Node.js Stand: Version 1.4 Hinweise: Docker Desktop nur auf dafür freigegebenen Systemen.
Dadurch bleibt auch Monate später nachvollziehbar, warum ein Paket Bestandteil des Profils ist.
Best Practices
Für dauerhaft nutzbare Winget-Softwareprofile haben sich einige Grundregeln bewährt:
- Paket-IDs statt Programmnamen verwenden.
- Dadurch werden Installationen eindeutiger.
--exacteinsetzen.- Damit wird eine exakte Paketzuordnung verlangt.
- Profile klein und modular halten.
- Ein Basisprofil plus Zusatzprofile ist meist übersichtlicher als eine gigantische Liste.
- Software vor der Aufnahme testen.
- Nicht jedes Paket eignet sich automatisch für eine Silent-Installation.
- Lizenzbedingungen prüfen.
- Technische Installierbarkeit bedeutet nicht automatisch rechtliche Nutzbarkeit.
- Logging verwenden.
- Automatisierte Installationen sollten nachvollziehbar sein.
- Listen versionieren.
- Git eignet sich hervorragend dafür.
- Versionsvorgaben bewusst einsetzen.
- Neueste Version und freigegebene Version sind nicht zwangsläufig identisch.
- Regelmäßig aufräumen.
- Nicht mehr benötigte Software sollte aus dem Profil entfernt werden.
- Profile testen.
- Vor einer breiten Verteilung sollte ein neuer Profilstand auf einem Testsystem installiert werden.
Beispiel für eine komplette Profilstruktur
Eine kleine Winget-Umgebung könnte schließlich so aussehen:
winget-deployment/ │ ├── profiles/ │ ├── base.txt │ ├── office.txt │ ├── developer.txt │ ├── gaming.txt │ └── administrator.txt │ ├── scripts/ │ ├── install.ps1 │ └── update.ps1 │ ├── exports/ │ ├── office.json │ └── developer.json │ ├── logs/ │ └── README.md
Damit besitzen wir bereits eine einfache Grundlage für eine reproduzierbare Windows-Softwarebereitstellung.
Beispiel: Neuer Entwickler-PC
Ein möglicher Ablauf sieht dann folgendermaßen aus:
Windows installieren
↓
Windows Update
↓
Winget prüfen
↓
Repository mit Profilen bereitstellen
↓
Developer-Profil auswählen
↓
Installationsskript starten
↓
Pakete installieren
↓
Logging kontrollieren
↓
Entwicklungsumgebung konfigurieren
Statt zahlreiche Programme manuell zusammenzusuchen, wird ein definierter Standard umgesetzt.
Von der Softwareliste zum Configuration as Code
Genau hier wird Winget konzeptionell besonders interessant.
Was zunächst nur eine Liste wie:
Git.Git Microsoft.VisualStudioCode Microsoft.PowerShell
war, entwickelt sich mit:
- PowerShell,
- Git,
- Versionskontrolle,
- Logging,
- Profilen,
- Tests
zu einer Form von Configuration as Code.
Die gewünschte Softwareausstattung eines Rechners wird nicht mehr nur im Kopf eines Administrators oder in einer Dokumentation festgehalten.
Sie wird maschinenlesbar beschrieben.
Und genau auf diesem Gedanken baut winget configure auf, das wir in einem späteren Teil ausführlich behandeln werden.
Fazit
Eigene Winget-Softwarelisten sind eine der praktischsten Möglichkeiten, wiederkehrende Windows-Installationen zu standardisieren.
Statt einen neuen Rechner jedes Mal manuell einzurichten, wird einmal definiert, welche Anwendungen zu einem bestimmten Arbeitsplatz gehören.
So können beispielsweise eigene Profile für:
Office-PC Entwicklungsrechner Gaming-PC Administrator-PC
erstellt werden.
Eine einfache Kombination aus Paketliste und PowerShell reicht bereits aus, um viele Installationen zu automatisieren.
Noch besser wird das Verfahren, wenn die Profile modular aufgebaut, dokumentiert und mit Git versioniert werden.
Damit ist jederzeit nachvollziehbar:
Welche Software gehört auf welchen Rechner – und seit wann?
Winget entwickelt sich dadurch von einem komfortablen Paketmanager zu einem Werkzeug für reproduzierbare Windows-Arbeitsplätze.
Der nächste logische Schritt besteht nun darin, nicht mehr nur Softwarelisten zu verwalten, sondern die Paketquellen selbst genauer unter die Lupe zu nehmen.