Add-Bcd-Vhd.ps1

I LOVE the new boot from VHD feature in Win7. I am primarily using it for doing some VS 2010 dogfooding without messing up my primary drive partition. But man, the process for setting up a VHD for booting is brutal. Scott Hanselman did a great job laying out the steps, but I wanted something a bit more productive.

First, I created a clean Win7 RC VHD and zipped it up for easy storage. The basic Win7 RC VHD is just under 5GB, but compresses down to about 1.5GB with 7-zip. I used the ImageX process Aviraj described though in the future I’ll use the Install-WindowsImage script. Install-WindowsImage is more convenient to use because it will list the indexes within a given .wim file instead of making you grovel thru an XML file like ImageX does. Also Install-WindowsImage is 27k download while ImageX is part of the 1.4 gigabyte Windows Automated Installation Kit. Look, I’m not hurting for bandwidth, but I don’t see the point of downloading 54442 times more data for a utility that isn’t as useful.

Once you’ve created the VHD, you need to update your Boot Configuration Data, or BCD for short, using the appropriately named BCDEdit utility. The process is fairly straight forward, if tedious. You have to run BCDEdit four times, copy the configuration GUID to the clipboard and type out the path to the VHD in a slightly funky syntax. Blech. So I built a PowerShell script to automate updating the BCD, called add-bcd-vhd. You can get it from my SkyDrive. Pass in the name of the BCD entry and the path to the VHD and add-bcd-vhd will do the rest.

I was whining on Twitter yesterday that there’s no PowerShell specific tools for managing the BCD data. Add-bcd-vhd just runs bcdedit behind the scenes and processes the text output with regular expressions. Ugly, but effective. I decided to spend some time trying accessing the BCD data from its WMI provider, but that turned out to be way too much of a hassle to be effective. If someone else out there knows how to use the BCD WMI provider from PowerShell, I’d appreciate some sample code.

__clrtype__ Metaclasses: Named Attribute Parameters

In my last post, I added support for custom attribute positional parameters . To finish things off, I need to add support for named parameters as well. Custom attributes support named parameters for public fields and settable properties. It works kind of like C# 3.0’s object initalizers. However, unlike object initalizers, the specific fields and properties to be set on a custom attribute as well as their values are passed to the CustomAttributeBuilder constructor. With six arguments – five of which are arrays – it’s kind of an ugly constructor. But luckily, we can hide it away in the make_cab function by using Python’s keyword arguments feature.

def make_cab(attrib_type, *args, **kwds):
  clrtype = clr.GetClrType(attrib_type)
  argtypes = tuple(map(lambda x:clr.GetClrType(type(x)), args))
  ci = clrtype.GetConstructor(argtypes)

  props = ([],[])
  fields = ([],[])

  for kwd in kwds:
    pi = clrtype.GetProperty(kwd)
    if pi is not None:
      props[0].append(pi)
      props[1].append(kwds[kwd])
    else:
      fi = clrtype.GetField(kwd)
      if fi is not None:
        fields[0].append(fi)
        fields[1].append(kwds[kwd])
      else:
        raise Exception, "No %s Member found on %s" % (kwd, clrtype.Name)

  return CustomAttributeBuilder(ci, args,
    tuple(props[0]), tuple(props[1]),
    tuple(fields[0]), tuple(fields[1]))

def cab_builder(attrib_type):
  return lambda *args, **kwds:make_cab(attrib_type, *args, **kwds)

You’ll notice that make_cab now takes a third parameter: the attribute type and the tuple of positional arguments we saw last post. This third parameter “**kwds” is a dictionary of named parameters. Python supports both positional and named parameter passing, like VB has for a while and C# will in 4.0. However, this **kwds parameter contains all the extra or leftover named parameters that were passed in but didn’t match any existing function arguments. Think of it like the params of named parameters.

As I wrote earlier, custom attributes support setting named values of both fields and properties. We don’t want the developer to have to know if given named parameter is a field or property, so make_cab iterates over all the named parameters, checking first to see if it’s a property then if it’s a field. It keeps a list of all the field / property infos as well as their associated values. Assuming all the named parameters are found, those lists are converted to tuples and passed into the CustomAttributeBuilder constructor.

In addition to the change to make_cab, I also updated cab_builder slightly in order to pass the **kwds parameter on thru to the make_cab function. No big deal. So now, I can add an attribute with named parameters to my IronPython class and it still looks a lot like a C# attribute specification.

clr.AddReference("System.Xml")
from System.Xml.Serialization import XmlRootAttribute
from System import ObsoleteAttribute, CLSCompliantAttribute
Obsolete = cab_builder(ObsoleteAttribute)
CLSCompliant = cab_builder(CLSCompliantAttribute)
XmlRoot = cab_builder(XmlRootAttribute)

class Product(object):
  __metaclass__ = ClrTypeMetaclass
  _clrnamespace = "DevHawk.IronPython.ClrTypeSeries"
  _clrclassattribs = [
    Obsolete("Warning Lark's Vomit"),
    CLSCompliant(False),
    XmlRoot("product", Namespace="http://samples.devhawk.net")]

  # remainder of Product class omitted for clarity

As usual, sample code is up on my SkyDrive.

Now that I can support custom attributes on classes, it would be fairly straightforward to add them to methods, properties, etc as well. The hardest part at this point is coming up with a well designed API that works within the Python syntax. If you’ve got any opinions on that, feel free to share them in the comments, via email, or on the IronPython mailing list.