The Sysnative Witch Project

Last Updated on February 11, 2024 by rudyooms

An old one, but still necessary when you are deploying a Win32 app and you have to make sure some 64 bits registry keys are configured before you are going to install the application.

I was inspired to write this blog after a question about this topic on the Technet community website.

In this blog, I will first show you the differences where data is stored on a 64 bits device and secondly, I will show you why deploying a 64 bits registry change in a *Win32 app could give you some issues.

(*Win32app –> Say it out Loud!… Windows 32 App)

I will divide this blog into multiple parts

  1. Differences
  2. Win32App registry Change
  3. 64 vs 32 and Synative

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 we don’t know what the WoW64 means! As an example, 32-bit apps are accessing their files from the SysWoW64 folder…Is this folder, the 64 bits folder? Let me explain.

WoW64 (Windows 32-bit on Windows 64-bit) is a subsystem of the Windows operating system capable of running 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)

2. Win32 App Registry Change

As I told you at the beginning of this blog, I was inspired to write this blog after a question on Technet. If you want to deploy an application that requires a license server, you will need to define a license server before you can proceed to install 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 register setting, the registry key is going to be created inside the wow6432node when you use a Win32App.

The Microsoft Intune Management Extension is responsible for the deployment of the Win32 app but keeping in mind the differences between 64 and 32 bits, take a look at where the Microsoft Intune Management extension is installed.  

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 not only be affecting the outcome when you deploy a Win32 app, but it also affects 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..

3. 64 vs 32 and Synative

So what options do we have to change this weird behavior? Are we going to ask the Sysnative Witch to fix it?

Or are we going to alter some PowerShell scripts and maybe add some .NET functionality to them? Well here are some options we have to deal with the 64/32 bits issue!

Option 1:

In my opinion, this option is maybe one of the coolest. Let me tell you why I think it’s cool and how it could give you way more functionality.

RegistryView Enum (Microsoft.Win32) | Microsoft Learn

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 also gives us the option 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.

To determine if we have a 32-bit or 64-bit registry key in our system, we could run something like this. 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, don’t forget 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)

You could also use the sysnative path when you need to install Printer Drivers with the use of a Win32app

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 could not find any documentation if this is a proper solution, but who cares? it works…

You need to create 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 is maybe 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
}

As shown below, when we are using this option, we will notice that it will now deploy the registry key to the proper path and NOT in the wow6432node registry key!

Conclusion:

Knowing the differences between 64 and 32 bits and how they can work together is very important. In my opinion. Hopefully, this blog showed you how you could deal with some of the challenges you could encounter when deploying a Win32 Bits app and you need to Get or Set a 64 bits registry key!

One thought on “The Sysnative 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

Leave a Reply

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

  +  73  =  81