$TaskName = "xyOps-RunAsUser"
$User = "DOMAIN\User" # or "$env:COMPUTERNAME\User"
$Wrapper = "C:\ProgramData\xyOps\runas\wrapper.ps1"
New-Item -Force -ItemType Directory (Split-Path $Wrapper) | Out-Null
@'
param(
[string]$RequestPath = "C:\ProgramData\xyOps\runas\request.json"
)
# Read request
$req = Get-Content -Raw -LiteralPath $RequestPath | ConvertFrom-Json
# Basic validation (tighten this to your needs)
if (-not $req.mode) { throw "Missing mode" }
# Execute
switch ($req.mode) {
"command" {
# Runs via cmd.exe to keep it simple, supports user-defined exe/args
$p = Start-Process -FilePath $req.file -ArgumentList $req.args -WorkingDirectory $req.cwd -PassThru
$p.WaitForExit()
exit $p.ExitCode
}
"pwsh" {
# Execute a PowerShell script file with args
$argList = @("-NoProfile","-ExecutionPolicy","Bypass","-File",$req.file) + @($req.args)
$p = Start-Process -FilePath "pwsh.exe" -ArgumentList $argList -WorkingDirectory $req.cwd -PassThru
$p.WaitForExit()
exit $p.ExitCode
}
default { throw "Unknown mode: $($req.mode)" }
}
'@ | Set-Content -LiteralPath $Wrapper -Encoding UTF8
# Task action: always runs wrapper, wrapper reads request.json
$Action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$Wrapper`""
$Principal = New-ScheduledTaskPrincipal -UserId $User -LogonType Password -RunLevel Limited
$Settings = New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -StartWhenAvailable
# Dummy trigger required to register; we will run it on-demand
$Trigger = New-ScheduledTaskTrigger -AtLogOn
$Task = New-ScheduledTask -Action $Action -Principal $Principal -Trigger $Trigger -Settings $Settings
$SecurePass = Read-Host "Password for $User" -AsSecureString
Register-ScheduledTask -TaskName $TaskName -InputObject $Task -User $User -Password $SecurePassNotes:
- RunLevel Limited = non-elevated as that user (change to Highest if you actually want elevation).
- The task always runs the wrapper; you change what it does by changing the request file.
Run a PowerShell script as the target user
$RequestPath = "C:\ProgramData\xyOps\runas\request.json"
$TaskName = "xyOps-RunAsUser"
$req = @{
mode = "pwsh"
file = "C:\Path\To\UserScript.ps1"
args = @("arg1","arg2")
cwd = "C:\Path\To"
}
($req | ConvertTo-Json -Depth 5) | Set-Content -LiteralPath $RequestPath -Encoding UTF8
Start-ScheduledTask -TaskName $TaskNameWith a single fixed request.json, two simultaneous launches will collide.
If you need concurrency, use a unique request file per user.