cOnlineAllDisks.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 cOnlineAllDisks { <# 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]::MBR <# This is a JSON representation of an array of drives using a PSCustomObject Object format is: DriveLetter DriveSize AllocUnit ----------- --------- --------- D 512 64 Q 1024 R 512 Typically, a new DriveArray is created via: $VMDiskArray = "D:512@64,Q:1024,R:512" $DiskArray = @() $VMDiskArray.Split(",") | ForEach-Object { $driveLetter = $_.split(':')[0] $DriveSize = $_.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. #> [cOnlineAllDisks] Get() { $this.Name = $Env:COMPUTERNAME #This is the default PartitionType $this.PartitionType = [PartitionType]::MBR #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 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" 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" } #Initializing Raw disks if (-not $this.PartitionType) {$this.PartitionType = [PartitionType]::MBR} $RawDisks = Get-Disk | Where-Object { $_.partitionstyle -eq 'raw' } | Sort-Object {$_.Number } if ($RawDisks -ne $Null) { $RawDisks | ForEach-Object { $DiskNumber = $_.Number Write-Verbose ("OnlineDisks:Set - Initializing RAW Disk $DiskNumber as " + ($this.PartitionType.ToString())) Initialize-Disk -Number $DiskNumber -PartitionStyle ($this.PartitionType.ToString()) } } else { Write-Verbose "OnlineDisks:Set - All disks initialized" } #Partition disks with no partitions Get-Disk | Sort-Object {$_.Number} | ForEach-Object { $DiskNumber = $_.Number $Part = Get-Partition -DiskNumber $DiskNumber -ErrorAction SilentlyContinue if ($Part -eq $null) { $NextDrive = $this.GetNextDisk() if ($NextDrive -ne $null) { Write-Verbose ("OnlineDisks:Set - Partitioning Disk $DiskNumber as " + $NextDrive.DriveLetter) New-Partition -DiskNumber $DiskNumber -DriveLetter $NextDrive.DriveLetter -UseMaximumSize } else { throw "No more drive letters" } } } #Format partitions that are not formatted Get-Volume | Where-Object {$_.DriveType -eq "fixed"} | Where-Object {$_.Size -eq 0} | ForEach-Object { $CurDriveLetter = $_.DriveLetter $curDrive = $This.DriveArray.Where({$_.Driveletter -eq $CurDriveLetter},'default') if ($curDrive -eq $null -or $curDrive.AllocUnit -eq $null -or $curDrive.AllocUnit -eq "") { $DriveNumber = (Get-Partition -DriveLetter $CurDriveLetter).DiskNumber if ($This.UseDriveLetterInVolumeName) { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveNumber/$CurDriveLetter using default allocation unit using label " + ($CurDriveLetter + "_Drive")) Format-Volume -DriveLetter $CurDriveLetter -FileSystem NTFS -NewFileSystemLabel ($CurDriveLetter + "_Drive") -Confirm:$false } else { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveNumber/$CurDriveLetter using default allocation unit using label " + ("Disk" + $DriveNumber)) Format-Volume -DriveLetter $CurDriveLetter -FileSystem NTFS -NewFileSystemLabel ("Disk" + $DriveNumber) -Confirm:$false } } else { #Format with our allocation units $DriveNumber = (Get-Partition -DriveLetter $CurDriveLetter).DiskNumber if ($This.UseDriveLetterInVolumeName) { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveNumber/$CurDriveLetter with allocation of " + ([int]$curDrive.AllocUnit) + " kb using label " + ($CurDriveLetter + "_Drive") ) Format-Volume -DriveLetter $CurDriveLetter -FileSystem NTFS -NewFileSystemLabel ($CurDriveLetter + "_Drive") ` -AllocationUnitSize ( ([int]$curDrive.AllocUnit) * 1024) -Confirm:$false } else { Write-Verbose ("OnlineDisks:Set - Formatting drive $DriveNumber/$CurDriveLetter with allocation of " + ([int]$curDrive.AllocUnit) + " kb using label " + ("Disk" + $DriveNumber) ) Format-Volume -DriveLetter $CurDriveLetter -FileSystem NTFS -NewFileSystemLabel ("Disk" + $DriveNumber) ` -AllocationUnitSize ( ([int]$curDrive.AllocUnit) * 1024) -Confirm:$false } } Write-Verbose "OnlineDisks:Set - Successfully formatted drive $DriveNumber/$CurDriveLetter" } } catch { $ErrorMessage = $_.Exception.Message Write-Verbose "ERROR: $ErrorMessage" } finally { Write-Verbose "OnlineDisks:Set - End" } } [string] GetNextDriveLetter() { Write-Debug "GetNextDriveLetter - Start" try { $array2 = @() if ( $this.DiskLetterArray -and $this.DiskLetterArray.Count -gt 0) { #Use from our letter list $NextDriveLetter = $this.DiskLetterArray[0] #Move all the letters up one for ($i = 1; $i -lt $this.DiskLetterArray.Count; $i++) { $array2 += $this.DiskLetterArray[$i] } $this.DiskLetterArray = $array2 return $NextDriveLetter } else { $AllDrives = [char[]]([char]'C'..[char]'Z') $CurrentDriveList = (Get-Volume).DriveLetter $NextDriveLetter = $AllDrives | Where-Object { $CurrentDriveList -notcontains $_ } | Select-Object -First 1 Write-Debug "GetNextDriveLetter - Next Drive Letter '$NextDriveLetter'" return $NextDriveLetter } } finally { Write-Debug "GetNextDriveLetter - End" } } [PSCustomObject] GetNextDisk () { Write-Debug "GetNextDisk - Start" try { $CurrentDriveList = (Get-Volume).DriveLetter $RemainingDriveArray = $This.DriveArray.Where({$_.Driveletter -notin $CurrentDriveList},'default') if ( $RemainingDriveArray.Count -gt 0) { #Return our first Remaining Drive Write-Verbose ("GetNextDisk - Next Drive '" + $RemainingDriveArray[0] + "'") Return $RemainingDriveArray[0] } else { $AllDrives = [char[]]([char]'C'..[char]'Z') $CurrentDriveList = (Get-Volume).DriveLetter $NextDriveLetter = $AllDrives | Where-Object { $CurrentDriveList -notcontains $_ } | Select-Object -First 1 Write-Verbose "GetNextDisk - Next Drive Letter '$NextDriveLetter'" $NewDrive = [PSCustomObject]@{ DriveLetter = $NextDriveLetter DriveSize = 0 AllocUnit = $Null } return $NewDrive } } finally { Write-Debug "GetNextDisk - End" } } } # This module defines a class for a DSC "cOnlineAllDisks" provider. |