Bash Script zu Powershell / CMD umwandeln?

DFFVB

Rear Admiral
Registriert
Dez. 2015
Beiträge
5.594
Hallo zusammen, vlt. ist das auch total Banane, was ich frage, aber ich frage mich, wie einfach es möglich wäre, folgendes Script in Powershell / Bash umzuwandeln?

Es geht um dieses Script, was remote unlock von TrueNAS erlaubt. Folgender UseCase, habe eine TrueNAS Box, die BackUps von einem einzelnen PC speichern soll, den Rest der Zeit ist sie aus. Sprich PC wird angeschaltet, TrueNAS wird per WakeOn LAN gestartet, drei Minuten später soll der automatisierte Unlock der TN Box erfolgen, dann startet der Sync, Box schaltet sich abend um 22 Uhr aus.

Habe das Bash-Script sowohl bei Perplexity als auch Github Copilot reingehauen, hat jeweils nicht geklappt. Ich hab aber null,null Ahnung davon.


Bash:
#!/bin/sh
set -e
set -u

g_version="1.0.0"
g_build="2024-08-26"
g_author="AJ ONeal <aj@therootcompany.com> (https://bnna.net)"
g_license="CC0-1.0"
g_license_url="https://creativecommons.org/publicdomain/zero/1.0/"

if test "version" = "${1:-}" || test "--version" = "${1:-}" || test "-V" = "${1:-}"; then
    echo "truenas-unlock-volumes v${g_version} (${g_build})"
    echo "copyright 2024 ${g_author} (${g_license} license)"
    echo "${g_license_url}"
    exit 0
fi

if test "help" = "${1:-}" || test "--help" = "${1:-}"; then
    {
        echo "truenas-unlock-volumes v${g_version} (${g_build})"
        echo "copyright 2024 ${g_author} (${g_license} license)"
        echo "${g_license_url}"
        echo ""
        echo "USAGE"
        echo "    truenas-unlock-volumes"
        echo ""
        echo "CONFIG"
        echo ""
        echo "  ~/.config/truenas/env:"
        echo "      # note: no trailing /"
        echo "      export TRUENAS_BASE_URL=https://truenas.local"
        # shellcheck disable=SC2016 # use of literal $ is intentional
        echo '      # from ${TRUENAS_BASE_URL}/ui/apikeys'
        echo "      export TRUENAS_API_KEY=abc123"
        echo ""
    } >&2
    exit 0
fi

if ! test -s ~/.config/truenas/env; then
    mkdir -p ~/.config/truenas/
    {
        echo '# Example'
        echo '#     export TRUENAS_BASE_URL=https://truenas.local'
        echo '#     export TRUENAS_API_KEY=abc123 # from https://<truenas>/ui/apikeys'
    } > ~/.config/truenas/env
fi
if ! grep -q -v -E '^\s*(#.*)?$' ~/.config/truenas/env; then
    {
        echo ""
        echo "ERROR"
        echo "    Missing ~/.config/truenas/env"
        echo ""
        echo "SOLUTION"
        echo "    Create and save an API key from https://truenas.local/ui/apikeys"
        echo ""
    } >&2
    exit 1
fi

# shellcheck disable=SC1090
. ~/.config/truenas/env
if test -z "${TRUENAS_BASE_URL:-}" || test -z "${TRUENAS_API_KEY:-}"; then
    {
        echo ""
        echo "ERROR"
        echo "    Missing config from ~/.config/truenas/env"
        echo ""
        echo "SOLUTION"
        echo "    Set the config in this format:"
        echo "      export TRUENAS_BASE_URL=https://truenas.local # no trailing slash"
        echo "      export TRUENAS_API_KEY=abc123"
        echo ""
    } >&2
    exit 1
fi

if ! test -s ~/.config/truenas/zfs-passphrases.conf; then
    {
        echo ""
        echo "ERROR"
        echo "    Missing ~/.config/truenas/zfs-passphrases.conf"
        echo ""
        echo "SOLUTION"
        echo "    Set the passphrases in this format:"
        echo "      tank1/Data:foo bar baz"
        echo "      tankN/VolumeName:pass phrase goes here"
        echo ""
    } >&2
    exit 1
fi

fn_list() { (
    b_dataset_url="${TRUENAS_BASE_URL}/api/v2.0/pool/dataset"
    echo "    GET ${b_dataset_url} (listing dataset ids)..." >&2
    curl --fail-with-body -sS -k "${b_dataset_url}" \
        -H "Authorization: Bearer ${TRUENAS_API_KEY}" |
        jq -r '.[] | select(.encrypted == true) | .id'
); }

fn_unlock() { (
    b_dataset_id="${1}"
    b_dataset_phrase="${2}"

    b_unlock_url="${TRUENAS_BASE_URL}/api/v2.0/pool/dataset/unlock"
    printf "    POST %s (unlocking %s)..." "${b_unlock_url}" "${b_dataset_id}" >&2
    curl --fail-with-body -sS -k "${b_unlock_url}" \
        -H "Authorization: Bearer ${TRUENAS_API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{ "id": "'"${b_dataset_id}"'"
            , "unlock_options": {
                "recursive": true,
                "datasets": [
                  { "name": "'"${b_dataset_id}"'"
                  , "passphrase": "'"${b_dataset_phrase}"'"}
                ]
              }
            }'
    echo " unlocked" >&2
); }

main() { (
    b_truenas_zfs_phrases="$(grep -v -E '^\s*(#.*)?$' ~/.config/truenas/zfs-passphrases.conf)"
    echo "Unlocking TrueNAS..." >&2
    fn_list | while read -r b_dataset_id; do
        b_dataset_phrase="$(
            echo "${b_truenas_zfs_phrases}" |
                grep -F "${b_dataset_id}:" |
                cut -d':' -f2
        )"
        if test -z "${b_dataset_phrase}"; then
            echo "    SKIP '${b_dataset_id}': no passphrase" >&2
            continue
        fi

        fn_unlock "${b_dataset_id}" "${b_dataset_phrase}"
    done
    echo "Done"
); }

main


https://github.com/coolaj86/home-sweet-home/blob/main/bin/truenas-unlock-volumes
 
Nein, Powershell wie Bash arbeiten unterschiedlich. Du kannst nicht umwandeln. Du kannst es ChatCPT geben, der baut Dir das so um. Ich verstehe zudem nicht was Du da umwandeln willst. Du kannst auch von einem Windows PC remote per SSH ein Script direkt auf dem NAS ausführen.
 
  • Gefällt mir
Reaktionen: DFFVB, aragorn92 und Gee858eeG
Das was nutrix sagt. Du könntest auch die wsl in windows nutzen und bspw. dadurch das script so wie es ist in ubuntu ausführen; ohne es auf powershell oder cmd umzuschreiben
 
  • Gefällt mir
Reaktionen: DFFVB, nutrix und aragorn92
WSL auf Windows installieren und dann dort per Task Scheduler das Skript starten ist keine Option?

Wieso kann das Skript nicht auf dem Truenas liegen?
 
  • Gefällt mir
Reaktionen: DFFVB und nutrix
Gee858eeG schrieb:
Das was nutrix sagt. Du könntest auch die wsl in windows nutzen und bspw. dadurch das script so wie es ist in ubuntu ausführen; ohne es auf powershell oder cmd umzuschreiben
Stimmt, WSL gibts auch noch, oder Cygwin. Bringt Dir aber nur was, wenn Du das Script direkt auf dem PC ausführen willst.
 
eigentlich könnte man den unlock mit curl aufrufen:

Bash:
fn_unlock() { (
    b_dataset_id="${1}"
    b_dataset_phrase="${2}"

    b_unlock_url="${TRUENAS_BASE_URL}/api/v2.0/pool/dataset/unlock"
    printf "    POST %s (unlocking %s)..." "${b_unlock_url}" "${b_dataset_id}" >&2
    curl --fail-with-body -sS -k "${b_unlock_url}" \
        -H "Authorization: Bearer ${TRUENAS_API_KEY}" \
        -H "Content-Type: application/json" \
        -d '{ "id": "'"${b_dataset_id}"'"
            , "unlock_options": {
                "recursive": true,
                "datasets": [
                  { "name": "'"${b_dataset_id}"'"
                  , "passphrase": "'"${b_dataset_phrase}"'"}
                ]
              }
            }'
    echo " unlocked" >&2
); }

Die Variablen ersetzten... müsste KI hinbekommen
 
  • Gefällt mir
Reaktionen: DFFVB
naja das Bash Script verwendet curl nur mal so nebenbei.... Dann kann man curl auch direkt aufrufen...
 
  • Gefällt mir
Reaktionen: dms
Danke euch ! Okay, also nicht so einfach übersetzbar. WSL ist wahrscheinlich dann der Weg! Werde aber auch mal versuchen das Snippet durch KIs zu jagen ^^
 
Dröseln wir die curl Parameter doch mal auf:
Bash:
curl --fail-with-body
Bestimmte Fehlerausgabe -> nicht ausschlaggebend

Bash:
curl -sS
Fehlerausgabe, aber keine sonstige Ausgabe -> auch nicht ausschlaggebend
ggf.
Bei Powershell:
PowerShell:
$ProgressPreference = "SilentlyContinue"
+ Pipen von der Ausgabe von Invoke-Webrequest zu Out-Null

Bash:
curl -k
Äquivalent bei Invoke-WebRequest: SkipCertificateCheck

Bash:
curl -H "Authorization: Bearer ${TRUENAS_API_KEY}" -H "Content-Type: application/json"
Äquivalent bei Invoke-WebRequest: Headers
Alternativ: Authentication + ContentType

Bash:
curl -d '{ "id": "'"${b_dataset_id}"'"
            , "unlock_options": {
                "recursive": true,
                "datasets": [
                  { "name": "'"${b_dataset_id}"'"
                  , "passphrase": "'"${b_dataset_phrase}"'"}
                ]
              }
            }'
Äquivalent bei Invoke-WebRequest: Body + Method Post


Fazit:
Die curl Aufrufe sollten auch mit PowerShell funktionieren. Der Rest scheint eh pillepalle zu sein, sehe also keinen Grund, warum man das script nicht zu Powershell umwandeln können soll
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: N.N. und DFFVB
By the way kennt PowerShell den Befehl curl zumindest indirekt. Denn curl ist in der PowerShell ein Alias fuer Invoke-Webrequest.
Dummerweise ist deren Syntax aber nicht die selbe, also kann man curl Befehle nicht einfach in eine PowerShell werfen.

Aber wie @KitKat::new() schreibt: Invoke-Webrequest sollte alles koennen was curl auch kann.
 
  • Gefällt mir
Reaktionen: nutrix, N.N. und DFFVB
Ranayna schrieb:
By the way kennt PowerShell den Befehl curl zumindest indirekt. Denn curl ist in der PowerShell ein Alias fuer Invoke-Webrequest.
Man kann einfach curl.exe schreiben und führt so das in Windows enthaltene curl aus.
 
  • Gefällt mir
Reaktionen: nutrix, Ranayna und JumpingCat
Ranayna schrieb:
Huh. TiL. ... hat wusste ich garnicht.
Ach, alles noch "viel" Schlimmer, MS liefert keine halbwegs aktuelle Version
aus und die Leute nölten den Maintainer an

https://curl.se/windows/microsoft.html

gerade mal nachsehen Win 10 22H2
curl.exe --version
curl 8.7.1 (Windows) libcurl/8.7.1 Schannel zlib/1.3 WinIDN
Release-Date: 2024-03-27
https://curl.se/ch/8.7.1.html

Versus
https://curl.se/download.html
curl 8.15.0, Released on the 2025-07-16

Wie so oft erinnert das an https://xkcd.com/2347/
 
  • Gefällt mir
Reaktionen: N.N.
dms schrieb:
gerade mal nachsehen Win 10 22H2
Wird etwas offtopic, aber da passt was nicht.

Ebenfalls Windows 10 22H2:
Code:
curl.exe --version
curl 8.13.0 (Windows) libcurl/8.13.0 Schannel zlib/1.3.1 WinIDN
Release-Date: 2025-04-02

Hast du alle Updates installiert? Ich kann mir kaum vorstellen, dass die Windows Edition (bei mir laeuft Enterprise) Einfluss auf die curl.exe Version hat.
 
Zuletzt bearbeitet: (typofixx)
Also Github Copilot und Perplexity haben nicht richtig funktioniert, mit Clause ging es besser, aber gibt weiterhin einen Fehler:

Failed to retrieve datasets: Die zugrunde liegende Verbindung wurde geschlossen: Unerwarteter Fehler beim Senden..

Über WSL geht es problemlos...

Code:
#!/usr/bin/env pwsh
param(
    [string]$Action
)

# ====== CONFIGURATION SECTION ======
# Edit these values directly in the script
$TRUENAS_BASE_URL = "https://truenas.local"  # Your TrueNAS URL (no trailing slash)
$TRUENAS_API_KEY = "your-api-key-here"       # API key from https://truenas.local/ui/apikeys

# Dataset passphrases in format: "dataset-name" = "passphrase"
$DATASET_PASSPHRASES = @{
    "tank1/Data" = "your passphrase here"
    "tank2/Media" = "another passphrase"
    # Add more datasets as needed:
    # "pool/dataset" = "passphrase"
}
# ====== END CONFIGURATION SECTION ======

# Set strict mode for better error handling
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# Configure TLS/SSL settings for Windows PowerShell 5.1
if ($PSVersionTable.PSVersion.Major -lt 6) {
    # Allow all TLS versions and ignore certificate errors
    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls
    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
}

# Handle version argument
if ($Action -eq "version" -or $Action -eq "--version" -or $Action -eq "-V") {
    Write-Host "truenas-unlock-volumes v$g_version ($g_build)"
    Write-Host "copyright 2024 $g_author ($g_license license)"
    Write-Host $g_license_url
    exit 0
}

# Handle help argument
if ($Action -eq "help" -or $Action -eq "--help") {
    Write-Host "truenas-unlock-volumes v$g_version ($g_build)" -ForegroundColor Yellow
    Write-Host "copyright 2024 $g_author ($g_license license)"
    Write-Host $g_license_url
    Write-Host ""
    Write-Host "USAGE" -ForegroundColor Green
    Write-Host "    truenas-unlock-volumes"
    Write-Host ""
    Write-Host "CONFIG" -ForegroundColor Green
    Write-Host ""
    Write-Host "  Edit the configuration section directly in this script:"
    Write-Host "      `$TRUENAS_BASE_URL = `"https://truenas.local`"  # no trailing slash"
    Write-Host "      `$TRUENAS_API_KEY = `"your-api-key`"            # from /ui/apikeys"
    Write-Host "      `$DATASET_PASSPHRASES = @{"
    Write-Host "          `"tank1/Data`" = `"your passphrase`""
    Write-Host "      }"
    Write-Host ""
    exit 0
}

# Validate configuration
if (-not $TRUENAS_BASE_URL -or $TRUENAS_BASE_URL -eq "https://truenas.local" -or $TRUENAS_BASE_URL -eq "") {
    Write-Host ""
    Write-Host "ERROR" -ForegroundColor Red
    Write-Host "    TRUENAS_BASE_URL not configured in script"
    Write-Host ""
    Write-Host "SOLUTION" -ForegroundColor Green
    Write-Host "    Edit the script and set:"
    Write-Host "      `$TRUENAS_BASE_URL = `"https://your-truenas-ip-or-hostname`""
    Write-Host ""
    exit 1
}

if (-not $TRUENAS_API_KEY -or $TRUENAS_API_KEY -eq "your-api-key-here" -or $TRUENAS_API_KEY -eq "") {
    Write-Host ""
    Write-Host "ERROR" -ForegroundColor Red
    Write-Host "    TRUENAS_API_KEY not configured in script"
    Write-Host ""
    Write-Host "SOLUTION" -ForegroundColor Green
    Write-Host "    1. Go to $TRUENAS_BASE_URL/ui/apikeys"
    Write-Host "    2. Create a new API key"
    Write-Host "    3. Edit the script and set:"
    Write-Host "      `$TRUENAS_API_KEY = `"your-actual-api-key`""
    Write-Host ""
    exit 1
}

if (-not $DATASET_PASSPHRASES -or $DATASET_PASSPHRASES.Count -eq 0) {
    Write-Host ""
    Write-Host "ERROR" -ForegroundColor Red
    Write-Host "    No dataset passphrases configured in script"
    Write-Host ""
    Write-Host "SOLUTION" -ForegroundColor Green
    Write-Host "    Edit the script and add your datasets to `$DATASET_PASSPHRASES:"
    Write-Host "    `$DATASET_PASSPHRASES = @{"
    Write-Host "        `"tank1/Data`" = `"your passphrase here`""
    Write-Host "        `"pool/dataset`" = `"another passphrase`""
    Write-Host "    }"
    Write-Host ""
    exit 1
}

# Function to list encrypted datasets
function Get-EncryptedDatasets {
    $datasetUrl = "$TRUENAS_BASE_URL/api/v2.0/pool/dataset"
    Write-Host "    GET $datasetUrl (listing dataset ids)..." -ForegroundColor Cyan
    
    try {
        $headers = @{
            "Authorization" = "Bearer $TRUENAS_API_KEY"
        }
        
        # Skip certificate validation for self-signed certificates
        if ($PSVersionTable.PSVersion.Major -ge 6) {
            $response = Invoke-RestMethod -Uri $datasetUrl -Headers $headers -SkipCertificateCheck
        } else {
            # For Windows PowerShell 5.1 - SSL settings already configured globally
            $response = Invoke-RestMethod -Uri $datasetUrl -Headers $headers
        }
        
        # Filter for encrypted datasets and return their IDs
        return $response | Where-Object { $_.encrypted -eq $true } | Select-Object -ExpandProperty id
    }
    catch {
        Write-Host "Failed to retrieve datasets: $_" -ForegroundColor Red
        exit 1
    }
}

# Function to unlock a dataset
function Unlock-Dataset {
    param(
        [string]$DatasetId,
        [string]$DatasetPhrase
    )
    
    $unlockUrl = "$TRUENAS_BASE_URL/api/v2.0/pool/dataset/unlock"
    Write-Host "    POST $unlockUrl (unlocking $DatasetId)..." -ForegroundColor Cyan -NoNewline
    
    $body = @{
        id = $DatasetId
        unlock_options = @{
            recursive = $true
            datasets = @(
                @{
                    name = $DatasetId
                    passphrase = $DatasetPhrase
                }
            )
        }
    } | ConvertTo-Json -Depth 5
    
    try {
        $headers = @{
            "Authorization" = "Bearer $TRUENAS_API_KEY"
            "Content-Type" = "application/json"
        }
        
        # Skip certificate validation for self-signed certificates
        if ($PSVersionTable.PSVersion.Major -ge 6) {
            $response = Invoke-RestMethod -Uri $unlockUrl -Method Post -Headers $headers -Body $body -SkipCertificateCheck
        } else {
            # For Windows PowerShell 5.1 - SSL settings already configured globally
            $response = Invoke-RestMethod -Uri $unlockUrl -Method Post -Headers $headers -Body $body
        }
        
        Write-Host " unlocked" -ForegroundColor Green
    }
    catch {
        Write-Host " failed: $_" -ForegroundColor Red
    }
}

# Main execution
function Main {
    Write-Host "Unlocking TrueNAS..." -ForegroundColor Yellow
    
    $datasetIds = Get-EncryptedDatasets
    
    foreach ($datasetId in $datasetIds) {
        # Find matching passphrase in the hashtable
        if ($DATASET_PASSPHRASES.ContainsKey($datasetId)) {
            $datasetPhrase = $DATASET_PASSPHRASES[$datasetId]
            
            if (-not [string]::IsNullOrWhiteSpace($datasetPhrase)) {
                Unlock-Dataset -DatasetId $datasetId -DatasetPhrase $datasetPhrase
            } else {
                Write-Host "    SKIP '$datasetId': empty passphrase" -ForegroundColor Yellow
            }
        } else {
            Write-Host "    SKIP '$datasetId': no passphrase configured in script" -ForegroundColor Yellow
        }
    }
    
    Write-Host "Done" -ForegroundColor Green
}

# Execute main function
Main
 
  • Gefällt mir
Reaktionen: DFFVB
Zurück
Oben