| description | Migrate scheduled tasks, PSScheduledJob scripts, and automation from Windows PowerShell 5.1 to PowerShell 7. |
|---|---|
| ms.date | 04/15/2026 |
| title | Migrate scheduled tasks and automation to PowerShell 7 |
Many organizations run PowerShell scripts through Windows Task Scheduler,
PSScheduledJob, or automation platforms. This article covers how to update
these configurations for PowerShell 7.
The PSScheduledJob module (Register-ScheduledJob, Get-ScheduledJob,
Set-ScheduledJob, and related cmdlets) was removed in PowerShell 7. This
module depended on PowerShell Workflow, which isn't available in .NET Core.
Use the ScheduledTasks module with pwsh.exe as the executable. The
ScheduledTasks module works in both Windows PowerShell 5.1 and
PowerShell 7.
Before (Windows PowerShell 5.1):
Register-ScheduledJob -Name 'DailyCleanup' `
-ScriptBlock { Remove-Item "$env:TEMP\*.tmp" -Force } `
-Trigger (New-JobTrigger -Daily -At '3:00 AM')After (PowerShell 7):
$action = New-ScheduledTaskAction `
-Execute "$Env:ProgramFiles\PowerShell\7\pwsh.exe" `
-Argument '-NoProfile -File "C:\Scripts\DailyCleanup.ps1"'
$trigger = New-ScheduledTaskTrigger -Daily -At '3:00 AM'
Register-ScheduledTask -TaskName 'DailyCleanup' `
-Action $action `
-Trigger $trigger `
-RunLevel Highest `
-User 'SYSTEM'Important
Always use the full path to pwsh.exe in scheduled task actions. Relying
on PATH resolution can break when the system PATH changes during
updates.
Use the full path to the PowerShell 7 executable:
C:\Program Files\PowerShell\7\pwsh.exe
In PowerShell 7, the first positional parameter is -File (not -Command
as in Windows PowerShell 5.1). This affects how you specify arguments in
Task Scheduler:
| Scenario | Argument string |
|---|---|
| Run a script file | -NoProfile -File "C:\Scripts\task.ps1" |
| Run an inline command | -NoProfile -Command "Get-Process | Export-Csv C:\logs\procs.csv" |
| Run a script with parameters | -NoProfile -File "C:\Scripts\task.ps1" -Param1 Value1 |
Note
If your existing tasks use powershell.exe "Get-Date" (relying on the
default -Command positional parameter), you must add -Command
explicitly when switching to pwsh.exe. Without it, PowerShell 7 treats
the argument as a file path.
PowerShell 7 passes the script's exit code to Task Scheduler. Use
exit $code in your scripts to return meaningful exit codes. Task Scheduler
shows the Last Run Result as the process exit code.
Use the following script to find all scheduled tasks that reference
powershell.exe:
Get-ScheduledTask | ForEach-Object {
$actions = $_.Actions | Where-Object {
$_.Execute -match 'powershell\.exe'
}
if ($actions) {
[PSCustomObject]@{
TaskName = $_.TaskName
TaskPath = $_.TaskPath
Execute = ($actions.Execute -join '; ')
Arguments = ($actions.Arguments -join '; ')
State = $_.State
}
}
} | Format-Table -AutoSizeThis lists every task that needs to be updated to use pwsh.exe.
After auditing, update tasks programmatically. The following script creates a backup of each task's XML definition, then updates the executable path:
$backupDir = 'C:\TaskBackups'
New-Item -Path $backupDir -ItemType Directory -Force
$tasks = Get-ScheduledTask | Where-Object {
$_.Actions.Execute -match 'powershell\.exe'
}
foreach ($task in $tasks) {
# Export backup
$exportPath = Join-Path $backupDir "$($task.TaskName).xml"
Export-ScheduledTask -TaskName $task.TaskName `
-TaskPath $task.TaskPath |
Set-Content -Path $exportPath
# Update each action
foreach ($action in $task.Actions) {
if ($action.Execute -match 'powershell\.exe') {
$action.Execute = `
"$Env:ProgramFiles\PowerShell\7\pwsh.exe"
# Add -Command if arguments don't start with
# a flag
if ($action.Arguments -and
$action.Arguments -notmatch '^\s*-') {
$action.Arguments =
"-Command $($action.Arguments)"
}
}
}
Set-ScheduledTask -InputObject $task
Write-Host "Updated: $($task.TaskPath)$($task.TaskName)"
}Important
Test in a non-production environment before running bulk updates. Always back up task definitions first so you can roll back if scripts behave differently under PowerShell 7.
If a task fails under PowerShell 7, restore it from the XML backup:
Register-ScheduledTask -TaskName 'DailyCleanup' `
-Xml (Get-Content 'C:\TaskBackups\DailyCleanup.xml' -Raw) `
-ForceAzure Automation supports PowerShell 7 runbooks. When creating or updating a runbook:
- Set the Runtime version to 7.2 or later in the runbook properties
- Update any
Get-WmiObjectcalls toGet-CimInstance - Test the runbook in the Azure portal before publishing
Note
Hybrid Runbook Workers use the locally installed PowerShell version. If
you need PowerShell 7 on hybrid workers, install it on the worker machines
and update the worker configuration to use pwsh.exe.
Orchestrator runbook activities that call powershell.exe can be updated
to call pwsh.exe. Update the program path in the Run .NET Script or
Run Program activity properties.
In Jenkins pipeline scripts, specify the PowerShell 7 executable:
bat '"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -File script.ps1'Or use the PowerShell plugin configured to use pwsh.exe as the
executable.