Home > Net >  Windows scheduled task unable to write to event log at startup
Windows scheduled task unable to write to event log at startup

Time:03-30

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.

  • Related