以下是两种在PowerShell脚本错误时中断构建的方法。
使用exit()
终止PowerShell进程
要从脚本返回状态代码,如果为非零,则会显示在错误列表中,请使用以下内容:
exit(45) # or any other non-zero number, for that matter.
这并不完全将错误文本添加到您的错误列表中,但它确实终止了脚本,并在错误列表中加入了一些内容,指示哪个预先或后置构建命令失败了。
使用自定义MSBuild任务来执行PowerShell脚本
我花了一点时间研究如何在MSBuild任务中执行PowerShell脚本的细节。我在我的博客上发布了一个包含示例代码的完整文章。请查看它,因为它包括更多讨论和有关如何处理示例项目的说明。它可能不是一个完整或完美的解决方案,但我用一个非常简单的脚本在我的机器上工作了。
这种方法提供了在报告PowerShell错误时的行和列精度,甚至支持我们在Visual Studio中习惯的双击文件跳转行为。如果它不够用,我相信您可以扩展它以满足您的需求。此外,根据您的Visual Studio版本,您可能需要调整程序集引用版本等细节。
首先,在类库项目中构建自定义MSBuild任务。该库应引用以下用于MSBuild和PowerShell集成的程序集。(请注意,此示例需要PowerShell 2.0。)
- Microsoft.Build.Framework(GAC)
- Microsoft.Build.Utilities.v3.5(GAC)
- System.Management.Automation(来自C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0)
构建一个任务类,并公开一个属性以指定PowerShell脚本的路径,如下所示:
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class PsBuildTask : Task
{
[Required]
public string ScriptPath { get; set; }
public override bool Execute()
{
}
}
在Execute()
方法内,启动PowerShell运行时,执行脚本并收集错误。使用Log
属性记录错误。完成后关闭runspace,并返回true(如果脚本未记录任何错误)。
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(". " + ScriptPath);
pipeline.Invoke();
var errors = pipeline.Error;
foreach (PSObject error in errors.Read(errors.Count))
{
var invocationInfo = ((ErrorRecord)(error.BaseObject)).InvocationInfo;
Log.LogError(
"Script",
string.Empty,
string.Empty,
new FileInfo(ScriptPath).FullName,
invocationInfo.ScriptLineNumber,
invocationInfo.OffsetInLine,
0,
0,
error.ToString());
}
runspace.Close();
return !Log.HasLoggedErrors;
就这样。有了这个程序集,我们可以配置另一个项目来使用MSBuild任务。
例如考虑一个基于C#的类库项目(.csproj文件)。在后期生成事件中集成任务只需要几个步骤。
首先,在.csproj文件的节点内部注册该任务,如下所示:
<UsingTask TaskName="PsBuildTask"
AssemblyFile="..\Noc.PsBuild\bin\Debug\Noc.PsBuild.dll" />
TaskName 应该是任务类的名称,尽管似乎不需要命名空间。 AssemblyFile
是自定义的 MSBuild 任务程序集的绝对路径,或相对于 .csproj 文件的路径。对于位于 GAC 中的程序集,可以使用 AssemblyName
属性代替。
在注册后,任务可以在构建前和构建后事件中使用。请在 .csproj 文件的 <Project>
元素中配置一个构建事件,如下所示:
<Target Name="AfterBuild">
<PsBuildTask ScriptPath=".\script.ps1" />
</Target>
就是这样了。当 Visual Studio 编译项目时,它会加载自定义程序集和任务对象并执行任务。检索和报告管道引发的错误。
![屏幕截图](https://istack.dev59.com/aXlqI.webp)