Tuesday, July 22, 2014

Files in and out of Hyper-V VMs with Copy-VMFile

Over the life of Hyper-V there have been lots of convoluted ways that folks have used to get files in and out of Hyper-V VMs.

The most common method has been to mount the VHD and copy files in and out.  But you can't do this while the VM is running.

Then there the issue of using differencing disks or snapshots - and you want to replicate one file to many VMs.  Folks try and mount the parent virtual disk and copy files in - but due to the way that differencing disks work, this gives mixed results if it works at all.

Well, Hyper-V has a nifty feature of the Integration Components / Integration Services that allows you to inject files in or pull files out of a running VM.
The PowerShell cmdlet is Copy-VMFile.

I recently stumbled on this while getting some labs set up and I suddenly realized that I have 25 lab machines with 4 VMs each that my students will be using, and I have a broken lab if I don't correct one file.  Did I mention that I can't physically visit these servers?  I only have remote access.  What a pain.

Prior to being able to use the cmdlet you must have Guest Services enabled on your VM - and this is not on by default.

Enable-VMIntegrationService -Name 'Guest Service Interface' -VMName DSC01
Then, you can push a file into a VM from the Hyper-V Server by using -FileSource Host

Copy-VMFile -Name DSC01 -SourcePath .\1.2.0.0.zip -DestinationPath 'C:\Users\Public\1.2.0.0.zip' -FileSource Host -CreateFullPath
You use the -Force parameter if you are overwriting an existing file.  And you don't need -Force otherwise.
-CreateFullPath does just what you would think it does, it creates the folder path you defined if it is not already present.

Simple as that.

There is some safety built into this I will mention.  Such as you cannot copy into the system path and other permissions blocks you will encounter.

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=1.0.0.0, 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) {
          "*1.0.0.0*" { $e = $e -replace "1.0.0.0", ($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.

Wednesday, May 21, 2014

SCVMM is deploying using the wrong VHD or VHDX

I like this one.  It is interesting.
This is a classic case of 'as designed' being exposed through changes in behavior as an implementation evolves.  Combined with what you see in the UI not really being what happens in the system.

I like it because I consider it a bug due to the fact that the behavior has changed between release and applying Update Rollups.

The symptom is this: you deploy a VM (or a bare metal deployment) and you observe that SCVMM is using the incorrect virtual disk.
And you noticed this happening consistently after applying UR2 (IMHO - that is the key differentiator in the behavior change).

In a nutshell - SCVMM is selecting the virtual disk from the Library.  And it is actually getting more than one from the Library and it is using the incorrect one.

Lets back up a bit.  How is SCVMM ending up with an incorrect virtual disk from the Library in the first place.

Objects in the SCVMM Library have this concept of equivalency.  Multiple objects being equivalent to each other, though they are different objects.
And virtual disks are one of these objects.

Lets say that you create one VHD and this is Server 2012 R2, sysprep'd, all ready to go.  You assign that to a Host Profile or a Service Template, or a WAP Gallery Item.  You set the version to 1.0.0.0 and the family to 'Server 2012 R2' and the OS to 'Server 2012 R2 Datacenter'.
You perform some test deployments and all is good, you move ahead and use it.

After a bit, you get new hardware and you create a new VHD.  Identical to the first except you add some additional drivers for the new storage cards and NICs.
You set the version and family and OS the same.

You then open the Host Profile or Service template and select this new disk.
You deploy, and ... your hardware does not work.  Your new device drivers are missing.  You jump up and down and bang your head on the wall.
You run around in circles.

What happened was this.  SCVMM didn't select the single object that you think you selected.  It selected the OS, family, and version.  And it got two back from the Library.  It then used the "first" one, not the second one.  (this is the behavior change - prior to UR2 it was as if the one with the later date was used, but no longer).

Make the version unique (or the family name) and you will fix the problem.

According to the VMM team - this is 'as designed'.  That is developer speak for:  We built it to work that way.
I hope the documentation will soon describe this equivalency concept.  Since it currently mentions it in passing and never really describes anything about it.

Until then, I hope search brings you here.


Tuesday, April 29, 2014

Uninstalling software from Server 2012 R2 Core

Back a while ago I had a short post about uninstalling the SCVMM agent from Server Core.

That was an older version of Server and an older version of PowerShell.

Today, I had a reason to revisit that process.  But now I have a bit more finesse with PowerShell and PowerShell is now in its v4 revision with Server 2012 R2.

And, needless to say, it is considerably simpler.

I am simply going to capture and paste my PowerShell screen and allow you to sort out the rest by reading through it.  I think you will understand it simply enough.

PS C:\> Get-WmiObject -Class win32_product | ft

IdentifyingNumber Name Vendor Version Caption
----------------- ---- ------ ------- -------
{1D8E6291-B0D5-35EC-... Microsoft Visual C++... Microsoft Corporation 10.0.40219 Microsoft Visual C++...
{3834A905-5CC1-454D-... Microsoft System Cen... Microsoft Corporation 3.2.7510.0 Microsoft System Cen...
{A89BBF08-D933-4634-... Microsoft System Cen... Microsoft Corporation 3.2.7620.0 Microsoft System Cen...


PS C:\> Get-WmiObject -Class win32_product


IdentifyingNumber : {1D8E6291-B0D5-35EC-8441-6616F567A0F7}
Name : Microsoft Visual C++ 2010 x64 Redistributable - 10.0.40219
Vendor : Microsoft Corporation
Version : 10.0.40219
Caption : Microsoft Visual C++ 2010 x64 Redistributable - 10.0.40219

IdentifyingNumber : {3834A905-5CC1-454D-8CA4-AC449F12775D}
Name : Microsoft System Center Virtual Machine Manager DHCP Server (x64)
Vendor : Microsoft Corporation
Version : 3.2.7510.0
Caption : Microsoft System Center Virtual Machine Manager DHCP Server (x64)

IdentifyingNumber : {A89BBF08-D933-4634-8FBB-EB88F870981B}
Name : Microsoft System Center Virtual Machine Manager Agent (x64)
Vendor : Microsoft Corporation
Version : 3.2.7620.0
Caption : Microsoft System Center Virtual Machine Manager Agent (x64)



PS C:\> $installed = Get-WmiObject -Class win32_product
PS C:\> $installed[1].Uninstall()


__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
PSComputerName :



PS C:\> $installed[2].Uninstall()


__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
PSComputerName :



PS C:\> Get-WmiObject -Class win32_product


IdentifyingNumber : {1D8E6291-B0D5-35EC-8441-6616F567A0F7}
Name : Microsoft Visual C++ 2010 x64 Redistributable - 10.0.40219
Vendor : Microsoft Corporation
Version : 10.0.40219
Caption : Microsoft Visual C++ 2010 x64 Redistributable - 10.0.40219



PS C:\>