Windows 计划任务无法在启动时写入事件日志

Windows scheduled task unable to write to event log at startup

如果以下任务按原样 运行 在启动时(重新启动并检查日志时)它将成功完成并且不会写入任何内容,我将无法在系统或应用程序日志中获取日志条目应用程序事件日志。如果我 运行 手动执行任务,它会很好地写入应用程序日志。

Windows 2019 服务器上的 Powershell 5.1:

    # 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

更新:正如@Bender The Greatest 指出的那样,这与从 comspec 调用 powershell 有关,这里的工作是关于语法协调,转义和引号是主要的违规者。由于下面的评论没有现成的答案,我想展示我使用固定代码的方法,其中包括一个转义模式,用于将本地构建时变量推入作业数据

$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

像这样修改您的 $action 定义:

$action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument "-Command ""$command"""

您不能提供 ScriptBlock 作为 powershell -Command 的参数 ,除非您 从 PowerShell 本身调用 powershell 二进制文件。相反,使用一个字符串,就像我在上面所做的那样,通过使用两个双引号 (") 作为字符串参数而不是 curly-braces ({}) 你环绕 $command .


外部程序无法传入 ScriptBlock 的原因是在 PowerShell 之外,ScriptBlock 不存在。当 Task Scheduler 执行它时,它将把它解析为一个字符串,然后 PowerShell 将处理该解析的字符串。在这种情况下,它将逐字定义 ScriptBlock 并在没有 运行 的情况下退出,因为在这种情况下会呈现花括号,这在语法上定义了 PowerShell 中的 ScriptBlock。理论上您可以在 ScriptBlock 前加上 call-operator (&) 并且它应该执行,但是没有什么意义,因为您可以简单地使用字符串文字来代替。

ScriptBlock 在 PowerShell 中工作,因为在 PowerShell 中,它可以发挥自己的魔力,确保某些类型在执行前转换为字符串 它认为适合 。在进程触发之前,它不会成为文字 {$command},而是首先呈现为没有括号 的文字字符串 。此处的操作顺序很重要,这就是为什么您不能在 PowerShell 之外将 ScriptBlocks 用于 -Command


请记住:如您所写,您的任务不会像您预期的那样工作。但是,一旦您解决了上述问题,特别是因为您已经根据问题评论设置了转录,这应该为您提供必要的工具来解决计划任务定义中的剩余问题。