Thursday, May 22, 2008

Is this PowerShell Session a 32-bit or a 64-bit?

How can one identify whether the current PowerShell process is running the 32-bit version (x86) or the 64-bit version of PowerShell? Well first, why would you care? You are right, normally I do not care, but if I need to execute VBscript with Invoke-Script, I need to know as that only works on 32-bit Windows.

I'm now running Vista x64 - and that is actually a pleasure. For the first time, I feel my PC is responsive enough when running many applications. If you are interested, my PC is a Dell D830 with 4 GB RAM and a Intel Turbo Channel module having 1 GB. OK specs and nice performance.

One of the minor problems I have encountered is that MSScriptControl.ScriptControl used by Invoke-Script cannot be started from 64-bit PowerShell. I simply does not exist :(

So I set off hunting a way of finding out how to differentiate, so I could do something clever.

First, I looked at the $host variable, but that seemed to return the same info. Next, I looked at the current process. The only difference I found was the image path, there does not seem to be any flag indicating the execution mode. Strange, I would have expected that.

Before jumping on a image path test, I looked as wmi32_process as well. This did not really help me, but at least win32_operatingSystem.OSArchitecture help me figuring out the platform.

This all added up in Get-Architecture.ps1 which contains -



param([switch]$CurrentProcess)

if ($CurrentProcess.ispresent) {
$me=[diagnostics.process]::GetCurrentProcess()
if ($me.path -match '\\syswow64\\') {
32
}
else {
64
}
}
else {
$os=Get-WMIObject win32_operatingsystem
if ($os.OSArchitecture -eq "64-bit") {
64
}
else {
32
}
}


Example -



PS> powershell -noprofile {get-architecture -currentprocess}
64
PS> C:\WINDOWS\syswow64\windowspowershell\v1.0\powershell.exe -noprofile {get-architecture -currentprocess}
32
PS> powershell -noprofile {get-architecture}
64
PS> C:\WINDOWS\syswow64\windowspowershell\v1.0\powershell.exe -noprofile {get-architecture}
64
PS> powershell -noprofile {get-architecture -currentprocess}
64
PS> C:\WINDOWS\syswow64\windowspowershell\v1.0\powershell.exe -noprofile {get-architecture -currentprocess}
32


Suggestions for improvements are highly welcome!

6 comments:

Anonymous said...

Why not just check the size of a pointer?

if ([System.IntPtr]::Size -eq 8)
{
64
}
else
{
32
}

Per Østergaard said...

You are right, that actually works! The reason I did not look into this, is that I assumed that .Net would isolate me from the information: An int is the same size on 32 and 64 bit (try [int]::MaxValue). Obviously [IntPtr] reveal the underlying bitwidth.

Per Østergaard said...

The script now reads -

param([switch]$CurrentProcess)

if ($CurrentProcess.ispresent) {
    if ([intptr]::size -eq 4) {
        32
    }
    else {
        64
    }
}
else {
    $os=Get-WMIObject win32_operatingsystem
    if ($os.OSArchitecture -eq "64-bit") {
        64
    }
    else {
        32
    }
}

Faster is normally better

Ryan O'Dwyer said...

Would checking the PROCESSOR_ARCHITECTURE environment variable be just as easy?

on a 64bit powershell it eq AMD64 in a 32bit powershell it eq X86

this is from a non programmer so I could be totally wrong.

Per Østergaard said...

Hi Ryan

To my surprise, it turns out your are right! First, I thought you were wrong, but when I checked, PowerShell32 actually has modified environment variables compared to a normal process! But if you look at the environment variables with e.g. PROCEXP, PROCESSOR_ARCHITECTURE is always AMD64 (on my system).
It seems like PowerShell is doing something...

BTW: ProgramFiles is also changed


Per

Pat Richard, MCSE MVP said...

One liner:
if ((Get-WMIObject win32_operatingsystem).OSArchitecture -eq '64-bit'){ write-host "64 bit"}else{write-host "32-bit"}