PowerShell Command Execution in `run-before` Hook on Windows
Bug Report: PowerShell Command Execution in run-before Hook
Description
PowerShell commands containing nested quotes fail to execute correctly when defined in the run-before section of the resticprofile configuration file (test.yml). The command appears to be parsed incorrectly by the shell invoking it, leading to execution failures or syntax errors.
Reproduction Steps
-
Configuration: Create a
test.ymlwith the following content:version: "1" test: repository: "c:\restic\temp\repo" password-file: "password.txt" initialize: true run-before: - powershell -Command "New-Item -Path 'c:\restic\temp\testfile.txt' -ItemType File -Value 'This is a test file.' -Force" backup: source: - c:\restic\temp\testfile.txt -
Execution: Run the backup profile:
resticprofile -v --config C:\restic\test.yml --name test backup
Observed Behavior
- The command does not execute successfully.
- The file
c:\restic\temp\testfile.txtis not created. - No clear error message is always displayed in the
resticprofileoutput, but manual reproduction viacmd /cshows parsing errors.
Root Cause Analysis
resticprofile likely executes shell commands using the system's default shell (e.g., cmd.exe on Windows). When passing a command string that includes double quotes (") for the -Command argument and single quotes (') for PowerShell parameters, the outer shell (cmd.exe) may misinterpret the quotes.
For example, cmd.exe might strip the outer quotes or fail to handle the nested quotes, causing powershell.exe to receive a malformed command string.
Workaround / Solution
To avoid quoting and escaping issues between shells, use the -EncodedCommand parameter of PowerShell. This accepts a Base64-encoded string of the command.
Example Fix
-
Generate Base64 Command:
$cmd = "New-Item -Path 'c:\restic\temp\testfile.txt' -ItemType File -Value 'This is a test file.' -Force" $bytes = [System.Text.Encoding]::Unicode.GetBytes($cmd) $encoded = [Convert]::ToBase64String($bytes) Write-Host $encoded -
Update Configuration:
run-before: - powershell -EncodedCommand <Base64String>
Alternatively, placing the command in a separate .ps1 file and executing it with -File also resolves the issue:
run-before:
- powershell -File path\to\script.ps1
Hi,
Thank you for this very detailed description of the issue, along with potential fixes. I wasn't aware of the base64 form and I do like this idea.
I'll see if I automatically convert a command line with quote into the base64 form 👍🏻