如何转义 schtasks /tr 参数

How to escape schtasks /tr arguments

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

powershell.exe -file ..\Execute\execute.ps1

我试过将它分配给一个参数 $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

但是在 运行 上面的代码之后,没有任何反应 - 虽然任务创建成功,但似乎没有 运行。

我也试过不带引号将它分配给 $Argument,它起作用了,但我收到了以下警告:

ERROR: Invalid syntax. Value expected for '/tr'.
Type "SCHTASKS /CREATE /?" for usage.

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

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

我读过 this 但它对我不起作用

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

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

一个
$Argument = 'powershell.exe -file \"{0}\"' -f (Convert-Path ..\Execute\execute.ps1)

请注意 - 不幸的是 - 需要将嵌入的 " 转义为 \",这是一个长期存在的错误,为了向后兼容尚未修复 - 请参阅this GitHub docs issue 为背景。

Convert-Path 将相对路径解析为绝对路径。
注意相对路径必须引用一个已经存在的文件(或目录)。

类似地,相对路径你的脚本中也会相对于$env:windir\system32;要使它们相对于脚本的目录,首先通过执行Set-Location $PSScriptRoot[切换到你的脚本目录=213=] 在脚本的开头。


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

注意:实际上 相同的规则 适用于 运行 从 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 are expanded 相同的语法形式(例如,%USERNAME%

    • 警告:您无法逃避此类引用:
    • %% 不起作用 - 额外的 % 被简单地视为文字,并且仍然会发生扩展;例如,%%OS%% 结果为 %Windows_NT%
    • ^%(意外地)阻止扩展,但 保留 ^ - ^ 不会 escape ;相反,它 "disrupts" 变量名,在这种情况下,令牌保持原样;例如,^%OS^% 结果为 ^%OS^%,即按原样保留。

以上适用于命令,因为它们必须结束在计划任务中定义,正如您在任务计划程序中看到或交互式定义它们一样(taskschd.msc) .

另外,用于从命令行/PowerShell 脚本/批处理文件:

创建计划任务
  • 你必须引用整个命令

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

(如果命令只包含一个不需要转义的单个单词,你只能在没有引用的情况下离开,比如路径到不包含空格或特殊字符且未向其传递参数的可执行文件。)

调用schtasks.exe[2]时,/tr参数整体引用如下

  • 来自 PowerShell,使用 "...",如果您需要预先扩展(字符串插入)命令字符串 ;否则,使用 '...'.
    重要:转义 nested " as \" 的需要在这两种情况下都适用,在外部 "..." 引号意味着嵌套的 " 必须转义为 \`"(原文如此)。

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

PowerShell 示例:

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

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

# 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"

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

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