【问题标题】:$PSScriptRoot empty when called with Powershell ScheduledJob using -Filepath parameter使用 -Filepath 参数使用 Powershell ScheduledJob 调用 $PSScriptRoot 为空
【发布时间】:2018-08-23 21:09:12
【问题描述】:

使用 Powershell ScheduledJob(不要与 ScheduledTask 混淆)时,不会填充自动变量 $PSScriptRoot。

带有指定本地脚本的 -Filepath 参数的 ScheduledJob:

-Filepath "C:\Scriptpath\Script.ps1"

未能填充 $PSScriptRoot。

Get-Job 显示它没有运行脚本,而是像读取 .txt 文件一样输出脚本。 false

带有 -Scriptblock 和 & 调用操作员指定本地脚本的 ScheduledJob:

-Scriptblock {& "C:\Scriptpath\Script.ps1"}

成功填充 $PSScriptRoot。

Script.ps1 可以这么简单

$PSScriptRoot | out-file "C:\Test.txt"

问题似乎是任务计划程序中的作业如何执行文件,而不是 .ps1 中的语法错误。因为如果通过 -Scriptblock 参数调用相同的脚本也可以工作。在任何一种情况下,都会执行脚本,因为 Out-File 将创建一个空白 txt 文件。

这两种用法似乎都符合 Microsoft 的文档:

https://docs.microsoft.com/en-us/powershell/module/psscheduledjob/register-scheduledjob?view=powershell-5.1

任何有关行为的指导都会有所帮助。

编辑:

我注意到的是 Get-Job,它显示了计划作业正在执行的“命令”。

如果使用 -Scriptblock。 Get-Job 显示脚本块的确切内容,如上。

& "C:\Scriptpath\Script.ps1"

如果使用 -Filepath。 Get-Job 显示文件的内容。

$PSScriptRoot | out-file "C:\Test.txt"

这就像复制文件的内容然后调用它们。这可以解释为什么 $PSScriptRoot 无法填充。

....~测试噪音~

$PWD | Out-File "C:\file.txt"

在文件中显示 $PWD 恰好是执行计划作业的用户帐户的 $Home 变量。我想我正在做某事。

【问题讨论】:

  • 看起来像一个错误。

标签: powershell


【解决方案1】:

您似乎在描述两个问题:

  1. $PSScriptRoot 在某些情况下未填充。

  2. 带有 -FilePath 参数的 Set-ScheduledJob 显示文件的内容而不是执行它。

对于#1:There is an open issue filed for $PSScriptRoot,但很难说情况是否符合您的用例,因为...您没有提供任何代码。我建议您添加更多源代码来解释您的代码如何使用$PSScriptRoot

对于#2:Set-ScheduledJob : -Filepath 的文档似乎需要一个 .ps1 文件,但您的示例显示正在传递一个非 .ps1 文件。

-文件路径

指定计划作业运行的脚本。 输入本地计算机上.ps1 文件的路径。指定默认值 对于脚本参数,使用 ArgumentList 参数。每一个 计划作业必须具有 ScriptBlock 或 FilePath 值。

'c:\Filepath' 处的脚本实际上是否有 .ps1 扩展名?如果没有,请给它一个并更改您的 -Filepath 参数以匹配。

可能是一个问题导致另一个问题,但从当前的文本中不清楚它们是如何相关的。

【讨论】:

  • 这是一个ps1文件。该问题已更新以反映这一点。
  • 遗憾的是,我仅限于 Linux,它不支持 *-ScheduledJob cmdlet。不过,我很感兴趣,使用powershell.exe -File 时问题是否会重现。
  • 这是一个很好的调查。使用 Start-Job cmdlet 在 Linux 上重现相同的行为。奇怪的是 -FilePath 是这样实现的。
  • 与 Start-Job 相关的大部分代码似乎与远程调用作业密切相关。也许在启动远程作业时序列化本地脚本的内容比创建一些自动将脚本复制到远程位置以运行它们的系统更简单。
  • 是的,我认为没有办法强制执行此操作,而无需简单地使用 -filepath 来启动启动脚本的脚本?。这本质上就是 -scriptblock 正在做的事情,将脚本作为命令启动。我想我有这个问题的答案,即使这不是我们想要看到的。
【解决方案2】:

关于 $PSScriptRoot 不在 ScheduledJob 中。我们发现$PSScriptRoot不仅对计划作业执行的根文件失败,而且对随后包含的根文件也失败了。

例如,假设根文件包含. "<absolute path>\Include-SomeOtherFile.ps1",在Include-SomeOtherFile.ps1 中,我们调用. "$PSScriptRoot\Include-YetAnotherFile.ps1"。这会失败,因为 $PSScriptRoot 仍然是空的。

我不想硬编码所有内容,所以我在根文件中检查$PSScriptRoot 是否为空。如果为空,它将使用调用运算符再次启动脚本,但在 $PSScriptRoot 工作的新上下文中:

$ErrorActionPreference = "Stop"
 
if ($PSScriptRoot -eq "")
{   
    # Execute this file again but a new 
    # context where $PSScriptRoot works
    & "<absolute path of this file>.ps1"

    Exit $LASTEXITCODE
}
   
try 
{
    # Rest of code using $PSScriptRoot
}
catch
{
    Exit 1
}

所以我仍然必须使用根文件的绝对路径,但之后我可以在我包含的文件中依赖 $PSScriptRoot。

根据this SO answer,如果您想计算绝对路径并且很高兴依靠计划作业的名称,您显然可以使用以下(未经测试):

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command

【讨论】:

    猜你喜欢
    • 2021-02-24
    • 2017-11-12
    • 2023-04-03
    • 2016-09-24
    • 1970-01-01
    • 2013-11-01
    • 2014-03-19
    • 2018-01-02
    • 1970-01-01
    相关资源
    最近更新 更多