MVP
02 Nov 2009

In 64-bits versions of Windows Operating Systems, a subsystem called Windows on Windows 64 (WoW64) enables you to run 32 bits applications. Even to date, many Windows applications only exist in a 32 bits version – not the least of which is Microsoft’s own Visual Studio(!)

The purpose of WoW64 is to hide many of the structural differences between 32 bits and 64 bits Windows for 32 bits applications. This is a good thing. Most of the time, anyway…

However, when your PowerShell script runs in a 32 bits process on a 64 bits OS, and you want to integrate with 64-bits applications (e.g. you want to integrate SharePoint or SQL Server within Visual Studio), WoW64 can get in the way.

E.g., WoW64 hides the 64 bit registry and changes the environment variables for processor architecture and for the program files folder – in short, WoW64 hides that you are running on a 64 bits OS.

To detect a 64 bits OS from PowerShell on Vista, W2008 and later Windows versions, we could use WMI:

(Get-WMIObject win32_operatingsystem).OSArchitecture

However, this is not supported on W2003.

Fortunately, Microsoft provided an alternative, which is supported on all Windows versions that have Wow64: the IsWow64Process function. Since this is an unmanaged API call to Kernel32.dll, we need to do some extra work to call this in PowerShell.

We can write a simple managed C# wrapper around IsWow64Process:

using System;
using System.Runtime.InteropServices;

public class Kernel32
{
    [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool lpSystemInfo);

    // This overload returns True if the current process is running on Wow, False otherwise
    public bool CurrentProcessIsWow64()
    {
        bool retVal;
        if (!(IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle, out retVal))) { throw new Exception("IsWow64Process() failed"); }
        return retVal;
    }
}

When we use the PowerShell InvokeCSharp function, we can put this C# inline in our PowerShell script:

Function global:CurrentProcessIsWOW64
{
    # Use some inline C# code to call the unmanaged IsWow64Process() function in Kernel32.dll and return its result:
    $code = @"
        using System;
        using System.Runtime.InteropServices;

        public class Kernel32
        {
            [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool lpSystemInfo);

            // This overload returns True if the current process is running on Wow, False otherwise
            public bool CurrentProcessIsWow64()
            {
                bool retVal;
                if (!(IsWow64Process(System.Diagnostics.Process.GetCurrentProcess().Handle, out retVal))) { throw new Exception("IsWow64Process() failed"); }
                return retVal;
            }
        }
"@
    InvokeCSharp -code $code -class 'Kernel32' -method 'CurrentProcessIsWow64'
}

Function global:ProcessArchitecture
{
    switch ([System.IntPtr]::Size)
    {
        4 { 32 }
        8 { 64 }
        default { throw "Unknown Process Architecture: $([System.IntPtr]::Size * 8) bits" }
    }
}

Function global:OSArchitecture
{
    if (((ProcessArchitecture) -eq 32) -and (CurrentProcessIsWOW64)) { 64 } else { ProcessArchitecture }
    # Note that on Vista, W2008 and later Windows versions, we could use (Get-WMIObject win32_operatingsystem).OSArchitecture.
    # We don't use that because we also support W2003
}

So there you have it, some simple PowerShell functions to detect the process architecture and the OS architecture, regardless of whether or not you are running under WoW64.

P.S. I also added these functions to the global functions in the Macaw Solutions Factory, so they can be leveraged by anyone who wants to extend the Factory.

About the Author
Vincent Hoogendoorn is a Microsoft MVP Developer Technologies with over 20 years of experience as hands-on .NET innovator / architect / engineer. He is currently focused on full stack C#: Microsoft Orleans backends and browser/native frontends with C# Markup 2 for Windows App SDK, Uno Platform and Xamarin/Maui. Xamarin cross-platform mobile veteran, passionate about developer productivity. Principal Software Engineer at InnoWvate.NET, Technical Director at Applicita.
  1. JD

    How can you do this against a remote machine? We’re trying to write a script to deploy a client to servers remotely. First we have to determine if the target server is 2003 or 2008 server. Then we have to determine if it is 32bit or 64bit. Any help is appreciated.

  2. Vincent

    To do this against a remote machine, you could use the powershell remoting functionality that comes built-in since V2.

    In short, you need to performs these steps:

    1. 1) Enable powershell remoting om the destination machine (with Enable-PSRemoting)
    2. 2) From the local machine, execute the OSArchitecture function on the remote machine via powershell remoting
    3. 3) You will receive the results from the remote OSArchitecture invocation back your local machine.

    See about_Remote for more info on PowerShell Remoting. It’s actually quite simple to use.

    I’m experimenting with this myself to deploy setup packages on remote machines. So far it’s looking good.

Leave a Reply


*

captcha *