cOnlineAllDisksWithPools.psm1
enum PartitionType { GPT MBR } <# This resource ensures all disks are online, read/write, partitioned and formatted [DscResource()] indicates the class is a DSC resource #> [DscResource()] class cOnlineAllDisksWithPools { <# This property is the name of the system - its not used for anything other than they key. #> [DscProperty(Key)] [string]$Name [DscProperty()] [PartitionType]$PartitionType = [PartitionType]::GPT <# This is a JSON representation of an array of drives using a PSCustomObject Object format is: DriveLetter DriveLun AllocUnit ----------- --------- --------- D 0 64 Q 1+2 R 3 Typically, a new DriveArray is created via: $VMDiskArray = "D:0@64,Q:1+2,R:3" #Format is <Letter>:<Lun>@Alloc #LunSize can be <lun>+<Lun> for disk pooling $DiskArray = @() $VMDiskArray.Split(",") | ForEach-Object { $driveLetter = $_.split(':')[0] $DriveLuns = $_.split(':')[1].Split('@')[0] $AllocUnit = $_.split(':')[1].Split('@')[1] $DiskObject = [PSCustomObject]@{ DriveLetter = $DriveLetter DriveSize = $DriveSize AllocUnit = $AllocUnit } $DiskArray += $DiskObject } This should be passed via $DiskArray | ConvertTo-Json #> [DscProperty()] [string] $DriveArrayInJSON [PSCustomObject[]] $DriveArray <# This toggles the volume lable between "Disk1" and "E_Drive" #> [DscProperty()] [Bool]$UseDriveLetterInVolumeName = $False <# This method is equivalent of the Get-TargetResource script function. The implementation should use the keys to find appropriate resources. This method returns an instance of this class with the updated key properties. #> [cOnlineAllDisksWithPools] Get() { $this.Name = $Env:COMPUTERNAME #This is the default PartitionType $this.PartitionType = [PartitionType]::GPT #Convert from Json try { $this.DriveArray = $This.DriveArrayInJSON | ConvertFrom-Json } catch { throw "Invalid DriveArrayInJSON" } return $this } <# This method is equivalent of the Test-TargetResource script function. It should return True or False, showing whether the resource is in a desired state. #> [bool] Test() { Write-Verbose "OnlineDisks:Test - Start" Write-Verbose "OnlineDisks:Test - Start - UseDriveLetterInVolumeName: $This.UseDriveLetterInVolumeName" #Default to PASS $TestResult = $true try { #See if we have any offline disks $OfflineDisks = Get-Disk | Where-Object {$_.IsOffline -eq $true} if ($OfflineDisks -ne $null) { Write-Verbose "OnlineDisks:Test - Found an offline disk" $TestResult = $false } #See if we have any RAW partitions $RawDisks = Get-Disk | Where-Object { $_.partitionstyle -eq 'raw' } #Any raw disks means we need to run SET if ($RawDisks -ne $null) { Write-Verbose "OnlineDisks:Test - Found a RAW disk" $TestResult = $false } #Now see if any disks have no partitions Get-Disk | Sort-Object { $_.Number } | ForEach-Object { $Part = (Get-Partition -DiskNumber $_.Number -ErrorAction SilentlyContinue | Where-Object {$_.Type -ne "Reserved"}) if ( $Part -eq $null ) { Write-Verbose "OnlineDisks:Test - Found an unpartitioned disk" $TestResult = $false } } #Finally, see if any volumes need to be formatted Get-Volume | Where-Object {$_.DriveType -eq "fixed"} | ForEach-Object { if ($_.Size -eq 0) { Write-Verbose "OnlineDisks:Test - Found an unformatted disk" $TestResult = $false } } #All tests run, return results return $TestResult } finally { Write-Verbose "OnlineDisks:Test - End" } } <# This method is equivalent of the Set-TargetResource script function. It sets the resource to the desired state. #> [void] Set() { Write-Verbose "OnlineDisks:Set - Start" $DiskPoolToken = '\+' try { #Convert from Json try { $this.DriveArray = $This.DriveArrayInJSON | ConvertFrom-Json } catch { throw "Invalid DriveArrayInJSON" } #Online all disks $OfflineDisks = Get-Disk | Where-Object {$_.IsOffline -eq $true} if ($OfflineDisks -ne $null ) { $OfflineDisks | ForEach-Object { $DiskNumber = $_.DiskNumber Write-Verbose "OnlineDisks:Set - Onlining disk $DiskNumber" Set-Disk -InputObject $_ -IsOffline $false Write-Verbose "OnlineDisks:Set - Setting disk $DiskNumber to Read/Write" Set-Disk -InputObject $_ -IsReadOnly $false } } else { Write-Verbose "OnlineDisks:Set - All disks online" } #Loop through each disk $DiskCount = 1 $this.DriveArray | ForEach-Object { $DriveLetter = $_.DriveLetter $DriveLuns = $_.DriveLun $AllocUnit = [int]$_.AllocUnit * 1024 If ($DriveLuns -match "$DiskPoolToken") { #This is a pool, get the array of disks $LunArray = $DriveLuns -split '\+' $PhysDisks = Get-PhysicalDisk | Where-Object { $LunArray -contains $_.DeviceID} $StorageName = (Get-StorageSubSystem).FriendlyName $PoolName = ("Pool_" + $DriveLetter) #Set up our pool Write-Verbose ("OnlineDisks:Set - Creating new pool '$PoolName' on '$StorageName' using LUN's '$DriveLuns'.") New-StoragePool -FriendlyName $PoolName ` -StorageSubSystemFriendlyName $StorageName ` -PhysicalDisks $PhysDisks #Set up our Virtual Disk $DiskLabel = ("Disk" + $DiskCount) Write-Verbose ("OnlineDisks:Set - Creating new Virtual Disk '$DiskLabel' on pool '$PoolName'.") New-VirtualDisk -StoragePoolFriendlyName $PoolName ` -FriendlyName $DiskLabel ` -ResiliencySettingName "Simple" ` -Interleave 65536 ` -NumberOfColumns $LunArray.count ` -ProvisioningType Fixed ` -UseMaximumSize #Initialize Disk $NewDisk = Get-VirtualDisk -FriendlyName $DiskLabel | Get-Disk if ( ($this.PartitionType -EQ [PartitionType]::MBR) -and ( ($NewDisk.Size/1GB) -GT 2048) ) { #MBR doesn't support more than 2048 - force GPT Write-Verbose ("OnlineDisks:Set - Initalizing Disk '$DiskLabel' using 'GPT'.") Initialize-Disk -Number $NewDisk.Number -PartitionStyle GPT } else { Write-Verbose ("OnlineDisks:Set - Initalizing Disk '$DiskLabel' using '" + ($this.PartitionType.ToString()) + "'.") Initialize-Disk -Number $NewDisk.Number -PartitionStyle ($this.PartitionType.ToString()) } #Partition Write-Verbose ("OnlineDisks:Set - Partitioning Pool $PoolName as '" + $DriveLetter + "'") New-Partition -DiskNumber $NewDisk.Number -DriveLetter $DriveLetter -UseMaximumSize #Format if ($This.UseDriveLetterInVolumeName) { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveLetter using default allocation unit using label " + ($DriveLetter + "_Drive")) Format-Volume -DriveLetter $DriveLetter -FileSystem NTFS -NewFileSystemLabel ($DriveLetter + "_Drive") -Confirm:$false -AllocationUnitSize $AllocUnit } else { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveLetter using default allocation unit using label '$DiskLabel'") Format-Volume -DriveLetter $DriveLetter -FileSystem NTFS -NewFileSystemLabel $DiskLabel -Confirm:$false -AllocationUnitSize $AllocUnit } } else { #Initalize Disk Write-Verbose ("OnlineDisks:Set - Initializing RAW Disk $DiskNumber as " + ($this.PartitionType.ToString())) if ( ($this.PartitionType -EQ [PartitionType]::MBR) -and ( ($_.Size/1GB) -GT 2048) ) { #MBR doesn't support more than 2048 - force GPT Initialize-Disk -Number $DriveLuns -PartitionStyle GPT } else { Initialize-Disk -Number $DriveLuns -PartitionStyle ($this.PartitionType.ToString()) } #Partition disks Write-Verbose ("OnlineDisks:Set - Partitioning Disk $DriveLuns as " + $DriveLetter) New-Partition -DiskNumber $DriveLuns -DriveLetter $DriveLetter -UseMaximumSize #Format $DiskLabel = ("Disk" + $DiskCount) if ($This.UseDriveLetterInVolumeName) { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveLetter using default allocation unit using label " + ($DriveLetter + "_Drive")) Format-Volume -DriveLetter $DriveLetter -FileSystem NTFS -NewFileSystemLabel ($DriveLetter + "_Drive") -Confirm:$false -AllocationUnitSize $AllocUnit } else { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveLetter using default allocation unit using label '$DiskLabel'") Format-Volume -DriveLetter $DriveLetter -FileSystem NTFS -NewFileSystemLabel $DiskLabel -Confirm:$false -AllocationUnitSize $AllocUnit } } $DiskCount += 1 } } catch { $ErrorMessage = $_.Exception.Message Write-Verbose "ERROR: $ErrorMessage" } finally { Write-Verbose "OnlineDisks:Set - End" } } } # This module defines a class for a DSC "cOnlineAllDisks" provider. |