PowerShell within CloudConfig – Disk Identification Formatting and Labelling

  • simon 

In a previous post I’d worked through a few issues with formatting and labelling disks with PowerShell and part of a CloudConfig element.  I had someone get in touch with a similar issue linked to how they could use PowerShell within CloudConfig to provide Disk Identification Formatting and Labelling, for disks being added across multiple SCSI controllers.

Thanks again to Dean and Chris, for providing environments for me to test against and validating the logic.

The problem they described was that, through the Cloud Assembley blueprint that could control the sequence that drives where attached when aligned to an individual SCSI controller.  However, when mulitple controllers are part of the blueprint the Windows image being built appears to attach the SCSI controllers in a random order.  This results in the disk numbering being out of sequence.

For example, below we see the a virtual machine with six hard drives attached aligned across four SCSI controllers. For simplicity, the 1GB drive maps to SCSI 1:1, the 2GB Drive to 2:2, and the 3GB, 4GB and 5GB drives to 3:3, 3:4 and 3:5.

The placement coresponds to the SCSI controller and the unit numbers allocated in the Cloud Assembly blueprint, an extract of which is below.

Cloud_vSphere_Disk_1:
  type: Cloud.vSphere.Disk
  properties:
    capacityGb: 1
    name: Disk labelE
    driveLetter: E
    SCSIController: SCSI_Controller_1
    unitNumber: 1
Cloud_vSphere_Disk_2:
  type: Cloud.vSphere.Disk
  dependsOn:
    - Cloud_vSphere_Disk_1
  properties:
    capacityGb: 2
    name: Disk labelF
    driveLetter: F
    SCSIController: SCSI_Controller_2
    unitNumber: 2
Cloud_vSphere_Disk_3:
  type: Cloud.vSphere.Disk
  dependsOn:
    - Cloud_vSphere_Disk_2
    - Cloud_vSphere_Disk_1
  properties:
    capacityGb: 3
    name: Disk labelG
    driveLetter: G
    SCSIController: SCSI_Controller_3
    unitNumber: 3
Cloud_vSphere_Disk_4:
  type: Cloud.vSphere.Disk
  dependsOn:
    - Cloud_vSphere_Disk_3
  properties:
    capacityGb: 4
    name: Disk labelH
    driveLetter: H
    SCSIController: SCSI_Controller_3
    unitNumber: 4
Cloud_vSphere_Disk_5:
  type: Cloud.vSphere.Disk
  dependsOn:
    - Cloud_vSphere_Disk_4
  properties:
    capacityGb: 5
    name: Disk labelI
    driveLetter: I
    SCSIController: SCSI_Controller_3
    unitNumber: 5

So far so good, until looking at how that has been interpretted on the Windows VM.

PowerShell within CloudConfig - Disk Identification Formatting and Labelling

SCSI 3:3, 3:4 and 3:5 have been attached as disks 1, 2 and 3.  SCSI1:1 as Disk 4 and SCSI 2:2 as Disk 5.  Unfortunately, what this means is that if for example we’re passing the unitNumber property into a CloudConfig PowerShell script to format the drives, the OS drive numbers are not going to match the allocated unitNumber. In the BluePrint unitNumber 3, 4 and 5 are mapping to disknumber 1, 2 and 3 in the OS.

The problem is now how can it be ensured that the correct labels and formatting options are applied to the disks, when with multiple SCSI controllers the system can no longer guarantee the order that the OS will attach the drives.

PowerShell within CloudConfig – Disk Identification Formatting and Labelling

The BluePrint contains information about the SCSI controllers and the size of the disks that are being attached, because they are either being defined in the properties or via inputs.  This  information can be used in the CloudConfig section to create variables that will map to the desired disk objects.

$s = ${resource.Cloud_vSphere_Disk_1[0].capacityGb}

Firstly we’re going to capture the capactiy information from the property into a PowerShell variable, the reason for doing this is so that we can easily concantenate the size information within another variable that will be assigned.

$u = Get-Disk | where-object {$_.Location -match "SCSI3" -and $_.Size -match $sGB}

Here is where we are setting that other variable.

This is using the Get-Disk cmdlet to collect information about the appropriate disk, by aligning disk location, in terms of SCSI controller, with the expected size. Concantenating the size variable with the text “GB” as this is the expected string format in the Windows OS for the size value returned by Get-Disk.

An example of the output from this command is below.

PowerShell within CloudConfig - Disk Identification Formatting and Labelling

At a glance there is nothing particularly useful being provided by this command, however in the full output…

PowerShell within CloudConfig - Disk Identification Formatting and Labelling

There are a lot more values of interest including a -UniqueId that can be passed into a New-Partition command as a replacement for -DiskNumber, which as observed above is not mapping as desired.

PowerShell within CloudConfig - Disk Identification Formatting and Labelling

With the -UniqueId value being captured, this can be passed into the New-Partition PowerShell section of the script from the previous post.

$s = ${resource.Cloud_vSphere_Disk_3[0].capacityGb}
$u = Get-Disk | where-object {$_.Location -match "SCSI3" -and $_.Size -match $sGB}
New-Partition -DiskId $u.UniqueId -DriveLetter ${resource.Cloud_vSphere_Disk_3[0].driveLetter} -UseMaximumSize
Format-Volume -DriveLetter ${resource.Cloud_vSphere_Disk_3[0].driveLetter} -FileSystem NTFS -AllocationUnitSize 4096 -Force -Confirm:$false
Set-Volume -DriveLetter ${resource.Cloud_vSphere_Disk_3[0].driveLetter} -NewFileSystemLabel "${resource.Cloud_vSphere_Disk_3[0].name}"

The above is the CloudConfig PowerShell section example.  With this example each disk is being handled in a different section of CloudConfig.

The variable $s is assigned from the resource property size information and the variable $u is assigned from that size information and knowledge of the correct SCSI Location. I’m sure the SCSI location could be programatically mapped via equality operators to map the Cloud Assembly SCSI value of SCSI_Controller_x to the windows OS value of SCSIx, but as a quick example it was just as easy to manually add this in the CloudConfig element.

The New-Partition cmdlet now works based on the -DiskID, which is being passed via $u.UniqueId.  Nothing else in the script changes from what was previously posted.

PowerShell within CloudConfig - Disk Identification Formatting and Labelling

The above image shows the script working, SCSI ID 1:1 is being attached as Disk4 but via the script the correct formating and labels are being enforced.

N.B.  This method will only work if all the presented disks on the SCSI Controller are of different sizes, if this is the case then there would need to be a third point of reference that could be passed into the Get-Disk cmdlet…

Hopefully this is useful to someone…

Thanks

Simon