Hassan Hashmi
03/24/2026, 5:41 PMMarvin
03/24/2026, 5:42 PMMarvin
03/24/2026, 5:46 PMprefect.cli.shell.run_shell_process (logs output, raises on non‑zero, supports env/cwd via popen_kwargs)
- If you need to capture stdout/stderr as return values inside your flow code, use Python’s subprocess in a @task
- For deployment build/pull steps (prefect.yaml), use the run_shell_script step which returns stdout/stderr
Examples
1) Run a .ps1 file from a flow with Prefect’s shell utility (logs output)
from prefect import flow
from prefect.cli.shell import run_shell_process
import os
@flow
def run_ps():
run_shell_process(
command='powershell -NoProfile -ExecutionPolicy Bypass -File ".\\script.ps1" -Arg1 value',
log_output=True,
stream_stdout=True, # stream live stdout to Prefect logs
popen_kwargs={
"cwd": r"C:\path\to\dir",
"env": {**os.environ, "MY_VAR": "123"},
},
)
if __name__ == "__main__":
run_ps()
Notes:
- run_shell_process does not return stdout/stderr; it logs them. It raises on non-zero exit (Prefect FailedRun).
- popen_kwargs supports standard subprocess.Popen args like env and cwd.
2) Capture output programmatically in a task
from prefect import flow, task
import subprocess, os
@task
def run_powershell_capture(cmd: str):
r = subprocess.run(
cmd,
shell=True, # ok on Windows to use PowerShell/cmd pipelines
text=True,
capture_output=True,
cwd=r"C:\path\to\dir",
env={**os.environ, "MY_VAR":"123"},
)
if r.returncode != 0:
raise RuntimeError(f"PowerShell failed: {r.stderr}")
return r.stdout
@flow
def my_flow():
out = run_powershell_capture('powershell -NoProfile -Command "Get-Date"')
print(out)
if __name__ == "__main__":
my_flow()
3) If you’re configuring deployments (prefect.yaml), and want stdout/stderr back
build:
- prefect.deployments.steps.run_shell_script:
id: setup
script: powershell -NoProfile -ExecutionPolicy Bypass -Command "Write-Output 'Hello from PS'"
directory: C:\path\to\dir
env:
MY_VAR: "123"
stream_output: true
- This step returns both stdout and stderr that can be referenced by subsequent steps (e.g., {{ setup.stdout }}) and fails on non-zero exit.
Gotchas and tips
- On Windows, the default shell is cmd.exe; explicitly invoke PowerShell: powershell ... or pwsh ... (for PowerShell 7+). If you need PS7 features cross‑platform, use pwsh.
- Execution policy can block .ps1 files. Common fixes: -ExecutionPolicy Bypass or set it per-process: Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force.
- For pipelines/redirection, keep shell=True (Prefect’s run_shell_process already does this). With subprocess.run, specify it yourself.
- Encoding: if you see odd characters, set output encoding in PowerShell: [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new().
If you can share whether you need to capture stdout/stderr in Python and whether you’re on Windows PowerShell 5.1 or PowerShell 7 (pwsh), I can tailor the snippet further.