Jenkins powershell plugin is running 32 bit Powershell and I need 64bit Jenkins powershell plugin is running 32 bit Powershell and I need 64bit powershell powershell

Jenkins powershell plugin is running 32 bit Powershell and I need 64bit


Environment

  • Jenkins on Windows (mine happens to run as a service)
  • plus Powershell plugin (for running Powershell scripts as "build steps")

Jenkins will typically call upon the correct version of powershell.exe. However, the executor/slave process must be running a 64-bit JRE so that PowerShell can also operate in 64-bit mode.

A simple tester project with the following Powershell script can show the above 32-bit vs 64-bit nature:

$env:Path               # Path will have the right Powershell available[intptr]::size          # outputs: 4 = 32-bit, 8 = 64-bitStop-WebAppPool FOOBAR  # fails when 32-bit, succeeds when 64-bit

Console output example (extra blank lines for clarity):

[Powershell Test] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Windows\TEMP\hudson123456789.ps1'"C:\Windows\system32;C:\Windows;C:\Windows\System32\WindowsPowerShell\v1.0\4Stop-WebAppPool : Retrieving the COM class factory for component with CLSID {688EEEE5-6A7E-422F-B2E1-6AF00DC944A6} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).At C:\Windows\TEMP\hudson123456789.ps1:7 char:1

Solution

tl;dr... Install 64-bit JRE, and configure Jenkins to be 64-bit.

I used chocolatey to install a fairly recent JRE, via "Administrator" PowerShell:

First, install chocolatey:

iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))

Looked for the latest version available https://chocolatey.org/packages?q=java (chocolatey has multiple packages for the same thing, often not kept fully up to date).

Then, install JRE (using the one with the higher JRE number):

choco install -y javaruntime

Or:

choco install -y jre8

Finally, I edited my jenkins.xml configuration so that it would run using the 64-bit JRE instead of the built-in JRE.

Changed:

<executable>%BASE%\jre\bin\java</executable>

To (set the path as appropriate for your instance):

<executable>C:\Program Files\Java\jre1.8.0_66\bin\java</executable>

This one should be an "always fresh" symlink (handled by system updates) that ought to allow your Jenkins instance to survive Restart and Update events:

<executable>C:\ProgramData\Oracle\Java\javapath\java.exe</executable>

Then I restarted Jenkins. Powershell execution woke up to the might of 64-bits. Note: I am using a single Jenkins instance that does double duty as the "server" and "execution slave" at the same time. For fully autonomous slaves, I would suppose doing whatever to get the slave-agents processes in 64-bit mode would result in a similar success.

Full automation? According to the chocolatey "jre8" package documentation, using command line switches, it's even be possible to force fixed destination paths for JRE, and exclude 32-bit and/or 64-bit editions, if fully automated non-interactive steps are needed. https://chocolatey.org/packages/jre8


I am not familiar with Jenkins, but it seems like it's a 32 bit process itself.

Can you specify the location of the PowerShell executable? If so, try to use this path:C:\Windows\SysNative\WindowsPowerShell\v1.0\powershell.exe

If you can't do that, then you might be able to do it in code in your "execution sequence" with Invoke-Command:

Invoke-Command -ComputerName . -ScriptBlock { [Environment]::Is64BitProcess }

All the code in the scriptblock will be run in a separate 64 bit process and the results will be serialized and returned.

Explanations

Paths

On a 32 bit Windows OS, the system folder is C:\Windows\System32. On a 64 bit Windows OS, the 64 bit system folder is also C:\Windows\System32. But the system folder for 32 bit processes on a 64 bit Windows installation is in fact C:\Windows\SysWOW64.

For compatibility, a 32 bit process on a 64 bit OS will have any calls to C:\Windows\System32 transparently redirected to C:\Windows\SysWOW64, unbeknownst to the process.

To enable a 32 bit process to reference the real System32 on a 64 bit OS, you can you use C:\Windows\SysNative.

Since PowerShell has a 32 bit and a 64 bit version, and it lives inside the system folders, you need to use the above rules to reference the correct executable depending on whether you're calling it from a 64 or 32 bit process.

The typical scenario (you want to call the version of the same bitness) is easiest (just call powershell.exe or reference it via System32), but it gets hairy if you want to reference the other version.

Invoke-Command Method

The Invoke-Command cmdlet lets you run code, typically on another computer, but you can run it on the same computer as well. This will spawn a completely separate process, and any output gets serialized and sent back to the calling process.

The caveat to this method is that you must enable PowerShell remoting on the machine, via Enable-PSRemoting or Group Policy (shameless self plug).

The default profile (Microsoft.PowerShell) that you connect to on a 64 bit machine will be a 64 bit version of PowerShell, regardless of the OS of the caller.

Incidentally, if you wanted to use Invoke-Command to connect to a 32 bit version, you could do so by explicitly specifying the profile Microsoft.PowerShell32.


OK, so the answer was pretty simple, yet maddening all at once. Basically, the module(s) didn't exist in both of the Powershell paths (x86 and x64), so copying the modules over to the 32-bit powershell environment fixed the issue.