I cannot get a log entry in to system or application logs if the below task runs as-is, at Startup (upon reboot and inspecting the logs) it will complete with success and write nothing to the application event log. If I run the task manually it writes to the application log just fine.
I tried writing to the system log instead, same behavior. I am starting to think Windows requires a user session to write to the event logs but ... that seems wrong as SYSTEM is able to write to the logs and I cannot find any documentation explaining what this apparent limitation is.
on Windows 2019 Server, reproduce with:
# objective: log to windows event log at startup without requiring a login
$command = '-ExecutionPolicy Bypass -NonInteractive -NoProfile -Command { Write-EventLog -LogName Application -Source "Application" -EventID 1 -Message "important system startup message" }'
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-Command {$command}"
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -Compatibility Win8 -MultipleInstances IgnoreNew -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$taskName = "Helpful Task Name"
$description = "Task does helpful things"
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings -Description $description -User "NT AUTHORITY\SYSTEM" -RunLevel Highest -Force
I have tried removing -NoProfile and -NonInteractive without any change in behavior
CodePudding user response:
Modify your $action
definition like so:
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-Command ""$command"""
You cannot provide a ScriptBlock
as an argument to powershell -Command
unless you are invoking the powershell
binary from within PowerShell itself. Instead, use a string as I've done above by using two double quotes ("
) for a string argument instead of the curly-braces ({}
) you wrapped around $command
.
The reason external programs can't pass in a ScriptBlock
is because outside of PowerShell, a ScriptBlock
doesn't exist. When Task Scheduler executes this, it will parse this as a string, then PowerShell will process that parsed string. In this case, it will literally define the ScriptBlock
and exit without running it because the curly braces get rendered in this case, which syntactically defines a ScriptBlock
in PowerShell. You could theoretically prefix the ScriptBlock
with the call-operator (&
) and it should execute, but there's little point since you can simply use a string literal instead.
The ScriptBlock
works inside PowerShell because inside PowerShell, it can do its own magic to ensure certain types are converted to strings as it sees fit to before execution. Instead of becoming a literal {$command}
it will first render as a literal string without the brackets before the process fires off. The order of operations matters here and is why you can't use ScriptBlocks
for -Command
outside of PowerShell.
Keep in mind: as written your task will not work as you expect. However, once you fix the above problem, especially since you have the transcripting set up as per the question comments, this should give you the tools necessary to work through the remaining issues with your Scheduled Task definition.