如何转义 schtasks /tr 参数

gjj*_*hh_ 6 windows powershell cmd scheduled-tasks windows-task-scheduler

我需要安排一个 PowerShell 任务,如下所示:

powershell.exe -file ..\Execute\execute.ps1
Run Code Online (Sandbox Code Playgroud)

我尝试将它分配给一个参数,$Argument然后将其传递给schtasks如下所示:

$Argument = "powershell.exe -file '..\Execute\execute.ps1'"
schtasks /create /tn "SOE_Checks" /tr $Argument /sc DAILY /st 05:00 /ru "System" /rl HIGHEST /f
Run Code Online (Sandbox Code Playgroud)

但是在运行上面的代码后,什么也没发生 - 虽然任务创建成功,但它似乎没有运行。

我也尝试将它分配给$Argument没有引号,它有效,但我收到以下警告:

ERROR: Invalid syntax. Value expected for '/tr'.
Type "SCHTASKS /CREATE /?" for usage.
Run Code Online (Sandbox Code Playgroud)

谁能让我知道我在这里做错了什么?(我知道我可以使用 PowerShell 完成此操作,New-ScheduledTaskAction但我希望它以这种方式工作)

只是想补充一点,如果我改变的文件路径的特定位置$Argument这样的,
$Argument = "powershell.exe -file 'C:\SOE\Execute\execute.ps1'",它工作正常,没有任何警告,但这并不理想。

我已经阅读了这篇文章,但它对我不起作用

mkl*_*nt0 5

schtasks.exe使用执行创建的计划任务将工作目录设置为$env:windir\system32[1],因此除非您的脚本恰好位于..\Execute\execute.ps1相对于那里的位置,否则您的命令将无法按预期工作。

如果您不想将脚本路径直接硬编码到命令中,请动态构造命令,方法是在分配给时将相对路径解析为绝对$Argument路径:

$Argument = 'powershell.exe -file \"{0}\"' -f (Convert-Path ..\Execute\execute.ps1)
Run Code Online (Sandbox Code Playgroud)

请注意 - 不幸的是 - 需要转义嵌入的"as \",这是一个长期存在的错误,为了向后兼容性尚未修复 - 请参阅此 GitHub 文档问题了解背景。

Convert-Path将相对路径解析为绝对路径。
请注意,相对路径必须引用现有文件(或目录)。

同样,脚本内的相对路径相对于$env:windir\system32; 要使它们相对于脚本的目录,请首先通过Set-Location $PSScriptRoot在脚本开头执行来更改到脚本的目录。


可选阅读:如何引用从计划任务运行的命令:

注意:实际上,应用的规则与从 Windows“运行”对话框(按 )运行命令时适用的规则相同WinKey+R可以使用它来测试驱动命令(要传递到 的命令schtasks /tr,不带外部引号,而不是整个schtasks命令行) - 不过请注意,工作目录将是用户的主目录,并且您将无法'...'在 PowerShell CLI 的-File参数周围使用 - 引号 - 见下文):

  • cmd.exe执行过程中不参与,这意味着:

    • cmd.exe例如,您不必担心元字符(例如)的非双引号使用&,因此您甚至可以在作为参数(一部分)传递到 PowerShell CLI 的引号字符串中使用这些字符。powershell.exe-Command

    • 相反,不直接> c:\path\to\log.txt支持输出重定向(例如, )。

    • 在调用 PowerShell CLI 的上下文中,这意味着:

      • 使用 时-File,您无法在命令行上使用它们,而必须在脚本中执行它们。

      • 但是-Command,通过 ,您可以使用它们,因为随后是PowerShell应用它们(但请注意,Windows PowerShell 的>操作员创建 UTF-16LE 文件)。

  • (虽然cmd.exe 涉及)使用与中相同的语法形式对环境变量的引用进行了扩展cmd.exe (例如,%USERNAME%

    • 警告:您无法逃避此类引用
    • %%不起作用 - 附加值%被简单地视为文字,并且扩展仍然发生;例如,%%OS%%结果为%Windows_NT%.
    • ^%(意外地)防止扩展,但保留^- the^不会转义;相反,它“破坏”了变量名,在这种情况下,令牌保持原样;例如,^%OS^%结果为^%OS^%,即按原样保留。

上述内容适用于命令,因为它们必须最终在计划任务中定义,就像您在任务计划程序 ( taskschd.msc) 中以交互方式看到或定义它们一样。

此外,要从命令行/PowerShell 脚本/批处理文件创建计划任务:

  • 您必须引用整个命令并且

  • 遵守调用 shell 关于转义和预先字符串插值的语法规则。

(你只能逃走如果命令仅包含一个不需要转义的单词例如不包含空格或特殊字符且不传递任何参数的可执行文件的路径,则只能在不引用的情况下退出。)

当调用schtasks.exe[2]时,引用/tr整个参数,如下所示

  • 在 PowerShell 中"...",如果需要预先扩展(字符串插值)命令字符串,请使用;否则,使用'...'.
    重要提示:需要转义嵌套 "\",在外部引用的情况下"..."意味着嵌套"必须转义为\`"(sic)。

    • 令人惊讶的是,schtasks.exe它可以识别嵌入的 '...'引用并自动将其转换为"..."引用- 这就是为什么您的原始命令 ,"powershell.exe -file '..\Execute\execute.ps1'"有效,即使在直接调用中 PowerShell CLI不会'...'与 结合使用-File
  • 来自cmd.exe(无论是直接还是来自批处理文件),您必须使用"...".

PowerShell 示例

  • 以下 PowerShell 命令创建并执行两个运行一次的计划任务,名为test1它们test2在下一个日历分钟开始时在调用用户的上下文中运行。(之后您必须手动删除这些任务。)

  • 您可能需要等待最多 1 分钟才能看到调用启动,此时将为每个任务弹出一个新的控制台窗口。

# Create sample script test.ps1 in the current dir. that
# echoes its arguments and then waits for a keypress.
'"Hi, $Args."; Read-Host "Press ENTER to exit"' > test.ps1

# Find the start of the next calendar minute.
$nextFullMinute = ([datetime]::Now.AddMinutes(1).TimeOfDay.ToString('hh\:mm'))

# -File example:
# Invoke test.ps1 and pass it 'foo' as an argument.
# Note the escaped embedded "..." quoting around the script path
# and that with -File you can only pass literal arguments at 
# invocation time).
schtasks.exe /create /f /tn test1 /sc once /st $nextFullMinute `
  /tr "powershell -File \`"$PWD/test.ps1\`" foo"                                                                            #`# (dummy comment to fix broken syntax highlighting)

# -Command example:
# Invoke test.ps1 and pass it $env:USERNAME as an argument.
# Note the '...' around the script path and the need to invoke it with
# &, as well as the ` before $env:USERNAME to prevent its premature expansion.
schtasks.exe /create /f /tn test2 /sc once /st $nextFullMinute `
  /tr "powershell -Command & '$PWD/test.ps1' `$env:USERNAME"

"Tasks will execute at ${nextFullMinute}:00"
Run Code Online (Sandbox Code Playgroud)

[1] 请注意,任务计划程序 GUI 允许您配置工作目录,但此功能无法通过schtasks.exe实用程序使用。

[2] 这同样适用于传递给PowerShell cmdlet-Argument参数的值New-ScheduledTaskAction,但请注意,可执行文件名称/路径是通过-Execute参数单独指定的。
相比之下,Register-ScheduledJob用于创建计划的 PowerShell作业的cmdlet接受脚本块作为要运行的命令,这消除了引用问题。