Reputation: 50
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
Upvotes: 2
Views: 597
Reputation: 437428
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
Note that this virtual SysNative
directory is visible to 32-bit processes only, so in order to make your project file bitness-agnostic, i.e. to allow it to target the 64-bit SYSTEM32 directory irrespective of whether it is being built from a 32-bit or a 64-bit process, define a custom SysDir64
property conditionally, whose value you can later reference as $(SysDir64)
, e.g. $(SysDir64)\WindowsPowerShell\v1.0\powershell.exe
:
<!-- Place inside a <PropertyGroup> element -->
<SysDir64>$(windir)\System32</SysDir64>
<SysDir64 Condition=" ! $([System.Environment]::Is64BitProcess) ">$(windir)\SysNative</SysDir64>
The value is first defined unconditionally as $(windir)\System32
, and conditionally overwritten with $(windir)\SysNative
if the current process is found to be a 32-bit one.
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.[2]
The equivalent PowerShell solutions to the above (i.e., expressions you can use in a PowerShell script or session) are:
Targeting the 64-bit SYSTEM32 dir. from a 32-bit session:
"$env:windir\SysNative"
Bitness-agnostic solution:
"$env:windir\$(('SysNative', 'System32')[[Environment]::Is64BitProcess])"
[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] 32-bit processes see this directory too, which for them is the same as $(WINDIR)\System32
.
Upvotes: 3