Wednesday, June 18, 2014

Cannot load Windows PowerShell snap-in microsoft.windowsazure.serviceruntime

There are some issues that simply lose interest due to not being pertinent enough, I believe I have found one.
And I can see from searching that I am not alone here.
The thing that is going on is that I am using startup tasks in a Worker Role to install an MSI and configure it.
When the script being executed by my startup task attempts to: add-pssnapin microsoft.windowsazure.serviceruntime

I receive the error:
add-pssnapin : Cannot load Windows PowerShell snap-in microsoft.windowsazure.serviceruntime because of the following error: The Windows PowerShell snap-in module
F:\plugins\RemoteAccess\Microsoft.WindowsAzure.ServiceRuntime.Commands.dll does not have the required Windows PowerShell snap-in strong name Microsoft.WindowsAzure.ServiceRuntime.Commands, Version=, Culture=neutral,
The work around that has been posted is to edit the registry key for the DLL, because the version is wrong.
My impression of this workaround is this:  "So, now I have to script a work around for an MSFT provided DLL because no one is updating the DLL registration for the snap-in in MSFT provided Gallery Images in Azure."
Mind you, these are developers, and if a workaround can be done in code - my experience has been that the issue is ignored after the workaround exists.

A workaround is great, but there are caveats to all of the workarounds posted thus far;
  • if I update the registry key with the incorrect version number, it still won’t load.  
  • I have to get the right version number and fix the registry entry.
  • And edit both the Assembly Name string and the version string.
Each posted workaround that I can find through search is a point version, and a point version edit.  A lasting workaround (since it seems like this bug is not going to get fixed anytime soon) is to dynamically deal with any version of the DLL and strong name enforcement in the OS.
I always preface that my solution might not be the most elegant thing that a developer comes up with, but I hope that folks can follow it and understand what I did.
# Get the current execution path
$exPath = Split-Path -parent $MyInvocation.MyCommand.Definition
$exPath # Echo for logging

### Before we can load the service runtime, we must fix the broken registry information for the DLL
### and the version must be right, or it will continue to be broken.

$runtimeDllReg = Get-Item HKLM:\SOFTWARE\Microsoft\PowerShell\1\PowerShellSnapIns\Microsoft.WindowsAzure.ServiceRuntime
$runtimeDll = Get-Item $runtimeDllReg.GetValue('ModuleName')

$exportPath = $expath + "\AzureServiceRuntime.reg"

& $env:SystemRoot\System32\regedt32.exe /E $exportPath 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\PowerShellSnapIns\Microsoft.WindowsAzure.ServiceRuntime'

# This is because the wait does not wait until regedit actually completes.

Do {

Start-Sleep 10

$regFile = Get-Item -Path $exportPath -ErrorAction SilentlyContinue

} Until ($regFile.Exists)

$runtimeRegFile Get-Content -Path $exportPath
$newRuntimeRegFile = @()

foreach ($e in $runtimeRegFile) {
     switch -wildcard ($e) {
          "**" { $e = $e -replace "", ($runtimeDll.VersionInfo.FileMajorPart.ToString() + '.' + $runtimeDll.VersionInfo.FileMinorPart.ToString() + '.0.0') }
     $newRuntimeRegFile += $e

Set-Content -Value $newRuntimeRegFile -Path $exportPath -Force

Start-Sleep 2

& $env:SystemRoot\System32\regedt32.exe /S $exportPath

Start-Sleep 2

# Load the necessary PowerShell modules for configuration and management Web and Work Roles
add-pssnapin microsoft.windowsazure.serviceruntime

# Take the VM Instance offline with Azure, or else Azure will keep attempting to start the script
Set-RoleInstanceStatus -Busy

You might wonder why I am using regedit.exe instead of the PowerShell cmdlets to set the value. What I found is that I kept running into permissions issues. And using regedit to export and import is a way around that.

Get more VM detail from Hyper-V

There was recently a question in the Hyper-V TechNet forum asking if there was a way to run the SCVMM Get-SCVirtualMachine cmdlet on a Hyper-V Server.

Well, technically yes;  you install the SCVMM Console PowerShell module on the Hyper-V Server - I don't think that was the intent of the question.

What the individual was looking for is more information about the VM - since SCVMM (by default) returns a ton of information about a virtual machine.
This is status, linked object detail, owner, etc.

Now, all of this information comes from the SCVMM Server, and much of this detail is unique to SCVMM.  At the same time, there is a lot more in Hyper-V than I think most folks realize, because it is filter output by default.

I am going to ignore SCVMM at the moment and focus on getting more from the in-box Hyper-V cmdlet.

Lets run through some examples:

PS C:\> Get-VM *
Name       State   CPUUsage(%) MemoryAssigned(M) Uptime     Status
----       -----   ----------- ----------------- ------     ------
WAPDev     Running 0           1580              4.20:34:51 Operating normally
myAdDns    Running 0           879               4.20:34:55 Operating normally
Downloader Off     0           0                 00:00:00   Operating normally
bjeSql     Running 0           2749              4.20:34:52 Operating normally

PS C:\> Get-VM WAPDev | Format-List

Name             : WAPDev
State            : Running
CpuUsage         : 0
MemoryAssigned   : 1656750080
MemoryDemand     : 1275068416
MemoryStatus     : OK
Uptime           : 4.20:37:01
Status           : Operating normally
ReplicationState : Replicating
Generation       : 2

Now, the individual in the forum post requested the following: "The SCVMM cmdlet Get-SCVirtualMachine returns a plethora of information regarding a VM. I would like to run this cmdlet on a Hyper-V host and get the same level of detail for each VM running on it. It appears that this is not possible."

Let me take my example one step further and show you one simple command that can give you everything about a VM.  It is a command the simply tells the PowerShell cmdlet to return all properties of the VM, not the default filtered set.  That is what the pipe to select * does.

And from here you can dig into the object and go off down some rabbit hole of dependencies such as NetworkAdapters, or the DVDDrives, or the HardDrives.

PS C:\> Get-VM WAPDev | Select *

VMName                      : WAPDev
VMId                        : 7ff0d548-1032-4cce-91ba-9a100a27b113
Id                          : 7ff0d548-1032-4cce-91ba-9a100a27b113
Name                        : WAPDev
State                       : Running
IntegrationServicesState    : Up to date
OperationalStatus           : {Ok}
PrimaryOperationalStatus    : Ok
SecondaryOperationalStatus  :
StatusDescriptions          : {Operating normally}
PrimaryStatusDescription    : Operating normally
SecondaryStatusDescription  :
Status                      : Operating normally
Heartbeat                   : OkApplicationsHealthy
ReplicationState            : Replicating
ReplicationHealth           : Normal
ReplicationMode             : Primary
CPUUsage                    : 0
MemoryAssigned              : 1656750080
MemoryDemand                : 1275068416
MemoryStatus                : OK
SmartPagingFileInUse        : False
Uptime                      : 4.20:39:47
IntegrationServicesVersion  : 6.3.9600.16384
ResourceMeteringEnabled     : False
ConfigurationLocation       : E:\WAPDev
SnapshotFileLocation        : E:\WAPDev
AutomaticStartAction        : StartIfRunning
AutomaticStopAction         : Save
AutomaticStartDelay         : 0
SmartPagingFilePath         : E:\WAPDev
NumaAligned                 : False
NumaNodesCount              : 1
NumaSocketCount             : 1
Key                         : Microsoft.HyperV.PowerShell.VirtualMachineObjectKey
IsDeleted                   : False
ComputerName                : SWEETUMS
Version                     : 5.0
Notes                       :
Generation                  : 2
Path                        : E:\WAPDev
CreationTime                : 11/22/2013 11:42:23 AM
IsClustered                 : False
SizeOfSystemFiles           : 69268
ParentSnapshotId            :
ParentSnapshotName          :
MemoryStartup               : 2147483648
DynamicMemoryEnabled        : True
MemoryMinimum               : 1073741824
MemoryMaximum               : 1099511627776
ProcessorCount              : 2
RemoteFxAdapter             :
NetworkAdapters             : {Network Adapter}
FibreChannelHostBusAdapters : {}
ComPort1                    : Microsoft.HyperV.PowerShell.VMComPort
ComPort2                    : Microsoft.HyperV.PowerShell.VMComPort
FloppyDrive                 :
DVDDrives                   : {DVD Drive on SCSI controller number 0 at location 1}
HardDrives                  : {Hard Drive on SCSI controller number 0 at location 0}
VMIntegrationService        : {Time Synchronization, Heartbeat, Key-Value Pair Exchange, Shutdown...}

So, the next time you want to know more about your VM, or you want to do a relationship walk from the VM object to the dependent object - just remember to "select *" and return all properties of the VM to you $vm object.  It takes longer, it works WMI harder, but it might get you where you are headed.

Once you know what you are looking for - using Get-VM, Get-VMMemory, Get-VMDVDDrive, Get-VMHardDisk, Get-VMSnapshots, etc. are actually faster - since they focus on the class of object and filter by that class.