powershellmsbuildcsproj

Execute powershell in x64 from MSBuild


I would like to run an after build script with Powershell. This script needs to be run in 64bits. However, whenever I run msbuild with my .csproj file the script always runs in 32 bits. If I run the same script from the same powershell session where I started the msbuild, the script runs in x64 just fine.

My command:

msbuild .\src\Project.csproj /t:Build /p:Platform='x64' /p:Configuration='Debug'

I thought I could force to use the 64bits version like suggested on this post My target in my .csproj file:

<PropertyGroup> 
     <PowerShellExe>$(WINDIR)\system32\WindowsPowerShell\v1.0\powershell.exe</PowerShellExe>
</PropertyGroup>
<Target Name="AfterBuild">
   <Exec Command="$(PowerShellExe) .\Run-AfterBuild.ps1" WorkingDirectory="$(OutputPath)"/>
</Target>

The beginning of the after build script:

Write-Host $"Is a 64bitsProcess $([System.Environment]::Is64BitProcess)"

When run from msbuild the output is false, and from the session session that launched msbuild but running the script directly outputs true.

MS build version: 16.3


Solution

  • 64-bit vs. 32-bit processes see separate, bitness-specific directories as C:\Windows\System32.

    Therefore, when launched from a 32-bit process, $(WINDIR)\System32\WindowsPowerShell\v1.0\powershell.exe refers to the 32-bit version of PowerShell.

    However, there is a virtual[1] SysNative directory that allows 32-bit processes to access the 64-bit System32 directory:[2]

    $(WINDIR)\SysNative\WindowsPowerShell\v1.0\powershell.exe
    

    For the sake of completeness: For the inverse, i.e. to allow 64-bit processes to access the 32-bit System32 directory, use the (non-virtual) SysWOW64 directory.[3]


    [1] When enumerating the child directories of C:\Windows\System32, no SysNative entry shows up. However, using it as part of a path, e.g. C:\Windows\SysNative\WindowsPowerShell\v1.0\powershell.exe, transparently targets the otherwise-invisible-to-32-bit-processes 64-bit System32 directory.

    [2] Note that this virtual directory is visible to 32-bit processes only. From inside a PowerShell session, a bitness-agnostic way to refer to the 64-bit SYSTEM32 directory would be:
    "$env:windir\" + ('SysNative', 'System32')[[Environment]::Is64BitProcess]

    [3] 32-bit processes see this directory too, which for them is the same as $(WINDIR)\System32.