9
votes

We have several scripts we use to install and configure the dependencies backing the systems we maintain. We run these anytime we establish a dev, test, demo, train, prod, etc. environment. We often find that we have to deal with x64 vs. x86 architecture, especially where the powershell scripts are concerned.

For example, I have a script that uses the Windows Installer PowerShell Extensions to determine if a program/patch has been installed. The script doesn't work in an x64 environment without explicitly invoking PowerShell (x86), which, isn't in the path by default. As we port these scripts to the x64 platform it would be great to maintain a single set of scripts that work in powershell on both architectures and only invoke x86 code when needed.

Does anyone know of a strategy for doing this?

2

2 Answers

18
votes

I run into this issue a lot with my configuration scripts. The basic approach I take is to

  1. Use several functions to test if I'm in a 64 bit environment (http://blogs.msdn.com/jaredpar/archive/2008/10/16/powershell-and-64-bit-windows-helper-functions.aspx)
  2. Invoke x86/x64 PowerShell based on the needs of a particular script

Unfortunately a lot of this is done in a brute force manner. Each particular configuration entry that is x86/x64 dependent essentially has 2 code paths (one for each architecture).

The only real exception I've been able to make is to test for the existince of certain programs on disk. I have a handy function (Get-ProgramFiles32) which makes it easy to test for programs.

if ( test-path (join-path Get-ProgramFiles32 "subversion") ) { ...

Here are all of the helper functions that I have in my common library that deal with 32/64 bit differences.

# Get the path where powershell resides.  If the caller passes -use32 then 
# make sure we are returning back a 32 bit version of powershell regardless
# of the current machine architecture
function Get-PowerShellPath() {
    param ( [switch]$use32=$false,
            [string]$version="1.0" )

    if ( $use32 -and (test-win64machine) ) {
        return (join-path $env:windir "syswow64\WindowsPowerShell\v$version\powershell.exe")
    }

    return (join-path $env:windir "System32\WindowsPowerShell\v$version\powershell.exe")
}


# Is this a Win64 machine regardless of whether or not we are currently 
# running in a 64 bit mode 
function Test-Win64Machine() {
    return test-path (join-path $env:WinDir "SysWow64") 
}

# Is this a Wow64 powershell host
function Test-Wow64() {
    return (Test-Win32) -and (test-path env:\PROCESSOR_ARCHITEW6432)
}

# Is this a 64 bit process
function Test-Win64() {
    return [IntPtr]::size -eq 8
}

# Is this a 32 bit process
function Test-Win32() {
    return [IntPtr]::size -eq 4
}

function Get-ProgramFiles32() {
    if (Test-Win64 ) {
        return ${env:ProgramFiles(x86)}
    }

    return $env:ProgramFiles
}

function Invoke-Admin() {
    param ( [string]$program = $(throw "Please specify a program" ),
            [string]$argumentString = "",
            [switch]$waitForExit )

    $psi = new-object "Diagnostics.ProcessStartInfo"
    $psi.FileName = $program 
    $psi.Arguments = $argumentString
    $psi.Verb = "runas"
    $proc = [Diagnostics.Process]::Start($psi)
    if ( $waitForExit ) {
        $proc.WaitForExit();
    }
}

# Run the specified script as an administrator
function Invoke-ScriptAdmin() {
    param ( [string]$scriptPath = $(throw "Please specify a script"),
            [switch]$waitForExit,
            [switch]$use32=$false )

    $argString = ""
    for ( $i = 0; $i -lt $args.Length; $i++ ) {
        $argString += $args[$i]
        if ( ($i + 1) -lt $args.Length ) {
            $argString += " "
        }
    }

    $p = "-Command & "
    $p += resolve-path($scriptPath)
    $p += " $argString" 

    $psPath = Get-PowershellPath -use32:$use32
    write-debug ("Running: $psPath $p")
    Invoke-Admin $psPath $p -waitForExit:$waitForExit
}
2
votes

The msgoodies blog has this suggestion for determining the architecture. One could use this approach to determine the architecture and invoke the x86 powershell when there is a known incompatibility.