6

I have a .NET Framework 4.5.2 WebAPI2 project. While building the project in Visual Studio, I want a powershell script I wrote to run before each and every build. If the powershell script exits with any non-zero code, I want the build to fail and the error message from the powershell script visible in the Visual Studio output.

This is how I've modified my csproj file so far:

<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>

For simplicity's sake, my script is the following:

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

However, when I go to build the project, I now see my powershell script open in notepad and the build stops until I close notepad. Once closed, I'm getting an error and I am not finding any way of resolving the error. Any assistance would be much appreciated.

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 
mckennawebdev
  • 547
  • 1
  • 5
  • 17
  • 1
    For all those people who are facing the same issue - $(PowerShellExe) and $(ScriptLocation) are being parsed together with the line endings (it is not obvious but gets easily from the console output formatting). Had absolutely the same issue and it has gone when I've rewrote variable definitions as one-liners. – n0ne May 08 '20 at 09:57

2 Answers2

18

I was able to get everything working by changing the following. This builds off of Apoorva's answer:

<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>

For me, the inclusion of PowerShellExe and ScriptLocation variables were both causing an error. Removing these lines and stripping the Exec line down fixed the issue. The inclusion of 'ContinueOnError="False"' and 'LogStandardErrorAsError="True"' ensured the build process would halt if a non-zero exit code was thrown by the powershell script.

John
  • 29,788
  • 18
  • 89
  • 130
mckennawebdev
  • 547
  • 1
  • 5
  • 17
  • 2
    This also worked for me `powershell -NonInteractive -Executionpolicy Unrestricted .\MyScript.ps1` – maxc137 Dec 16 '20 at 11:56
3

I edited the Target Name="BeforeBuild" as below instead of creating new Target. So before start of the build the powershell script is executed and build is passed or failed accordingly

<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>

(Edited to add 's' to windows)

ximon
  • 197
  • 3
  • 11
Apoorva Raju
  • 300
  • 1
  • 14
  • 1
    I tried this as an AfterPublish task and it opens the script in notepad. Which is weird because it's almost exactly the same as the other one. – Chris Jun 21 '19 at 17:12
  • 3
    @Chris I'm sorry for necroposting, but you're getting such a weird behavior because $(PowerShellExe) and $(ScriptLocation) are being parsed along with the line endings. Just have faced the same issue and when defining properties using one-liners everything works like a charm. M$ examples are misleading in this case. – n0ne May 08 '20 at 09:54