Using PowerShell and the the iSCSI Target 3.3 WMI classes to create a differencing VHD for OS boot

I recently blogged about the PowerShell cmdlets included with the Microsoft iSCSI Software Target 3.3. That included the details on all the 10 cmdlets available, including the one used to create VHD files, which is New-IscsiVirtualDisk. If you’re paying close attention to the list of new features in the iSCSI Target 3.3, you probably noticed that it also supports using differencing VHDs for OS boot. However, the parameters for New-IscsiVirtualDisk cmdlet do not mention differencing disks at all:

New-IscsiVirtualDisk [-DevicePath] <WindowsPath> [-Size] <StorageSize> [-ComputerName <string>]

Although there is no iSCSI Target cmdlet to directly create a differencing VHD, I dug a little deeper and found that the iSCSI Target also exposes a number of WMI classes. They include more functionality than the included PowerShell cmdlets expose. The good news is that PowerShell is really good at using WMI directly. So I set out to find how to create an iSCSI Target differencing disk using PowerShell and the WMI classes.

First, to get a full list of the iSCSI WMI classes related to the iSCSI Target, you need to use the –List option of the Get-WMIObject cmdlet (or gwmi for short). You need to know the specific namespace of your WMI object (you’ll find the iSCSI Target classes under “root/WMI”) and you can also filter by a portion of the class name (the iSCSI Target classes use “WT_” as a prefix). This must be done on a server with the Microsoft iSCSI Software Target 3.3 installed. So, here’s the cmdlet to list the iSCSI Target WMI classes:

PS C:> Get-WmiObject -Namespace "root/wmi" -List "WT_*"

   NameSpace: ROOTwmi

Name Methods Properties
---- ------- ----------
WT_SnapshotEvent {} {Id, OrigWTD, SECURITY_DESCRIPTOR, State...}
WT_DVMountedPath {} {MountedPath, WTD}
WT_LUNMapping {} {HostName, LUN, WTD}
WT_Portal {} {Address, Listen, Port}
WT_Connection {} {CID, DataDigestEnabled, HeaderDigestEnabled, InitiatorIPAd...
WT_Disk {NewWTDisk, NewDi... {AllocatedSize, CacheParent, Description, DevicePath...}
WT_Host {NewHost, AddWTDi... {CHAPSecret, CHAPUserName, Description, Enable...}
WT_IDMethod {} {HostName, Method, Value}
WT_ISnsServer {} {ServerName}
WT_Session {} {Connections, HostName, InitiatorIQN, ISID...}
WT_General {} {Index, Version}
WT_CachedInitiatorInfo {} {Name}
WT_Snapshot {Create, Delete, ... {ExportedWTD, Id, OrigWTD, Status...}

That list alone shows that there’s a treasure trove of functionality beyond the cmdlets in the MicrosoftiSCSITarget module. But let’s focus on the problem at hand: differencing disks. I then looked at the details of the WT_Disk WMI class, which is used to manage the iSCSI Target Virtual Disks. So I put a single class name in the –List parameter and piped the result to Get-Member to see all static methods and properties.

PS C:> Get-WmiObject -Namespace "root/wmi" -List "WT_Disk" | Get-Member

   TypeName: System.Management.ManagementClass#ROOTwmiWT_Disk

Name MemberType Definition
---- ---------- ----------
Name AliasProperty Name = __Class
NewDiffWTDisk Method System.Management.ManagementBaseObject NewDiffWTDisk(System.String DevicePath, Sys...
NewWTDisk Method System.Management.ManagementBaseObject NewWTDisk(System.String DevicePath, System....
__CLASS Property System.String __CLASS {get;set;}
__DERIVATION Property System.String[] __DERIVATION {get;set;}
__DYNASTY Property System.String __DYNASTY {get;set;}
__GENUS Property System.Int32 __GENUS {get;set;}
__NAMESPACE Property System.String __NAMESPACE {get;set;}
__PATH Property System.String __PATH {get;set;}
__PROPERTY_COUNT Property System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH Property System.String __RELPATH {get;set;}
__SERVER Property System.String __SERVER {get;set;}
__SUPERCLASS Property System.String __SUPERCLASS {get;set;}
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime ScriptMethod System.Object ConvertToDateTime();

As you can see, there is a static method NewDiffWTDisk. Now I only need the complete definition with all the required parameters. A little more work on the output (focusing on methods only and formatting as a list) did the trick:

PS C:> Get-WmiObject -Namespace "root/wmi" -List "WT_Disk" | Get-Member -MemberType Method | Format-List

TypeName : System.Management.ManagementClass#ROOTwmiWT_Disk
Name : NewDiffWTDisk
MemberType : Method
Definition : System.Management.ManagementBaseObject NewDiffWTDisk(System.String DevicePath, System.String ParentPath, System.String Description, System.Boolean CacheParent)

TypeName : System.Management.ManagementClass#ROOTwmiWT_Disk
Name : NewWTDisk
MemberType : Method
Definition : System.Management.ManagementBaseObject NewWTDisk(System.String DevicePath, System.String Description, System.Boolean ClearPartTable, System.UInt32 SizeInMB)

You see we have two static methods for the WT_Disk class. One is the “NewWTDisk”, which maps closely to the functionality of the New-IscsiVirtualDisk cmdlet. The second is the “NewDiffWTDisk”, which creates a differencing disk. There’s a parameter to point to the parent (or base) VHD and an even more interesting parameter to tell whether we want to cache the parent VHD file in memory. This should come in handy to improve the target performance when using a single parent with multiple differencing disks. Make sure to specify a full file path for both the differencing and the parent, since the API does not take relative paths.

Now you have all you need to know to create an iSCSI Target 3.3 differencing VHD from an existing base. Just use the Get-WmiObject command syntax below:

(Get-WmiObject -Namespace "root/wmi" -List "WT_Disk").NewDiffWTDisk("<diff VHD path>","<base VHD path>","<description>",<cache parent?>)

Next, let’s go ahead and use the differencing disk feature to create an OS boot image, as an example. Before you create the differencing disk itself, you want to create a fixed-size Base.VHD, install an operating system on it, prepare it using sysprep and finally dismount it and/or remove any of its LUN mappings. In our case, I already had a Base.VHD file available, so had all I needed to create a Diff.VHD from it using NewDiffWTDisk:

PS C:> (Get-WmiObject -Namespace "root/wmi" -List "WT_Disk").NewDiffWTDisk("E:Diff.VHD","E:Base.VHD","Diff", $True)

__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : System.Management.ManagementBaseObject

Once the diff disk is created, you can use the regular PowerShell cmdlets to list it, associate with a target, etc.

PS C:> Import-Module MicrosoftIscsiTarget

PS C:> Get-IscsiVirtualDisk

Id : Server0.contoso.local:E:Diff.VHD
VirtualDiskIndex : 0
DevicePath : E:Diff.VHD
Description : Diff
Size : 10 GB
Status : Idle
Flags : None
SerialNumber : DDC8DEBA-C4F1-4AE5-B137-9CA530538AD8
SnapshotStorageSize : 0.00 B
LocalMountStatus : NotMounted
LastLocalMountTime : 12/31/1600 4:00:00 PM
LocalMountDeviceId :
LocalMountPaths : {}
Enabled : True
ComputerName : Server0.contoso.local
Version : 3.3.16543
ServerInfo : Server0.contoso.local

Note that the size is returned as 10 GB, which was the size of my base VHD. As you saw, the WMI method to create the differencing disk does not take a size parameter. The size property actually comes from the base VHD. Also note that the iSCSI Target does not use dynamically expanding VHD files, so your base VHD must be of fixed size. You can use the New-IscsiVirtualDisk PowerShell cmdlet to create the base VHD, since it’s just a regular fixed-sized VHD file. Just make sure you never mount the base VHD or expose it to an initiator after your create any diffs from it. Any changes to the base VHD will corrupt the differencing disk.

I hope you enjoyed this tip on how to use the iSCSI Target WMI classes to create a differencing VHD. You could do much more with those WMI classes, though. For instance, you could use them to manage iSCSI Target snapshots. But that’s a topic for another blog post…

If you are an MSDN or TechNet subscriber, find the details on how to obtain an evaluation copy of the Microsoft iSCSI Software Target 3.3 at https://blogs.technet.com/b/josebda/archive/2010/09/27/windows-storage-server-2008-r2-and-the-microsoft-iscsi-software-target-3-3-are-available-on-msdn-technet-here-s-how-to-install-them.aspx. For more details about Window Storage Server and the Microsoft iSCSI Software target, check the Windows Storage Server blog at https://blogs.technet.com/b/storageserver/ and the other posts on Windows Storage Server on this blog at https://blogs.technet.com/b/josebda/archive/tags/windows+storage+server/