Search code examples
windowspowershellscheduled-tasks

Windows scheduled task unable to write to event log at startup


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.

Powershell 5.1 on Windows 2019 Server:

    # 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

UPDATE: As @Bender The Greatest pointed out, this has to do with invoking powershell from comspec, and the work here is about syntax reconciliation with escapes and quotes being the main offenders. Since there was no ready answer from the comments below I wanted to show the method I used with fixed code that includes an escape pattern for pushing local construction-time variables into the job data

$script = "Write-EventLog -LogName Application -Source Application -EventID 1 -Message `"[$($env:COMPUTERNAME)\$($env:USERNAME)] important system startup message`""
$command = $script.replace('"','\"')
$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-ExecutionPolicy Bypass -NonInteractive -NoProfile -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

Solution

  • 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.