Call4Cloud | MMP-C | Autopilot | Device Preparation

The Sysnative 64 bit Witch Project

Patch My Pc | install & update thousands of apps

Though it may seem dated, ensuring that 64-bit registry keys are appropriately configured is still crucial when deploying Win32 apps. This step is often required before the application can be successfully installed. To address this, using the sysnative path can be important for accessing the correct system directories on 64-bit systems. In this blog, I will first show you the differences between data stored on a 64-bit device and then explain why deploying or reading a 64-bit registry change in a Win32 app could cause issues.

1. Differences

Before I show you the differences between 64 and 32 bits, we need to know what WoW64 means. You could get confused about the name itself if you don’t know what WoW64 means! For example, 32-bit apps access their files from the SysWoW64 folder…Is this folder the 64-bit folder? Let me explain.

WoW64 (Windows 32-bit on Windows 64-bit) is a subsystem of the Windows operating system that can run 32-bit applications on 64-bit Windows. It is included in all 64-bit versions of Windows.

Program files:

On a 64-bit computer, 64-bit programs store their files in C:\Program Files, 32-bit programs store their files in C:\Program Files (x86).

Windows Folder:

On a 64-bit computer, if a 64 bits program wants to access the system-wide folder it opens the c:\windows\system32 folder, if a 32 bits program wants to access the system-wide folder it will be redirected to C:\Windows\SysWOW64.

Registry:

On a 64-bit computer, if we write a registry key from a 64 bits process it will be stored in the HKEY_LOCAL_MACHINE\SOFTWARE, if we write a registry key from a 32-bits process  it will be  redirected to the HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node

Now we know some differences, I will give you an example:

If you install a 32-bit application on a 64-bit version of Windows and it tries to write to the C:\Program Files folder, WoW64 points it at C:\Program Files (x86). If it wants to access the C:\Windows\System32 folder, WoW64 points it at C:\Windows\SysWOW64.  This process is automatic and is done by a build-in file system redirect

Sysnative:

Sysnative is a virtual folder/alias, that can be used to access the 64-bit System32 folder from a 32-bit application or script.

For example, You could access this 64 bits folder from a 32 bits program like CMD (c:\windows\syswow64\cmd.exe)

Opening the CMD from the syswow64 lets us access the sysnative windows folder

2. Win32 App Registry Change

If you want to deploy an application that requires a license server, you will need to define one before installing the client app itself. 

Creating a custom-made Win32 app would be the best solution. Create a new folder and place your client MSI installation file in it and a PowerShell script to deploy the register setting and start the MSI client installation:


$flexreg = (Get-ItemProperty "HKLM:\Software\FLEXlm License Manager").SW_D_LICENSE_FILE
#Start-Process -Wait -NoNewWindow "msiexec" -ArgumentList "/i","$pwd\DraftSight.msi","/qb","LICENSETYPE=3"
if (!$flexreg) {
    New-Item -Path "HKLM:\Software" -Name "FLEXlm License Manager" -Force
    New-ItemProperty "HKLM:\Software\FLEXlm License Manager" -Name "SW_D_LICENSE_FILE" -Value 'portnr@servername' -PropertyType STRING -Force
} elseif ($flexreg -like '*portnr@servername*') {
Exit
} else  {
    New-ItemProperty "HKLM:\Software\FLEXlm License Manager" -Name "SW_D_LICENSE_FILE" -Value $flexreg';portnr@servername' -PropertyType STRING -Force

But now comes the trouble: When deploying this registry setting, the registry key will be created inside the wow6432node when you use a Win32App.

wow6432 node registry key

The Microsoft Intune Management Extension is responsible for deploying the Win32 app. Considering the differences between 64 and 32 bits, take a look at where the extension is installed.  

programfiles x86

As shown above, it is installed in the c:\program files (x86) folder and what did we learn about this folder? So by default behavior (when you did not change anything), Intune will trigger the Win32 app installation in a 32-bit process context and as I told you earlier, the key will be created in the wow6432node.

Luckily (or maybe not), this 64 vs. 32-bit issue could affect the outcome when you deploy a Win32 app and Device Query a bit. In the blog below I stumbled upon the fact that Intune Pivot (DeviceQuery) also tries to find the registry values in the wrong registry key.

https://call4cloud.nl/2024/02/device-query-dead-of-64-bits

3. 64 vs. 32 and Synative

So, what options do we have to change this weird behavior? Should we ask the Sysnative Witch to fix it?Or will we alter some PowerShell scripts and maybe add some .NET functionality to them? Here are some options we have to deal with the 64/32 bits issue!

Option 1:

This option is probably one of the coolest. Let me tell you why and how it could give you way more functionality.

As mentioned in the above Microsoft link, the RegistryKey class in the Microsoft.Win32 namespace is part of the .NET Framework. It provides a nice way to interact with the Windows Registry and allows us to deal with 64 and 32-bit keys.

-We could use Registry64 when working with 64-bit registry locations.

-We could use Registry32 when interacting with the 32-bit registry view.

The best thing about using a .NET approach is that it works in both ways. We could run it from an X64 PowerShell session or from a x86 based PowerShell session.

creating a powershell script that works with the Registry64 and the Registry32  Registryview to access both 64 a 32 bits registry keys

We could run something like this to determine if we have a 32-bit or 64-bit registry key in our system. The same idea but with a couple of “if” and “else” added to it


# 64-bit view
$key64 = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64)
$subKey64 = $key64.OpenSubKey("SOFTWARE\Microsoft\Office\ClickToRun\Configuration")

# Check if the key is present in the 64-bit view
if ($subKey64 -ne $null) {
    $regkey_value64 = $subKey64.GetValue("Platform")
    Write-Host "Value in 64-bit view: $regkey_value64"
} else {
    Write-Host "Key not found in 64-bit view"
}

# 32-bit view
$key32 = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry32)
$subKey32 = $key32.OpenSubKey("Software\Microsoft\Office\ClickToRun\Configuration")

# Check if the key is present in the 32-bit view
if ($subKey32 -ne $null) {
    $regkey_value32 = $subKey32.GetValue("Platform")
    Write-Host "Value in 32-bit view: $regkey_value32"
} else {
    Write-Host "Key not found in 32-bit view"
}

Besides trying to Get the proper registry value (32 bits or 64 bits) we could also Set the value in both places just by specifying the Registry32 or Registry64 switch.

$key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry32)
$subKey = $key.OpenSubKey("Software\Microsoft\Office\ClickToRun\Configuration", $true)  # Note the $true parameter to make the key writable
$subKey.SetValue("Platform", "NewValue", [Microsoft.Win32.RegistryValueKind]::String)  # Use the correct RegistryValueKind for a string value. Dword Or String
$regkey_value = $subKey.GetValue("Platform")
$regkey_value

$key = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64)
$subKey = $key.OpenSubKey("Software\Microsoft\Office\ClickToRun\Configuration", $true)  # Note the $true parameter to make the key writable
$subKey.SetValue("Platform", "NewValue", [Microsoft.Win32.RegistryValueKind]::String)  # Use the correct RegistryValueKind for a string value. Dword Or String
$regkey_value = $subKey.GetValue("Platform")
$regkey_value

As shown above, remember to add the $true while opening the subkey; otherwise, the registry key is NOT writable!

Option 2:

When we are deploying a Win32 App and want to add the registry value, we could, Instead of specifying the regular install command as shown below

We could specify the “CMD sysnative path”. The sysnative path is used to access the 64-bit system directory (System32) from a 32-bit process (In this example The 32-bit Intune Management Extension)

calling sysnative with the install command

You could also use the sysnative path when you need to install Printer Drivers using a Win32 app.

Deploy Intune Printer Drivers | PnPutil | Printbrm | PrnDrvr (call4cloud.nl)

Option 3:

We have some options left. This option is a little different and uses a different approach. I found no documentation proving this is a proper solution, but who cares? It works…

It would be best if you created a Powershell script, in this script, you will need to define an additional PowerShell script, which needs to be transferred to the disk and you will need to configure a system task to run the additional PowerShell script. The scheduled task would run the script in the 64-bit context.

Another option would be to create the additional PowerShell script itself and make sure you attach it to the intunewin file.

$content = @'
$flexreg = (Get-ItemProperty "HKLM:\Software\FLEXlm License Manager").SW_D_LICENSE_FILE
#Start-Process -Wait -NoNewWindow "msiexec" -ArgumentList "/i","$pwd\DraftSight.msi","/qb","LICENSETYPE=3"
if (!$flexreg) {
    New-Item -Path "HKLM:\Software" -Name "FLEXlm License Manager" -Force
    New-ItemProperty "HKLM:\Software\FLEXlm License Manager" -Name "SW_D_LICENSE_FILE" -Value 'portnr@servername' -PropertyType STRING -Force
} elseif ($flexreg -like '*portnr@servername*') {
Exit
} else  {
    New-ItemProperty "HKLM:\Software\FLEXlm License Manager" -Name "SW_D_LICENSE_FILE" -Value $flexreg';portnr@servername' -PropertyType STRING -Force
}'@

Out-File -FilePath $(Join-Path $env:ProgramData CustomScripts\test.ps1) -Encoding unicode -Force -InputObject $content -Confirm:$false

# register script as scheduled task
$Time = New-ScheduledTaskTrigger -AtLogOn
$User = "SYSTEM"
$Action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ex bypass -file `"C:\ProgramData\CustomScripts\test.ps1`" -Verb RunAs"
Register-ScheduledTask -TaskName "test" -Trigger $Time -User $User -Action $Action -Force
Start-ScheduledTask -TaskName "test"

Option 4:

This option may be one of the most commonly used ones.  When you add this script to the top of your own PowerShell script, the script host will rerun the PowerShell script, but this time in the 64 bits context

If ($ENV:PROCESSOR_ARCHITEW6432 -eq "AMD64") {
    Try {
        &"$ENV:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe" -File $PSCOMMANDPATH
    }
    Catch {
        Throw "Failed to start $PSCOMMANDPATH"
    }
    Exit
}

Some explanation about the script: 
This PowerShell script checks if the environment variable $ENV:PROCESSOR_ARCHITEW6432 equals "AMD64", which indicates that a 32-bit process is running on a 64-bit Windows system. If true, it attempts to restart the script using the 64-bit version of PowerShell (SysNative\WindowsPowershell\v1.0\PowerShell.exe) by executing the current script ($PSCOMMANDPATH) in a 64-bit context. If the attempt fails, it throws an error. Finally, the script exits to prevent further execution in the 32-bit process.This approach ensures the script runs in a 64-bit environment if required.

As shown below, when we use this option, we will notice that it now deploys the registry key to the proper path, NOT the wow6432node registry key!

Conclusion:

It is crucial to know the differences between 64 and 32 bits and how they can work together, in my opinion. Hopefully, this blog showed you how to deal with some of the challenges you could encounter when deploying a Win32app, and you need to Get or Set a 64-bit registry key!

4 thoughts on “The Sysnative 64 bit Witch Project

  1. Hi,

    I used the second option and i am getting the 81036502 error during device ESP. (windows OS ver. 21H2)

    It is telling “Installation exceeded the time limit (100min)” …but it happens around 3 minits after enrollemnt starts.

    Identified the app with get-autopilotdiagnostics, which is an app created with IntuneWinApp and executing a powershell script with an exe.

    Script:

    – i just run the sysinternal autologon.exe to prepare a autologon
    – somehow that doesn work directly and a registry needs to be modified afterwards. Because of this i used the trick from call4cloud, to execute the registry part through a scheduled task, because of x64 environment needed.

    #To run the $content part in x64 environment, it needs to be executed by a scheduled task source: https://call4cloud.nl/2021/05/the-sysnative-witch-project/

    Start-Process .\Autologon64.exe -ArgumentList “localuser”, “$($env:computername)”, “topsecret”, “/accepteula” -Wait

    $scriptname = “autologon.ps1”
    $transcript = “transcript.log”
    $basedir = “intune\autologon”
    $content = @’
    Set-ItemProperty -Path “HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon” -Name “DefaultUserName” -Value “$($env:computername)\localuser” -type String
    ‘@

    $path = Join-Path $env:ProgramData $basedir

    If (-Not (Test-Path $path)){
    New-Item -Path $path -ItemType Directory -Force -Confirm:$false
    }

    Start-Transcript “$(Join-Path $path $transcript)”

    Out-File -FilePath $(Join-Path $path $scriptname) -Encoding unicode -Force -InputObject $content -Confirm:$false

    # register script as scheduled task
    $Time = New-ScheduledTaskTrigger -AtLogOn
    $User = “SYSTEM”
    $Action = New-ScheduledTaskAction -Execute “powershell.exe” -Argument “-ex bypass -file `”$(Join-Path $path $scriptname)`” -Verb RunAs”
    Register-ScheduledTask -TaskName “Autologon-Fix” -Trigger $Time -User $User -Action $Action -Force
    Start-ScheduledTask -TaskName “Autologon-Fix”
    Start-Sleep -Seconds 10
    Unregister-ScheduledTask -TaskName “Autologon-Fix” -Confirm:$false

    Stop-Transcript

    Result during ESP:

    – The script is working. I checked the registry key, and it was modified.
    – but sadly the the script returns error code 4, identified in the registry:

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Autopilot\EnrollmentStatusTracking\Device\Setup\Apps\Tracking\Sidecar\Win32App_GUID-from-my-app

    – also the transcript during the executing of the app is not showing any error.
    – When i execute the script on this device during manually in the ESP state, it is working, without an error.

    Can someone give me a hint, what i can check, or where i can see, the complete process of the app installation, to see what exactly was going wrong?

    Thanks

    Dave

  2. Hi
    Great post! I am now testing which solution can work for us.

    I believe, however, that Option 4 will not work like this. It seems, the If condition is only invoking a 64-bit powershell if it is already running in 64-bit. The “-eq” should be “-ne” instead.

    Instead of: If ($ENV:PROCESSOR_ARCHITEW6432 -eq “AMD64”)
    Do: If ($ENV:PROCESSOR_ARCHITEW6432 -ne “AMD64”)

    Regards

  3. Hi Rudy,

    I have been testing option 4 and I realised two things:
    * $ENV:PROCESSOR_ARCHITEW6432 should be $ENV:PROCESSOR_ARCHITECTURE – at least on Windows 11 the former is not recognised, but the latter is.
    * The line &”$ENV:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe” -File $PSCOMMANDPATH doesn’t work, but invokes an error everytime, at least on Windows 11.

    That second point I tested like this – and the log file lists “NIET GELUKT!!!”.

    $LogFile = “C:\temp\Test123.log”

    If ($ENV:PROCESSOR_ARCHITECTURE -eq “AMD64″) {
    Try {
    &”$ENV:WINDIR\SysNative\WindowsPowershell\v1.0\PowerShell.exe” -File $PSCOMMANDPATH
    }
    Catch {
    Add-Content $LogFile “$(Get-Date -Format `”[dd/MMM/yy, HH:mm:ss]`”) – NIET GELUKT!!!”
    Throw “Failed to start $PSCOMMANDPATH”
    }
    Exit
    }

    Have there been some changes in the way this needs to be run? Do you have any advice how I can make this work?

    Thanks a lot in advance!

Leave a Reply

Your email address will not be published. Required fields are marked *

19  −  17  =  

Proudly powered by WordPress | Theme: Wanderz Blog by Crimson Themes.