Run Win32 Apps from Intune in 64 Bit PowerShell

As you may know (or have not realised so far) is that all your Win32 apps in Intune are being run in the 32 Bit environment. Usually this is not an issue as most executables elevate themselves into the 64 Bit environment if required. But there are some edge cases, where this is relevant, like creating some entries in the registry.

But let’s start from the beginning: We usually pack more complex Applications into a Win32 App / Intune-Win File. There we pack the executable and usually two PowerShell Files for installation and uninstallation and those a triggered as follows from Intune: powershell.exe -ExecutionPolicy Bypass -WindowStyle hidden -File install.ps1

As mentioned above, this script is being run in a 32 Bit environment and if you need to create registry items in the HKLM:\SOFTWARE\ node, you will notice, that the items you just added are ending up in the HKLM:\SOFTWARE\WOW6432Node. Not what you wanted and expected.

We can check that behaviour by adding the following lines of code to our PowerShell script and make sure the output is being saved by Start-Transcript or another solution for logging.

PowerShell
Write-Host "checking environment"
Write-Host "    PowerShell Version: $($PSVersionTable.PSVersion)"
Write-Host "    is 64bit os:      $([Environment]::Is64BitOperatingSystem)"
Write-Host "    is 64bit process: $([Environment]::Is64BitProcess)"

On a 64 Bit system, this will then return the following output:

PowerShell
checking environment
    PowerShell Version: 5.1.26100.2161
    is 64bit os:      True
    is 64bit process: False

So, what can we do about that? We can simply trigger the 64 Bit PowerShell to run our commands. And if you were wondering, the PowerShell 5 executable is hiding under the following path if you’re in a 32 Bit environment.

PowerShell
"$($env:SystemRoot)\sysnative\WindowsPowerShell\v1.0\powershell.exe"

There are multiple options to solve that issue, and we’re going to look into the following three:

  • Pass the cmlets to 64 Bit PowerShell
    We can call the 64Bit PowerShell executable and pass the required commands via the Command parameter.
  • Use a dedicated 64 Bit script
    We can use a dedicated Script containing the code to be run in 64 Bit PowerShell
  • Run the whole file itself
    Or we can call the Install-Script itself in 64 Bit PowerShell

Pass the cmlets to 64 Bit PowerShell

This is the simplest variant, but it gets quite messy if you need to run multiple or complex commands. But we just call the 64 Bit PowerShell executable with the Command Parameter.

PowerShell
C:\Windows\sysnative\WindowsPowerShell\v1.0\powershell.exe -Command { "is 64bit process: $([Environment]::Is64BitProcess)" }

Use a dedicated 64 Bit script

Another option is to create a dedicated script containing all the commands that need to be run in 64 Bit PowerShell. And we’re going to add that script to the Intunewin File we’re packing.

From the initial Install-Script, we can then run the 64 Bit PowerShell Executable with the File Parameter. In the following code, we’re assuming that the dedicated script is in the same folder as the Install-Script.

PowerShell
$PowershellX64Executable = "$($env:SystemRoot)\sysnative\WindowsPowerShell\v1.0\powershell.exe"
$Arguments = "-File `"$($PSScriptRoot)\MyCustomScript.ps1`""

$Process = Start-Process `
        -FilePath $PowershellX64Executable `
        -ArgumentList $Arguments `
        -PassThru `
        -Wait

Run the whole file itself

The last option is to call the Install-Script from the Install-Script. But, with some extra steps.

First we check, if we’re on a 64 Bit OS and if the Process is running in the 32 Bit environment. If this is true, we’re calling our script in the 64 Bit Environment. And due to above check, we run the following if statement only once. Make sure to exit the Script after launching the Process.

Of course, we need to be careful about recursion (to understand recursion, you first have to understand recursion. You may Google it as well.)

PowerShell
if ([Environment]::Is64BitOperatingSystem -eq $true -and [Environment]::Is64BitProcess -eq $false) {
    $PowershellX64Executable = "$($env:SystemRoot)\sysnative\WindowsPowerShell\v1.0\powershell.exe"
    $Arguments = "-File `"$($MyInvocation.MyCommand.Definition)`""

    Write-Host "starting process in 64bit powershell"
    Write-Host "    using executable '$($PowershellX64Executable)'"
    Write-Host "    using arguments '$($Arguments)'"
    Stop-Transcript

    $Process = Start-Process `
        -FilePath $PowershellX64Executable `
        -ArgumentList $Arguments `
        -PassThru `
        -Wait

    exit $Process.ExitCode
}

With this option we only require to have one script, if you call the Script in 64 Bit PowerShell already it will run the required commands as expected and if not, it will spawn a new PowerShell Session in 64 Bit. Make sure to add your commands after the if-Statement.

A whole script could look as follows:

PowerShell
Write-Host "checking environment"
Write-Host "    PowerShell Version: $($PSVersionTable.PSVersion)"
Write-Host "    is 64bit os:      $([Environment]::Is64BitOperatingSystem)"
Write-Host "    is 64bit process: $([Environment]::Is64BitProcess)"

if ([Environment]::Is64BitOperatingSystem -eq $true -and [Environment]::Is64BitProcess -eq $false) {
    $PowershellX64Executable = "$($env:SystemRoot)\sysnative\WindowsPowerShell\v1.0\powershell.exe"
    $Arguments = "-File `"$($MyInvocation.MyCommand.Definition)`""

    Write-Host "starting process in 64bit powershell"
    Write-Host "    using executable '$($PowershellX64Executable)'"
    Write-Host "    using arguments '$($Arguments)'"
    Stop-Transcript

    $Process = Start-Process `
        -FilePath $PowershellX64Executable `
        -ArgumentList $Arguments `
        -PassThru `
        -Wait

    exit $Process.ExitCode
}

# your commands in 64 bit PowerShell
Start-Process "msiexec.exe" `
    -ArgumentList '/i "YourApp.msi" /qn /norestart' `
    -Wait

$registryPath = "HKLM:\SOFTWARE\YourApp\YourNode"
if ((Test-Path -Path $registryPath ) -eq $false) {
    New-Item -Path $registryPath 
}

New-ItemProperty `
    -Path $registryPath `
    -Name "YourItem" `
    -Value "YourValue" `
    -PropertyType "String"
    
exit 0

Kommentare

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert