Skip to content

PowerShell Scheduled Tasks

How to create, manage, and automate Windows scheduled tasks using PowerShell cmdlets like Get-ScheduledTask, Register-ScheduledTask, and New-ScheduledTaskTrigger for script execution and system maintenance.

A scheduled task is an automated job managed by the Windows Task Scheduler engine that triggers scripts or binaries based on predefined intervals, system events, or user states. PowerShell's ScheduledTasks module lets you view, create, modify, and remove scheduled tasks entirely from the command line. Tasks are represented as Microsoft.Management.Infrastructure.CimInstance#Root/Microsoft/Windows/TaskScheduler/MSFT_ScheduledTask objects, constructed from modular actions, triggers, and principals.

Viewing Scheduled Tasks with Get-ScheduledTask

The Get-ScheduledTask cmdlet queries the Task Scheduler service and lists all scheduled tasks registered on the system. It returns CimInstance objects representing each task's definition and does not display run history.

Consolepowershell
Get-ScheduledTask
Outputplaintext
TaskPath                                          TaskName                    State
--------                                          --------                    -----
\                                                 OneDrive Standalone Update  Ready
\Microsoft\Windows\Power Efficiency Diagnostics\  AnalyzeSystem               Ready
\                                                 DailyBackup                 Ready

Getting a Specific Task

Use the -TaskName parameter to retrieve a single task by name.

Consolepowershell
Get-ScheduledTask -TaskName "DailyBackup"

where -TaskName is the name of the task to retrieve; supports wildcards.

To view detailed run history and results:

Consolepowershell
Get-ScheduledTask -TaskName "DailyBackup" | Get-ScheduledTaskInfo
Outputplaintext
LastRunTime        : 5/10/2024 3:00:00 AM
LastTaskResult     : 0
NextRunTime        : 5/11/2024 3:00:00 AM
NumberOfMissedRuns : 0

Filtering by Task Path

Task Scheduler organizes tasks hierarchically like a filesystem directory. By default, vendor and operating system tasks reside inside nested subdirectories (such as \Microsoft\Windows\Defrag\). Specifying -TaskPath "\" scopes the search to user-created tasks in the root folder, avoiding hundreds of internal Windows tasks.

get-tasks-demo.ps1powershell
Get-ScheduledTask -TaskPath "\" | 
    Select-Object -Property TaskName, State, @{Name="Actions"; Expression={$_.Actions.Execute}}

where:

  • -TaskPath filters by the directory container within the Task Scheduler tree (\ indicates the root folder).
  • Select-Object retrieves selected fields, using an expression script block to extract executable paths from the nested Actions collection.
Consolepowershell
./get-tasks-demo.ps1
Outputplaintext
TaskName           State Actions
--------           ----- -------
BackupScript       Ready C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
SystemHealthAudit  Ready C:\Scripts\audit.bat
OneDrive Reporting Ready C:\Program Files\OneDrive\OneDriveStandaloneUpdater.exe

Building Blocks: Triggers and Actions

Before creating a task, you need two components: a trigger (when it runs) and an action (what it runs). A principal can also be supplied to define the security context.

Creating a Trigger with New-ScheduledTaskTrigger

The New-ScheduledTaskTrigger cmdlet defines when a task should execute.

Consolepowershell
$trigger = New-ScheduledTaskTrigger -Daily -At "3:00AM"

where:

  • -Daily specifies the task recurs every day (other options: -Once, -Weekly, -AtLogOn, -AtStartup).
  • -At specifies the time of day the task should trigger.

Creating an Action with New-ScheduledTaskAction

The New-ScheduledTaskAction cmdlet defines what the task executes.

Consolepowershell
$action = New-ScheduledTaskAction -Execute "powershell.exe" `
                                   -Argument "-File C:\Scripts\backup.ps1"

where:

  • -Execute is the executable to run (e.g., powershell.exe, pwsh.exe, notepad.exe).
  • -Argument is the command-line arguments passed to the executable.

Combined Component Example

create-components.ps1powershell
$action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\RotateLogs.ps1"

$trigger = New-ScheduledTaskTrigger -Daily -At "2:30 AM"

Write-Output "Action Target: $($action.Execute) $($action.Arguments)"
Write-Output "Trigger Mode: Daily at $($trigger.StartBoundary)"

where:

  • New-ScheduledTaskAction generates an action definition object.
  • -Execute specifies the absolute path or registered system executable.
  • -Argument specifies parameters passed to the executable upon invocation.
  • New-ScheduledTaskTrigger generates a trigger object defining timing constraints.
  • -Daily creates a recurring daily schedule.
  • -At specifies the startup time of day.
Consolepowershell
./create-components.ps1
Outputplaintext
Action Target: pwsh.exe -NoProfile -ExecutionPolicy Bypass -File C:\Scripts\RotateLogs.ps1
Trigger Mode: Daily at 2026-03-31T02:30:00

Registering a New Task with Register-ScheduledTask

The Register-ScheduledTask cmdlet combines a trigger, an action, and optionally a principal or settings into a new scheduled task and registers it with the Windows Task Scheduler.

create-backup-task.ps1powershell
$trigger = New-ScheduledTaskTrigger -Daily -At "3:00AM"
$action  = New-ScheduledTaskAction -Execute "powershell.exe" `
                                    -Argument "-File C:\Scripts\backup.ps1"

Register-ScheduledTask -TaskName "DailyBackup" `
                        -Trigger $trigger `
                        -Action $action `
                        -Description "Runs the nightly backup script" `
                        -User "SYSTEM"

where:

  • -TaskName is the name assigned to the new scheduled task.
  • -Trigger is the trigger object created with New-ScheduledTaskTrigger.
  • -Action is the action object created with New-ScheduledTaskAction.
  • -Description is an optional human-readable description of the task.
  • -User is the account context the task runs under (e.g., SYSTEM, a domain user).
Consolepowershell
./create-backup-task.ps1
Outputplaintext
TaskPath  TaskName     State
--------  --------     -----
\         DailyBackup  Ready

Using Settings and RunLevel

Add -RunLevel and -Settings for finer control over execution behavior.

Consolepowershell
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -DontStopOnIdleEnd

Register-ScheduledTask -TaskName "DailyBackup" `
                        -Trigger $trigger `
                        -Action $action `
                        -Settings $settings `
                        -RunLevel Highest

where:

  • -Settings are additional behavior options (e.g., run as soon as possible if a scheduled start was missed).
  • -RunLevel Highest runs the task with administrative privileges.

Using a Principal for Execution Context

register-task-demo.ps1powershell
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File C:\Scripts\Archive.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "03:00 AM"
$principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest

Register-ScheduledTask -TaskName "DailyDataArchive" -TaskPath "\" -Action $action -Trigger $trigger -Principal $principal -Description "Daily archive of system metrics."

where:

  • Register-ScheduledTask writes and activates the task within the Task Scheduler service.
  • -TaskName is the unique identifying name assigned to the task.
  • -TaskPath is the folder location in the task tree where the definition will reside.
  • -Action is one or more action objects created by New-ScheduledTaskAction.
  • -Trigger is one or more trigger objects created by New-ScheduledTaskTrigger.
  • -Principal specifies the security identity under which the task executes, generated via New-ScheduledTaskPrincipal.
  • -Description is an optional string explaining the administrative purpose of the task.
Consolepowershell
./register-task-demo.ps1
Outputplaintext
TaskPath TaskName         State
-------- --------         -----
\        DailyDataArchive Ready

Removing a Task with Unregister-ScheduledTask

The Unregister-ScheduledTask cmdlet permanently removes an existing task and its definitions from the Task Scheduler database.

Consolepowershell
Unregister-ScheduledTask -TaskName "DailyBackup" -Confirm:$false

where:

  • -TaskName is the name of the task to remove.
  • -Confirm:$false suppresses the interactive confirmation prompt.

Practical Usage: Deploying a Weekly Maintenance Task

A common admin scenario is scheduling a maintenance script to run weekly, only when the target machine is powered on.

deploy-maintenance-task.ps1powershell
$trigger  = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Sunday -At "2:00AM"
$action   = New-ScheduledTaskAction -Execute "powershell.exe" `
                                     -Argument "-NoProfile -File C:\Scripts\maintenance.ps1"
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable

$existingTask = Get-ScheduledTask -TaskName "WeeklyMaintenance" -ErrorAction SilentlyContinue
if ($existingTask) {
    Unregister-ScheduledTask -TaskName "WeeklyMaintenance" -Confirm:$false
}

Register-ScheduledTask -TaskName "WeeklyMaintenance" `
                        -Trigger $trigger `
                        -Action $action `
                        -Settings $settings `
                        -User "SYSTEM" `
                        -Description "Weekly system maintenance script"

where:

  • $existingTask checks whether a task with the same name already exists.
  • -ErrorAction SilentlyContinue prevents an error if the task isn't found.
  • The script unregisters any existing task before re-registering it, avoiding duplicate or conflicting task definitions.
Consolepowershell
./deploy-maintenance-task.ps1
Get-ScheduledTask -TaskName "WeeklyMaintenance"
Outputplaintext
TaskPath  TaskName            State
--------  ------------------  -----
\         WeeklyMaintenance   Ready

Practical Administration: Manual Invocation and Task Auditing

Administrators often need to deploy a task, manually run it to verify functionality, and inspect the last run result to ensure proper configuration.

test-and-audit-task.ps1powershell
$taskName = "MaintenanceAudit"

$action = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "/c echo Maintenance Complete > C:\Logs\task_test.log"
$trigger = New-ScheduledTaskTrigger -Daily -At "11:00 PM"
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Force | Out-Null

Start-ScheduledTask -TaskName $taskName

Start-Sleep -Seconds 2
$info = Get-ScheduledTaskInfo -TaskName $taskName

[PSCustomObject]@{
    TaskName       = $taskName
    LastRunTime    = $info.LastRunTime
    LastTaskResult = $info.LastTaskResult
    NextRunTime    = $info.NextRunTime
}

where:

  • -Force overwrites any existing task with the same name during registration.
  • Out-Null discards pipeline output from Register-ScheduledTask for clean console execution.
  • Start-ScheduledTask triggers the task out-of-schedule immediately.
  • Start-Sleep temporarily pauses script execution to allow the spawned process to execute and finish.
  • Get-ScheduledTaskInfo retrieves execution history, exit codes, and scheduled upcoming runs.
  • LastTaskResult is the exit code returned by the last run (0 denotes success).
Consolepowershell
./test-and-audit-task.ps1
Outputplaintext
TaskName         LastRunTime           LastTaskResult NextRunTime
--------         -----------           -------------- -----------
MaintenanceAudit 3/31/2026 10:14:02 AM              0 3/31/2026 11:00:00 PM
Navigation