Invoke-SystemCommand
Code Properties
- Language: PowerShell
- Cmdlets:
Register-ScheduledTask,Start-ScheduledTask
Overview
Function to execute a scriptblock as SYSTEM by setting up a temporary scheduled task. Supports both instant execution and execution at next boot.
Code
function Invoke-SystemCommand {
<#
.SYNOPSIS
Execute a scriptblock as SYSTEM by setting up a temporary scheduled task.
.PARAMETER Name
The name of the task
.PARAMETER Scriptblock
The code to run
.PARAMETER Mode
Whether to run it right away (Instant) or after the next reboot (OnBoot).
Default: Instant
.PARAMETER Wait
Wait for the task to complete.
Only applicable in "Instant" mode.
.PARAMETER Timeout
Timeout how long to wait for the task to complete.
Only applicable with "-Wait"
.EXAMPLE
Invoke-SystemCommand -Name 'WhoAmI' -ScriptBlock { whoami | Set-Content C:\temp\whoami.txt }
#>
[CmdletBinding()]
Param (
[Parameter(Mandatory = $true)]
[ValidateScript({
if ($_ -notmatch "'") { return $true }
throw "Name may not contain a single-quote. Value: $Name"
})]
[string]$Name,
[Parameter(Mandatory = $true)]
[string]$Scriptblock,
[ValidateSet('Instant', 'OnBoot')]
[string]$Mode = 'Instant',
[switch]$Wait,
[timespan]$Timeout = '00:00:30'
)
process {
if ($Mode -eq 'OnBoot') {
$Scriptblock = "Unregister-ScheduledTask -TaskName 'PowerShell_System_$Name' -Confirm:`$false", $Scriptblock -join "`n`n"
}
$bytes = [System.Text.Encoding]::Unicode.GetBytes($Scriptblock)
$encodedCommand = [Convert]::ToBase64String($bytes)
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-NoProfile -EncodedCommand $encodedCommand"
$principal = New-ScheduledTaskPrincipal -UserId SYSTEM -RunLevel Highest -LogonType Password
switch ($Mode) {
'Instant' { $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) }
'OnBoot' { $trigger = New-ScheduledTaskTrigger -AtStartup }
}
$task = Register-ScheduledTask -TaskName "PowerShell_System_$Name" -Description "PowerShell Task - $Name" -Action $action -Trigger $trigger -Principal $principal
if ($Mode -eq 'Instant') {
$task | Start-ScheduledTask
if (-not $Wait) {
Start-Sleep -Seconds 1
}
else {
$limit = (Get-Date).Add($Timeout)
while (($task | Get-ScheduledTask).State -ne "Ready") {
if ($limit -lt (Get-Date)) {
$task | Unregister-ScheduledTask -Confirm:$false
throw "Task execution exceeded time limit ($Timeout)"
}
}
}
$task | Unregister-ScheduledTask -Confirm:$false
}
}
}Usage
# run command as SYSTEM immediately
Invoke-SystemCommand -Name 'WhoAmI' -ScriptBlock { whoami | Set-Content C:\temp\whoami.txt }
# run command as SYSTEM and wait for completion
Invoke-SystemCommand -Name 'GetServices' -ScriptBlock { Get-Service | Export-Csv C:\temp\services.csv } -Wait
# schedule command to run at next boot
Invoke-SystemCommand -Name 'CleanupTask' -ScriptBlock { Remove-Item C:\temp\* -Force } -Mode OnBootAppendix
Note created on 2024-05-03 and last modified on 2024-12-31.
See Also
Backlinks
(c) No Clocks, LLC | 2024