PowerShell 2.0 - 在命令行调用和从ISE中运行脚本的区别

4

在ISE中编写部署脚本后,我们需要持续集成(CI)服务器能够自动运行它们,即通过命令行或批处理文件。

我注意到以下调用之间存在一些显著差异:

powershell.exe -File Script.ps1
powershell.exe -Command "& '.\Script.ps1'"
powershell.exe .\Script.ps1

一些简单的例子:

  • 使用-File时,错误处理方式与ISE完全相同。
  • 另外两个调用似乎忽略了$ErrorActionPreference变量,并且在try/catch块中没有捕获Write-Error

使用pSake时:

  • 最后两个调用完美运行
  • 使用ISE或-File参数将会失败,报以下错误:

The variable '$script:context' cannot be retrieved because it has not been set


每种语法的含义是什么,它们为什么会有不同的行为?我希望找到一种语法,它可以始终正常工作并且像ISE一样表现。

你觉得这个命令会产生什么结果?try { remove-item nonexisting -ea 0 } catch { 'err occured' } 如果我将-ea改为2,会发生什么?在我的看法中,write-error并没有被捕获在catch块中。 - stej
感谢您的帮助,stej。您的示例按照我预期的方式工作,这意味着我提到的行为可能是特定调用的结果。我已经添加了一个真实的样本作为单独的条目,以便更易读而不是作为评论。 - Romain
2个回答

2

这不是一个答案,只是一条注释。

我搜索了关于 -file 参数的解释。大多数来源只说“执行一个脚本文件”。在 http://technet.microsoft.com/en-us/library/dd315276.aspx 上我读到:

Runs the specified script in the local scope ("dot-sourced"), so that the functions
and variables that the script creates are available in the current session. Enter
the script file path and any parameters.

之后,我尝试调用这个函数:

powershell -command ". c:\temp\aa\script.ps1"
powershell -file c:\temp\aa\script.ps1
powershell -command "& c:\temp\aa\script.ps1"

请注意,前两个停止在Get-Foo之后,但最后一个没有停止。
我上面描述的问题与模块有关--如果你在script.ps1中定义了Get-Foo,那么我描述的所有3个调用都会在调用Get-Foo之后停止。
尝试在script.ps1中定义它或使用Get-Foo文件进行点源,并检查它。有可能会起作用:)

谢谢!你说得对,前两个调用似乎做了完全相同的事情,都涉及错误处理和 pSake。关于模块,解决方法很难,因为在很多情况下,这些函数属于内部库或第三方模块。不过,如果有选择的话,将模块重命名为 PS1 然后进行点操作是可行的!我想知道是否始终使用 -File 更安全,这样行为就与在 ISE 中开发时获得的一致。 - Romain
作为一则注释,我刚刚发现另一个区别:使用 powershell.exe .\script.ps1-Command "& script.ps1" 时,Set-StrictMode 命令将无法捕获你导入的模块中的任何语法错误。使用 -File script.ps1-Command ". script.ps1" 时,它会像在 ISE 中一样捕获所有错误。 - Romain
是的,Set-StrictMode设置了“某些东西”,以及$errorActionPreference = ..。 这是相同的模式 - 设置某些东西,但在模块函数中不使用它。 模块有时会很棘手,但在这种情况下,我不知道发生了什么。 - stej

0
这是一个具体的例子,说明了我所描述的行为。

MyModule.psm1

function Get-Foo
{
    Write-Error 'Failed'
}

Script.ps1

$ErrorActionPreference = 'Stop'

$currentFolder = (Split-Path $MyInvocation.MyCommand.Path)
Import-Module $currentFolder\MyModule.psm1

try
{
    Get-Foo 
    Write-Host "Success"
}
catch
{
    "Error occurred"
} 

运行 Script.ps1:

  • 从 ISE 中或使用 -File 参数

    将输出 "Error occurred" 并停止

  • 从命令行中没有使用 -File 参数

    将输出 "Failed",然后是 "Success"(即未被捕获)


我认为最好将这个放在你原来的问题中。 - Elliptical view

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接