Doing P2V with HyperV

I had recently tried to use my Windows Home Server to restore a laptop image to a VM running inside HyperV. 

In the event that my machine totally died (not just a hard drive issue) I could restore the image to a VM and work from there while I got back on my feet with a new laptop.

Unfortunately I didn’t find any way to make this work.  I ended up doing all this work and in the end, I couldn’t boot.

A disk read error occurred
Press ctrl+alt+delete to restart.

I tried everything I could think of, repairing the MBR, running fixboot, doing a windows repair, restoring the hal dll from i386 etc.  Nothing worked.

So I gave up on using WHS to create an instance of my dev machine, and fell back on just trying to do a P2V of any type.

I came across Disk2VHD, a free Systernals tool.  This tool includes the options to run on the source machine while online, and also provides an option to “Fix” the HAL (hardware abstraction layer).  I think this was part of my original problem (the HAL issue).  My computer was setup to use SATA drivers, and HyperV only supports virtual IDE drivers.  I think (but am not sure) that this is what was causing my problem w/ using the WHS restore.

So anyway, Disk2VHD runs super fast, and pretty soon I had a VHD to try out. 

Now, this VHD didn’t work either, but it would get me further along.  I would see the windows splash screen before the black screen of death.

What followed was a weird set of steps trying to figure out why things wouldn’t work, but in the end, I never ended up needing to disable anything…. so I’m just going to try to write down the steps I took as best I can.

  1. After the first BSOD I booted to safe mode (using F8).
  2. Safe mode worked, and it seemed to find some new hardware, as I would have expected, but I don’t think it found any of the drivers it needed (so maybe I had ejected the virtual windows CD or something).
  3. Booting normally gave the black screen of death again.
  4. I then found this page with instructions on how to replace the HAL.  Really these instructions were how to do Disk2VHD to a working VM, but I had already done most of the steps except the hal replacement.  I’m going to replace those instructions below:
    1. 1)Downloaded Disk2VHD (v 1.3) from sysinternals (free) and unzipped on the laptop
      2)Find a place to store the new vhd – I used a 320GB external USB, but any storage device that pc can see and is big enough to hold your hard disk should work
      3)Run Disk2VHD and input the name and location for the new file
      4)On your virtual host create a new VPC (I use Virtual PC 2007) and add that new vhd you just created as the primary hard disk.
      5)Make sure you have an ISO of WinXP or an actual disk. If using an iso you’ll need to mount it so it can be booted from.
      6)Fire up the new vpc and have it boot from that XP disc.
      7)Let it run setup and then select option 2 (R) to get repair console
      Login in to windows (need admin pw)
      9)Type “cd system32” press enter
      10)Assuming your CD (or mounted iso) is drive D – Type “expand d:i386halacpi.dl_” press enter
      11)Type “copy halacpi.dll hal.dll” press enter and then press y
      12)Reboot
      13)Press F8 to get to safe mode
      14)After the message that new stuff was installed, click OK for reboot
      15)After system boots back up, log in and install VM Additions
  5. IIRC I still got the black screen of death.  It’s possible that at this point behind the scenes it was doing a check of my disck or something, but I can’t tell in the VM if the HDD is going or not so I just assumed it was locked.
  6. I booted to safe mode and used MSconfig to disable everything, and also used /SOS, and some other options.
  7. What followed was just a series of successful boots with me enabling more and more until I had everything enabled and it all still worked, so I’m not sure why I was getting the BlackSOD before I started this set of SafeMode boots.
  8. Another thing I did at some point (maybe more than once) was try to install the VM Integration Services, which says that it’s updating the HAL, so maybe that had something to do with it too.

The next 2 things that I’m going to try are, running a WHS restore to a VM that is already working (I don’t think this will matter, but we’ll see), and 2 trying to use the Disk2VHD on a machine that has a VHD mounted as a secondary drive.  I don’t konw if this is even possible, but I was thinking that I could use WHS to create the VHD, mount the VHD as X: on some machine, and then tell Disk2VHD to create a VHD from X: and instruct it to to the “Fix HAL” thing.  I’m guessing that will not work as well, but we’ll see.

 

Connecting dynamically to mygeneration MyMeta.dbRoot

The amount of time that this cost me is astounding for such a stupid issue.  (And, I’m going to lay the blame fully on whoever wrote the dbRoot object in the MyGeneration project.  Total improper use of properties).

The situation was this: I was trying to dynamically wire up all the plumbing that the mygeneration windows app does for you manually from the ZeusCmd command line.

Doing this would allow me to switch from DB to DB within my code gen application.

Because ZeusCmd runs first (it references my app and passes in what is needed), if you had previously saved a connection in your MyGeneration app, then this connection is used when ZeusCmd runs.  I didn’t want this to happen because as I move from location to location different DB servers are available or not available, so if the last DB server I connected to was at office A, I didn’t want my code gen crashing onload when I am out of said office.

So I ran MyGeneration and changed my connection to be <None> and saved the settings.  Then in my code gen, I tried to manually create the dbRoot object (named meta here) that was previously created for me my ZeusCmd and my saved MyGeneration settings.

Code like this:

meta.Connect("SQL", "Provider=SQLNCLI;Server=cmayt61p;Database=DBName;Trusted_Connection=yes;")

Seemed to do the trick.

However, my codegen started blowing up on my later in the process.  After tracking down the error I find that the mygeneration result column object can’t figure out the .net type that would be the same as a sql server “int”.  Strange, never had these problems before.

A lot of debugging leads me to find that:

meta.DbTarget
meta.Language 

Are both returning “” when before they were returning “SqlClient” and “VB.NET” when I was not dynamically connecting.

So here is where things get bad… anytime I try setting these properties to their values:

meta.DbTarget = "SqlClient"
meta.Language = "VB.NET"

Nothing happens.  The values don’t appear to stick.

Eventually I even start trying to set the LanguageMappingFileName and DbTargetMappingFileName properties as well:

meta.DbTarget = "SqlClient"
meta.Language = "VB.NET"
meta.LanguageMappingFileName = "C:Program FilesMyGeneration13SettingsLanguages.xml"
meta.DbTargetMappingFileName = "C:Program FilesMyGeneration13SettingsDbTargets.xml"

I tried doing these property sets before connecting and after connecting.

I tried returning to having MyGeneration setup the meta object form me (and all these properties have their values) before dynamically connecting (and losing the DbTarget and Language property values).

I even tried creating a brand new dbRoot object, as well as trying to read some hidden values in the IZeusInput object.

But, in the end, it all came down to the this 1 little thing:

You have to set the mapping file properties before you can set the DbTarget and Language properties.

So this will work just fine:

meta.Connect("SQL", "Provider=SQLNCLI;Server=cmayt61p;Database=MSiUpgraded;Trusted_Connection=yes;")
meta.LanguageMappingFileName = "C:Program FilesMyGeneration13SettingsLanguages.xml" meta.DbTargetMappingFileName = "C:Program FilesMyGeneration13SettingsDbTargets.xml" meta.DbTarget = "SqlClient" meta.Language = "VB.NET"

But this won’t:

meta.Connect("SQL", "Provider=SQLNCLI;Server=cmayt61p;Database=MSiUpgraded;Trusted_Connection=yes;")
meta.DbTarget = "SqlClient" meta.Language = "VB.NET" meta.LanguageMappingFileName = "C:Program FilesMyGeneration13SettingsLanguages.xml" meta.DbTargetMappingFileName = "C:Program FilesMyGeneration13SettingsDbTargets.xml"

It just so happened that everywhere that I was testing this stuff in my code, I always set the DbTarget and Language properties first, and they would never stick.

This is not a proper use of properties.  If a property set has conditional logic that will prevent it from setting, there is something wrong here.  At minimum something should happen, an exception being thrown maybe?  The proper thing to do in my mind would be to make DbTarget and Language readonly properties and have functions to set their value, which could return something indicating failure (or throw an exception).

Property gets and sets should do just that, get and set properties.  There shouldn’t be logic in there deciding if and when to actually perform the set that you have coded.  That is the job of a function.

UPDATE: And I discovered as well that you have to connect first before you set any of these values, or none of them will stick.  So you have to 1) connect 2) set the file paths 3) set the language and dbtargets, in that order or nothing works.