Thursday, June 25, 2015

64-bit vs 32-bit PowerShell

When PowerShell is installed on a 64-bit OS, you get both a 64-bit and a 32-bit version of PowerShell. On a 32-bit OS, of course, you only get the 32-bit version of PowerShell.

Which version of PowerShell is running in my session right now? What different does it make? Do I care?

Most of the time, you don’t need to care. Your system will launch the appropriate one, and they both do PowerShell things exactly the same.

Where it matters is when PowerShell needs to talk to or use something outside itself. When that happens, the versions have to match.

For example, if you are running 32-bit PowerShell and you try to use a module that calls a 64-bit .dll, it will fail. Or if you are running 64-bit PowerShell and you try to create a 32-bit COM object, it will fail.

So if I just make sure I install the 64-bit version of all my dependencies, I’m good, right?

Well, maybe not. If something other than you launches PowerShell, it may launch the 32-bit version. Generally, a 32-bit process will launch the 32-bit version of PowerShell, and a 64-bit process will launch the 64-bit version of PowerShell.

For example, System Center Orchestrator is still a 32-bit application, even in 2012 R2. Microsoft has not given any reason to believe that the 2016 version will be any different, as they are devoting their resources to other automation platforms. So when Orchestrator runs a PowerShell script, it runs it using 32-bit PowerShell.

So how can my script check which version it is being run as?

If you are running .Net 4.5 or higher, there is System class named Environment with a static method we can query.

001
[System.Environment]::Is64BitProcess
or
001
[Environment]::Is64BitProcess
will result in $True or $False.

([System] is a default namespace that PowerShell will search when looking for .Net references. So anywhere something starts with “System.”, you can omit “System.”.)

001
[Environment]::Is64BitOperatingSystem
will tell us if it’s a 64-bit OS (and therefore whether or not 64-bit PowerShell is even a possibility on this machine).

But most of us don’t have .Net 4.5 on every server and desktop in our environment.

Fortunately, there is a neat little trick that is backwards compatible with any version of .Net.

There is a System class named IntPtr. This class can be used to create memory pointer objects, which we as scripters would normally never care about. But what’s useful here is the fact that in a 32-bit process, the memory pointers are 32-bits long, and in a 64-bit process, the pointers are 64-bits long.

And the class even has a built-in property that can be called statically to find the size of IntPtr objects. (A static property is one that is hard-coded in the definition of the class, and we can call it directly from the definition without having to create an object of that class first.)

001
[IntPtr]::Size
returns 4 in 32-bit PowerShell, and 8 in 64-bit PowerShell, which is the size in bytes. So we just multiply by 8 to get the number of bits.

001
[IntPtr]::Size * 8
returns 32 or 64 as appropriate.

What do I do if this PowerShell session is the wrong version?

One option is to have your script relaunch itself in the correct version.

BE CAREFUL WITH THIS OPTION. If you get the logic wrong in a script that launches another copy of itself, it will try to iteratively launch an infinite number of copies, and crash your machine.

From a 32-bit PowerShell session, to launch a 64-bit PowerShell session, use:

C:\Windows\SysNative\WindowsPowerShell\v1.0\PowerShell.exe

From a 64-bit PowerShell session, to launch a 32-bit PowerShell session, use:

C:\Windows\SysWOW64\WindowsPowerShell\v1.0\PowerShell.exe

And yes, it looks wrong to launch the 32-bit version from a folder with 64 in the name, but that is correct.

To add to the confusion, the C:\Windows\Sys* folder names are dynamic. When you are in a 64 bit session, the 64-bit folder is named System32, the 32-bit folder is named SysWOW64, and the SysNative folder does not exist. When you are in a 32-bit session, the 64-bit folder is named SysNative, the 32-bit folder is named System32, and the SysWOW64 folder does not exist.

The full path to the script that is running can be found in automatic variable $MyInvocation.MyCommand.Path; we can specify that in the -File parameter.

If your script needs to run in a 32-bit PowerShell session, wrap it in this. If the session is not 32-bit, it will relaunch itself.

001
002
003
004
005
006
007
008
If ( [IntPtr]::Size * 8 -ne 32 )
    {
    C:\Windows\SysWOW64\WindowsPowerShell\v1.0\PowerShell.exe -File $MyInvocation.MyCommand.Path
    }
Else
    {
    # Your code here
    }

If your script needs to run in a 64-bit PowerShell session, wrap it in this. If the session is not 64-bit, it will relaunch itself.

001
002
003
004
005
006
007
008
If ( [IntPtr]::Size * 8 -ne 64 )
    {
    C:\Windows\SysNative\WindowsPowerShell\v1.0\PowerShell.exe -File $MyInvocation.MyCommand.Path
    }
Else
    {
    # Your code here
    }

If your script uses parameters, just add them to the mix.

If your script needs to run in a 32-bit PowerShell session with parameters, wrap it in this.

001
002
003
004
005
006
007
008
009
010
Param ( [string]$YourParam1, [int]$YourParam2 )

If ( [IntPtr]::Size * 8 -ne 32 )
    {
    C:\Windows\SysWOW64\WindowsPowerShell\v1.0\PowerShell.exe -File $MyInvocation.MyCommand.Path -YourParam1 $YourParam1 -YourParam2 $YourParam2
    }
Else
    {
    # Your code here
    }

If your script needs to run in a 64-bit PowerShell session, wrap it in this.

001
002
003
004
005
006
007
008
009
010
Param ( [string]$YourParam1, [int]$YourParam2 )

If ( [IntPtr]::Size * 8 -ne 64 )
    {
    C:\Windows\SysNative\WindowsPowerShell\v1.0\PowerShell.exe -File $MyInvocation.MyCommand.Path -YourParam1 $YourParam1 -YourParam2 $YourParam2
    }
Else
    {
    # Your code here
    }

Going back to my original point, most of the time, you don’t need to care, and this article is just an interesting exploration of some of the consequences of Microsoft trying to keep Windows backwards compatible. But if you are seeing odd behavior in your script that may be related to version incompatibilities, hopefully this will give you some help in confirming and/or working around the issue.

Sunday, June 14, 2015

Microsoft customer input event on automation

I was recently invited to spend a day at an event at Microsoft headquarters in Redmond, WA, to provide customer input to senior Microsoft program managers and developers on the topic of automation. Basically, primary development of Windows Server 2016 and System Center 2016 is finished, and they wanted us to tell them what to start working on for the next version.

I was impressed with the new culture at Microsoft, with their eagerness to find out what could be done to make my life, as a user of their products, better.

As an automation engineer, I was asked to attend an event which specifically addressed automation. They have held and continue to hold similar events with topics including patching, Linux, and DevOps.

21 customers and roughly 40 Microsoft personnel attended.

Customer attendees came from a variety of backgrounds and specialties related to automation. Represented were large enterprises, small businesses, and Microsoft partners (consultants). Most or all were already participating in much larger customer feedback programs, with early access to unreleased products, and with signed Non-Disclosure Agreements already in place. (Which is why this article is about the format and culture of the event, and contains no details of what was discussed.)

The Microsoft people were hands-on product managers, architects and developers, with a few people from QA, as well as technical writers. The most senior was Jeffrey Snover, the lead architect for Windows Server and System Center. The rest were from the PowerShell, SC Orchestrator/SMA, and Azure development teams. (The other well-known PowerShell guru I got to talk to was Bruce Payette.)

These were not sales and marketing people learning about the market. These were engineers learning about the needs of their end-users.

They opened with a few words about how Satya Nadella is changing the culture at Microsoft, and had brought in expert consultants to guide them through the change, and to help them with events like this one.

We were treated to a “ginger shot”, a quick swallow of uncut ginger juice. It burns. Everyone in the room did it together. It burns. Described to us as a recent tradition with numerous health benefits, it was in fact a clever psychological trick. By putting us through a shared “combat” experience, this little bit of self-inflicted hazing helped engender a sense of camaraderie and teamsmanship, breaking down barriers and helping us feel less reserved and able to share our thoughts more readily with the group.

For the first hour, the customers sat on stage and in turn introduced themselves and described in detail their biggest pain point related to automation. That phrase was oft repeated throughout the day. They wanted to know what our “pain points” were.

The Microsoft people listened attentively to the litany of complaints about their products, asked questions, and took copious notes. I have spoken to (and been part of) many different groups in many different circumstances over the years, and I have never seen a group that was more focused on what was being said. Every Microsoft eye was riveted on every speaker.

The rest of the day was comprised of one-hour sessions—intense, directed conversations in groups of 3 customers and 6 Microsoft engineers around a specific focus area. They again listened attentively to all of our complaints and comments and suggestions, asked questions, and took copious notes. For some focus areas, they presented three general possible solutions to a related problem, and asked for feedback.

The focus areas were: authoring, getting started, integrated management, extensibility (or something like that—I didn’t take notes), DevOps, and self service. While the discussion leaders focused on the assigned topic, we the customers were never told our responses were out of scope. Whatever our comments or complaints or suggestions, they listened to them and wrote them down.

They also took us to lunch and dinner, affording us the opportunity for additional, more informal conversations with the Microsoft engineers. Meals, accommodations, and travel were all arranged by and paid for by Microsoft.

There are certain realities of IT on the ground that product developers normally have no way to understand and appreciate. That’s why traditionally there is such a strong history of customers being upset by things that the design engineers thought were “features.” This event was specifically and successfully designed to allow us to help these teams understand those realities, so that the next generation of products will be designed for us in real life, rather than some idealized paradigm.

For example, I had lunch across from the lead developer for runbook servers. I helped him understand that while there are no true technical barriers to a particular paradigm they were hoping to exclusively use going forward, there are corporate political issues that will prevent universal adoption of the paradigm for many years, and that they have to provide interoperability with the legacy paradigm.

Another simple example I brought up was one of my regular rants. In most enterprises, no one, including IT people, have local admin rights on their desktop with their primary ID, if at all. This means things as simple as running Update-Help in PowerShell can’t be done simply. When designing these products, Microsoft needs to stop assuming escalation to admin rights is simple for everyone, and eliminate dependencies on admin rights wherever possible and appropriate. This was not something they knew enough to ask about, but it was something that impacts me and countless others every day. So I brought it up, and they listened and wrote it down.

In fairness, most of what the customers brought up was not news to Microsoft, and had been on their list of things to do for a while. We were there to help prioritize the list, to clarify the nuances of what our pain points are, and to provide feedback on possible solutions.

Overall, it was a great opportunity to help guide the development efforts at Microsoft. It was clear that the attitude and focus of Microsoft has changed considerably, primarily a result of changes in leadership. While the old regime focused on market dominance and making sales, Microsoft is now focused on listening and providing great services to their customers.