1

Resolved

Cloudinit.exe needs to target AnyCPU instead of x86

description

Wow... it just took me hours and hours to track down this issue, including lots of chasing after red herrings (including suspecting there was something up with admin privileges, which there was not).
 
When the service is targeted as x86, it creates a new instance of 32-bit PowerShell, even when on a 64-bit OS like Server Core 2008 R2.
 
This ends up being a massive issue.
 
Amongst other commands, I was trying to run DISM /online /featurename:foo in my cloudinit script to add features to the core OS.
 
My script was dying at that point, and I couldn't understand why. As I finally was able to determine, the 32-bit PowerShell was calling out to 32-bit DISM, which will crash and burn on a 64-bit OS.
 
Before I was able to figure that out, I decided to prepare my CloudInit AMI (by hand) with the Powershell cmdlets for ServerManager.
 
DISM /Online /Enable-Feature /FeatureName:ServerManager-PSH-Cmdlets /FeatureName:BestPractices-PSH-Cmdlets
 
This enables you to do the following in a script
 
Import-Module ServerManager
Add-WindowsFeature Web-Server
 
I did this thinking that there was some permissions elevation / UAC issue preventing DISM from running. As it turns out, Import-Module will fail silently if a module is missing, but your script will crash and burn if you try to use a non-existent cmdlet. So Add-WindowsFeature was dying.
 
What was really happening was that these Powershell cmdlets are installed as 64-bit only. They don't appear in the list of installed modules for 32-bit Powershell.
 
Another interesting issue comes up. Along the way during debugging, I tried to log the console output of whoami.exe. If running under 64-bit PowerShell, you can find it under $Env:windir\system32\whoami.exe. However, this will not work under 32-bit PowerShell. The correct location is actually $Env:windir\sysnative\whoami.exe. Similarly, you can't resolve with something like [Environment]::GetFolderPath([Environment+SpecialFolder]::System)\whoami.exe either. That's what ultimately tipped me off, and I found a good explanation of why this is:
 
http://www.tipandtrick.net/2008/how-to-suppress-and-bypass-system32-file-system-redirect-to-syswow64-folder-with-sysnative/
 
 
IMHO, it would be great to see the service run as AnyCPU to avoid these types of issues. I see that you're munging StructureMap into cloudinit.exe during the build (presumably with some ildasm / ilasm magic?) -- I'm wondering if that's when x86 is getting set on the resultant cloudinit.exe?
 
I can probably fix this and submit a pull request... but wanted to share what I ran into and get others thoughts.
 
Clearly this ended up being a pretty major issue for me, but maybe there was a reason for running x86?

comments

Iristyle wrote Jan 27, 2012 at 7:36 PM

I see that 1.2 actually targets AnyCPU now... so this is moot now! Sorry about that!

bwight4157 wrote Jan 27, 2012 at 7:38 PM

I don't remember what exactly I found the same bug and it's been fixed in 1.2 like you said.

wrote Jan 27, 2012 at 7:39 PM

Iristyle wrote Jan 27, 2012 at 7:45 PM

It might be helpful to log the 32-bit vs 64-bit process info during the startup of CloudInit to the log.

I've also been doing something like this in my scripts:
Add-Content $log -value "Available Modules - $(get-module -listAvailable | select -ExpandProperty name)"

That would have gone a long way to figuring out where my modules went.

bwight4157 wrote Jan 27, 2012 at 8:05 PM

I'll take a look at it. Could be useful. Also at least now if the script is crashing from powershell you should get the errors from powershell logged. Before it would just crash the service without giving you any hints.

wrote Feb 13, 2013 at 9:37 PM

wrote May 16, 2013 at 1:29 AM

wrote May 16, 2013 at 1:29 AM

wrote Jun 14, 2013 at 7:11 AM