PowerShell within CloudConfig – Disk Identification Formatting and Labelling
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.
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.
At a glance there is nothing particularly useful being provided by this command, however in the full output…
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.
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.
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