2011-04-28 92 views
12

我正在从MSBuild调用PowerShell脚本。 MSBuild能够捕获返回的输出,但认为该项目已成功构建。PowerShell退出代码 - 从MSBuild调用

问题是来自PowerShell的退出代码没有传递给MSBuild中的命令。有人曾经尝试过,并能够抛出退出代码到MSBuild?

testmsbuild.proj

<?xml version="1.0" encoding="utf-8"?> 
<Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <PropertyGroup> 
    <ScriptLocation>c:\scripts\test.ps1</ScriptLocation> 
    </PropertyGroup> 

    <Target Name="AfterDropBuild" > 
     <Exec Command="powershell.exe -NoProfile -Noninteractive -command &quot;&amp; { $(ScriptLocation)%3Bexit $LASTEXITCODE }&quot; " > 
     <Output TaskParameter="ExitCode" PropertyName="ErrorCode"/> 
     </Exec> 
    </Target>  

</Project> 

test.ps1(当然这是要出错误)

function CallFromMSBuild { 

    Invoke-command {Powershell.exe C:\a.ps1} -computername $computers 
} 

当MSBuild项目被触发时,它应该抓住这个问题,并在构建宜已经失败(认为建立成功)

当我从MSBuild打电话

C:\Scripts>msbuild testmsbuild.proj /t:AfterDropBuild 
Microsoft (R) Build Engine Version 4.0.30319.1 
[Microsoft .NET Framework, Version 4.0.30319.225] 
Copyright (C) Microsoft Corporation 2007. All rights reserved. 

Build started 4/28/2011 2:46:29 PM. 
Project "C:\scripts\testmsbuild.proj" on node 1 (AfterDropBuild target(s)). 
AfterDropBuild: 
    powershell.exe -NoProfile -Noninteractive -command "& { c:\scripts\test.ps1;e 
    xit $LASTEXITCODE }" 
    Invoke-Command : Cannot validate argument on parameter 'ComputerName'. The argu 
    ment is null or empty. Supply an argument that is not null or empty and then tr 
    y the command again. 
    At C:\install\test.ps1:3 char:58 
    + Invoke-command {Powershell.exe C:\a.ps1} -computername <<<< $computers 
     + CategoryInfo   : InvalidData: (:) [Invoke-Command], ParameterBind 
    ingValidationException 
     + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.Power 
    Shell.Commands.InvokeCommandCommand 

Done Building Project "C:\scripts\testmsbuild.proj" (AfterDropBuild target(s)). 


Build succeeded. 
    0 Warning(s) 
    0 Error(s) 

Time Elapsed 00:00:01.04 
+0

相关:http://stackoverflow.com/questions/78069/any-good-powershell-msbuild-tasks – 2012-12-13 21:46:14

回答

4

添加exit $lastexitcode到test.ps1

评论后:

在test.ps1试试这个:

trap {Write-Host -foreground red $_.Exception.Message; exit 1; continue} Invoke-command {Powershell.exe C:\a.ps1} -computername $computers 

基本上,我不认为是的MSBuild在这里有毛病。

我试过你的错误Invoke-Command并且$lastexitcode被设置为0,即使Invoke-Command失败!你可以通过做echo %errorlevel%并看到你得到1来测试它是否有效。从这个cmd本身可以测试。

+0

不幸运!还是一样。从PowerShell窗口直接运行退出代码是255 – Sanjeev 2011-04-28 20:35:52

+0

我已经编辑了我的回复 – manojlds 2011-04-28 20:46:37

+0

感谢您的更新。陷阱{}是诀窍!现在MSbuild说“构建失败”。问题在于它没有显示$ ._ Exception.Message思想。它显示的是'代码'C:\ scripts \ testmsbuild.proj(12,3):错误MSB3073:使用代码1'代码'退出命令“powershell.exe c:\ scripts \ test.ps1”。一半的战斗结束了,虽然:) – Sanjeev 2011-04-28 21:07:18

15

这个问题是一个主要搜索引擎的最佳答案。来自James Kovacs的best answer is this(psake的名声 - 即他在PowerShell和MSBuild集成上有点类似FizzBinned)。

综上所述,在PS1文件:

  1. 在你的脚本的顶部贴$ErrorActionPreference='Stop'所以它不是默认的,这是SilentlyContinue(在接受答案的trap位有同样的效果,但更为间接和混乱)
  2. 棍子在他function exec {...(或使用psake本身)外部的EXE的一个exec { x.exe }
  3. 包装调用不需要做任何expli CIT exit ...东西

默认的错误处理传播异常起来为1的ERRORLEVELpowershell.exe myscript.ps1,即在一个MSBuild <Exec你不需要做任何弄虚作假再告诉它忽略退出代码等。(除非你想做些什么具体的退出代码的条件,要在其中做IgnoreExitCode="true"并与<Output元素捕捉到它)

了解的最后一个重要的事情是,在PowerShell中,有一个$?这是最后一个表达式的结果(与ErrorAction='Stop'模式无关)随着每个事情而变化,而$ LastExitCode是系统中触发的最后一个.exe的'DOS'退出代码。 Details here - be sure to read the comments

+0

甜!感谢您的信息。我使用博客链接中提到的“Exec function”代码来捕获来自另一个PS脚本(remoteinvoke.ps1)的错误,该脚本从myscript.ps1中调用远程计算机。陷阱在这些情况下不起作用。我会写一篇关于我的发现的详细文章(并在此链接),以及exec如何帮助我解决问题:D – Sanjeev 2011-05-02 16:40:33

+0

@Sanjeev:很高兴听到它。当然,在大多数情况下,一个“陷阱”(错误goto':P)比'错误恢复下一个'要好得多。但它肯定会很好,得到实际相关的位的另一个总结,而不是堆积在许多小事情,以迫使它工作... – 2011-05-03 23:24:29

+0

@RubenBartelink关于http://geekswithblogs.net/dwdii /archive/2011/05/27/part-2-automating-a-visual-studio-build-with-powershell.aspx? – Kiquenet 2013-05-03 07:16:47