PowerShell-Tool zum Durchsuchen und Installieren von Winget-Paketen

Minimalistisches Beitragsbild mit dem zentrierten Text „Winget-Pakete durchsuchen und installieren“ auf hellem, beigefarbenem Hintergrund.

Winget ist ein praktisches Kommandozeilenwerkzeug, wenn es darum geht, Software unter Windows schnell zu installieren. Allerdings sind Paketnamen nicht immer selbsterklärend, und die Suche liefert häufig viele Ergebnisse. Dafür habe ich ein kleines PowerShell-Skript erstellt, das die Bedienung deutlich erleichtert.

Das Skript bietet ein Menü, mit dem man nach Programmen suchen kann. Die Suchergebnisse werden anschließend in einer Out-GridView angezeigt, in der man Pakete per Mausklick auswählen und installieren kann. Damit entfällt das manuelle Tippen von Paket-IDs.

Funktionsweise

  1. Das Skript führt eine Winget-Suche mit normaler Textausgabe aus.
  2. Die Ausgabe wird gefiltert und in Spalten aufgeteilt, unabhängig von der verwendeten Winget-Version.
  3. Alle Treffer erscheinen in einer grafischen Tabelle.
  4. Ausgewählte Einträge lassen sich direkt installieren.

Die Parserlogik basiert auf der Tatsache, dass Winget seine tabellarische Ausgabe mit mehreren Leerzeichen zwischen den Spalten trennt. Dadurch ist das Skript stabiler als Varianten, die die JSON-Ausgabe verwenden.

Bedienung

Nach dem Start erscheint ein kleines Menü. Mit der Option „Nach Programm suchen“ gibt man einen Begriff wie „firefox“ oder „gimp“ ein. Danach öffnet sich ein Fenster mit allen gefundenen Paketen. Nach der Auswahl installiert Winget die Programme automatisch.

Das Skript ist ein einfaches, aber hilfreiches Werkzeug für alle, die mit Winget arbeiten, aber nicht ständig Paketnamen nachschlagen möchten. Es läuft problemlos in der PowerShell ISE und kann leicht erweitert werden, etwa um Update-Funktionen oder Softwarelisten.

Folgendes Skript muss in die PowerShell ISE mit Administratorrechten eingefügt und abgespeichert werden, bevor es ausgeführt wird:

# Prüfen, ob winget verfügbar ist
if (-not (Get-Command winget -ErrorAction SilentlyContinue)) {
    Write-Error "winget wurde nicht gefunden. Bitte stelle sicher, dass es installiert und im PATH ist."
    return
}

function Search-WingetPackages {
    param(
        [Parameter(Mandatory = $true)]
        [string]$Query
    )

    Write-Host "Suche nach Paketen für: '$Query' ..." -ForegroundColor Cyan

    # Winget-Suche mit normaler Textausgabe
    $output = winget search $Query 2>$null

    if (-not $output) {
        Write-Warning "Keine Ausgabe von winget erhalten."
        return @()
    }

    # Leere Zeilen und Trennlinien rausfiltern
    $lines = $output |
        Where-Object {
            $_.Trim() -ne "" -and
            $_ -notmatch '^\s*-{3,}\s*$'
        }

    if ($lines.Count -lt 2) {
        Write-Warning "Zu wenige Zeilen in der winget-Ausgabe."
        return @()
    }

    # Headerzeile suchen (die mit "Name" und "Id")
    $headerIndex = -1
    for ($i = 0; $i -lt $lines.Count; $i++) {
        if ($lines[$i] -match 'Name' -and $lines[$i] -match 'Id') {
            $headerIndex = $i
            break
        }
    }

    if ($headerIndex -eq -1 -or $headerIndex -ge ($lines.Count - 1)) {
        Write-Warning "Konnte die Headerzeile der winget-Tabelle nicht erkennen."
        return @()
    }

    # Alle Zeilen nach dem Header sind Datenzeilen
    $dataLines = $lines[($headerIndex + 1)..($lines.Count - 1)]

    $packages = foreach ($line in $dataLines) {
        # Spalten sind durch mind. zwei Leerzeichen getrennt
        $parts = $line -split "\s{2,}"

        if ($parts.Length -ge 3) {
            [PSCustomObject]@{
                Name    = $parts[0].Trim()
                Id      = $parts[1].Trim()
                Version = $parts[2].Trim()
                Source  = if ($parts.Length -ge 4) { $parts[3].Trim() } else { "" }
            }
        }
    }

    if (-not $packages -or $packages.Count -eq 0) {
        Write-Warning "Keine Pakete aus der Ausgabe parsen können."
        return @()
    }

    return $packages
}

function Install-WingetPackage {
    param(
        [Parameter(Mandatory = $true)]
        $Package
    )

    $name   = $Package.Name
    $id     = $Package.Id
    $source = $Package.Source

    Write-Host ""
    Write-Host "Installationsbefehl:" -ForegroundColor Yellow
    if ($source) {
        Write-Host "  winget install --id `"$id`" --source `"$source`" --accept-package-agreements --accept-source-agreements"
    } else {
        Write-Host "  winget install --id `"$id`" --accept-package-agreements --accept-source-agreements"
    }
    Write-Host ""

    $confirm = Read-Host "Paket '$name' ($id) wirklich installieren? (j/n)"
    if ($confirm -ne 'j' -and $confirm -ne 'J') {
        Write-Host "Abgebrochen." -ForegroundColor DarkYellow
        return
    }

    if ($source) {
        winget install --id "$id" --source "$source" --accept-package-agreements --accept-source-agreements
    } else {
        winget install --id "$id" --accept-package-agreements --accept-source-agreements
    }
}

function Start-WingetGuiSearch {

    do {
        Write-Host ""
        Write-Host "===== Winget Such- & Installationsmenü =====" -ForegroundColor Green
        Write-Host "1) Nach Programm suchen"
        Write-Host "0) Beenden"
        Write-Host "============================================"
        $choice = Read-Host "Auswahl"

        switch ($choice) {
            '1' {
                $query = Read-Host "Bitte Suchbegriff eingeben (z.B. 'firefox' oder 'gimp')"
                if ([string]::IsNullOrWhiteSpace($query)) {
                    Write-Host "Kein Suchbegriff eingegeben." -ForegroundColor DarkYellow
                    break
                }

                $packages = Search-WingetPackages -Query $query
                if (-not $packages -or $packages.Count -eq 0) {
                    Write-Host "Keine passenden Pakete gefunden." -ForegroundColor DarkYellow
                    break
                }

                # Anzeige in Out-GridView mit Auswahl
                $selected = $packages |
                    Out-GridView -Title "Suchergebnisse für '$query' - wähle Paket(e) zur Installation" -PassThru

                if (-not $selected) {
                    Write-Host "Keine Pakete ausgewählt." -ForegroundColor DarkYellow
                    break
                }

                foreach ($pkg in $selected) {
                    Install-WingetPackage -Package $pkg
                }
            }
            '0' {
                Write-Host "Beenden..." -ForegroundColor Green
                return
            }
            default {
                Write-Host "Ungültige Auswahl." -ForegroundColor Red
            }
        }

    } while ($true)
}

# Einstiegspunkt
Start-WingetGuiSearch

Hinweis zur Ausführung von PowerShell-Skripten

Falls das Skript bei dir nicht ausgeführt werden kann und eine Fehlermeldung zur Ausführungsrichtlinie erscheint, muss eventuell vorher die PowerShell Execution Policy angepasst werden.

Führe dazu in einer PowerShell mit Administratorrechten folgenden Befehl aus:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine

Damit erlaubst du lokal signierte Skripte und selbst erstellte Skripte, ohne die Sicherheit vollständig aufzuheben. Anschließend kannst du das Update-Skript wie beschrieben starten.

Alle Angaben ohne Gewähr.

Comments

No comments yet. Why don’t you start the discussion?

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert