3

I'm running on Windows Server 2012 R2 standard machine with 32Bit python.
I'm trying to run a powershell script for a 64Bit system which check if a key exists in the registry:

$path = "Registry::HKLM\Software\<folder>"
if (!(Test-Path $path)) 
   {
       write "$path does not exist!"
   }

When running through powershell, script works perfect.
When I'm running it from python, it doesn't find the key:

from gevent.subprocess import call
call("powershell <script.ps1>, shell=True")

After some research, I found that the 32bit python process is calling the 32bit version of powershell.
I verified it with this simple script that checks if the process running is 32bit or 64bit:

powershell [System.Environment]::Is64BitProcess

Will return True for 64Bit process and False for a 32Bit process.
Manually checking this command works:

C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe [System.Environment]::Is64BitProcess

Returns False as this is the 32Bit version of powershell (yes, quite confusing due to the WOW64 folder).

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe [System.Environment]::Is64BitProcess

Returns True. But running:

from gevent.subprocess import call
call("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe [System.Environment]::Is64BitProcess", shell=True)

Returns False
What am I missing?

ocp1000
  • 571
  • 1
  • 5
  • 12
  • Possible duplicate of [Why do 64-bit DLLs go to System32 and 32-bit DLLs to SysWoW64 on 64-bit Windows?](https://stackoverflow.com/questions/949959/why-do-64-bit-dlls-go-to-system32-and-32-bit-dlls-to-syswow64-on-64-bit-windows) – JosefZ Aug 10 '19 at 15:13

1 Answers1

0

What you're missing is that Windows transparently redirects file system calls from 32-bit processes to C:\Windows\System32 to C:\Windows\SysWOW64 :)

There a simple solution to this - if a 32-bit process tries to fetch file system resources from C:\Windows\sysnative instead, Windows will not redirect to SysWOW64.

From PowerShell it's fairly easy to figure out whether your process will be affected by all of this SysWOW64 redirection, basically:

$IsSysWOW64Process = [Environment]::Is64BitOperatingSystem -and -not [Environment]::Is64BitProcess

In python however, I haven't been able to find a surefire way of doing this, so I suspect your best bet is to call kernel32!IsWow64Process2() via ctypes:

from ctypes import windll,c_ushort,byref
import platform

def is_syswow64_process():
    if platform.architecture()[0] != '64bit':
        # 32-bit OS, no syswow64 handling
        return False

    # Ok, 64-bit OS, let's see if the process is 32-bit
    # Obtain process handle to self
    this_process = windll.kernel32.GetCurrentProcess()

    # Declare ref arguments 
    proc_type, platform_type = c_ushort(), c_ushort()

    # Query Windows for the information
    wow64_call = windll.kernel32.IsWow64Process2(this_process, byref(proc_type), byref(platform_type))

    if wow64_call == 0:
        # you'd probably want to call kernel32!GetLastError here
        raise Exception("Problem querying kernel32!IsWow64Process2")

    return proc_type.value == 0

And now you can conditionally replace the path when needed:

powershell = "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"

if is_syswow64_process():
    powershell = re.sub("(?i)syswow64|system32", "sysnative", powershell)

call("%s .\path\to\script.ps1" % powershell)
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206