在MSBuild期间运行PowerShell脚本

6
我有一个.NET Framework 4.5.2 WebAPI2项目。在Visual Studio中构建该项目时,我希望运行我编写的PowerShell脚本以便在每次构建之前运行。如果PowerShell脚本以任何非零代码退出,则希望构建失败并将PowerShell脚本的错误消息显示在Visual Studio输出中。
以下是我目前已修改的csproj文件内容:
<Project ToolsVersion="12.0" DefaultTargets="MyCustomTarget;Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<Target Name="MyCustomTarget">
  <PropertyGroup>
    <PowerShellExe Condition=" '$(PowerShellExe)'=='' "> 
      %WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe
    </PowerShellExe>
    <ScriptLocation Condition=" '$(ScriptLocation)'=='' ">
      C:\Code\MyScript.ps1
    </ScriptLocation>
  </PropertyGroup>
  <Exec Command="$(PowerShellExe) -NonInteractive -executionpolicy Unrestricted -command &quot;&amp; { $(ScriptLocation) } &quot;" />
</Target>

出于简化的考虑,我的脚本如下:

if(((get-date -Format "mm") % 2) -eq 0){ exit 0 } else { write-error "The minute is not equally divisible by 2.";exit 1 }

然而,当我开始构建项目时,我现在看到我的PowerShell脚本在记事本中打开,并且在关闭记事本之前,构建会停止。一旦关闭,我会收到一个错误,但我找不到任何解决错误的方法。非常感谢您的帮助。
The command " 
    %WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe
   -NonInteractive -executionpolicy Unrestricted -command "& { 
    C:\Code\MyScript.ps1
   } "" exited with code 9009.  MyWebApi2Project    C:\Code\MySolution\MyWebApi2Project\MyWebApi2Project.csproj 269 

1
对于所有遇到相同问题的人 - $(PowerShellExe) 和 $(ScriptLocation) 与行尾一起解析(这不是显而易见的,但很容易从控制台输出格式中得到)。我也遇到了完全相同的问题,当我将变量定义重写为单行时,问题就解决了。 - n0ne
2个回答

18

通过更改以下内容,我成功使一切都正常工作。这是基于Apoorva的答案进行改进的:

<Target Name="BeforeBuild">
  <TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" /><!-- existing line, not part of answer -->
  <Exec Command="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NonInteractive -executionpolicy Unrestricted -command &quot;&amp; { .\MyScript.ps1 } &quot;" LogStandardErrorAsError="True" ContinueOnError="False" WorkingDirectory="$(MSBuildProjectDirectory)" />
</Target>

对我来说,PowerShellExe和ScriptLocation变量的包含都引起了错误。 删除这些行并简化Exec行可解决问题。 包含“ContinueOnError =&quot; False&quot;”和“LogStandardErrorAsError =&quot; True&quot;”确保如果powershell脚本抛出非零退出代码,则构建过程将停止。


2
这对我也有效:powershell -NonInteractive -Executionpolicy Unrestricted .\MyScript.ps1 - maxc137

3

我将Target Name="BeforeBuild"修改为下面的形式,而不是创建新的 Target。因此,在构建开始之前,会执行PowerShell脚本,构建会根据其成功或失败。

<Target Name="BeforeBuild">
   <PropertyGroup>
    <PowerShellExe Condition=" '$(PowerShellExe)'=='' "> 
     C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    </PowerShellExe>
    <ScriptLocation Condition=" '$(ScriptLocation)'=='' ">
      C:\Code\MyScript.ps1
    </ScriptLocation>
  </PropertyGroup>
  <Exec Command="$(PowerShellExe) -NonInteractive -executionpolicy Unrestricted -command &quot;&amp; { $(ScriptLocation) } &quot;" />
  </Target>

(增加“s”到Windows)


1
我尝试将其作为AfterPublish任务,但它在记事本中打开脚本。这很奇怪,因为它几乎与另一个脚本完全相同。 - Chris
3
@Chris,很抱歉我在回复过期的帖子,但你遇到奇怪的行为是因为$(PowerShellExe)和$(ScriptLocation)与行结尾一起被解析了。我也遇到过同样的问题,当使用单行定义属性时,一切都像魔术一样运作。微软的示例在这种情况下会导致误导。 - n0ne

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