Hi there, so I came across this handy script from @coolaj86
Summary
#!/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=“Deed - CC0 1.0 Universal - Creative Commons”
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:///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
Here is the link:
With the help of Claude I translated it to Powershell.
Summary
#!/usr/bin/env pwsh
param(
[string]$Action
)
====== CONFIGURATION SECTION ======
Edit these values directly in the script
$TRUENAS_BASE_URL = “https://10.10.10.30” # Your TrueNAS URL (no trailing slash)
$TRUENAS_API_KEY = “xyz” # API key from https://truenas.local/ui/apikeys
Dataset passphrases in format: “dataset-name” = “passphrase”
$DATASET_PASSPHRASES = @{
“sata” = “secret”
#“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
}
Configure TLS/SSL settings for Windows PowerShell 5.1
if ($PSVersionTable.PSVersion.Major -lt 6) {
# Force TLS 1.2 specifically
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
}
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
Now after upgrading to Goldeye it tells me unlock_options is not expected.
Also tried on Linux there it gives me a jq parsing error.
What to do?