Using PowerShell to select Physical Disks for use with Storage Spaces

 

1. Introduction

 

If you use PowerShell to configure Storage Spaces, you probably noticed that selecting physical disks is an important part of the process.

You must select disks to create a pool and you might also need to do it also when you create a virtual disk using a subset of the disks.

 

2. Select all poolable disks

 

The simplest way to create a pool is to select all physical disks available that can be pooled.

The Get-PhysicalDisk cmdlet has a parameter to filter by the “CanPool” property for this exact purpose:

Get-PhysicalDisk -CanPool $true

You can also do the same thing by filtering the output by the “CanPool” property, which I find even simpler:

Get-PhysicalDisk | ? CanPool

 

3. Creating a pool

 

When creating a pool, you can use this cmdlet (in parenthesis) directly in the command line:

New-StoragePool -FriendlyName Pool1 -PhysicalDisk (Get-PhysicalDisk | ? CanPool)

Note that you will need additional parameters on your “New-StoragePool” cmdlet, like providing the storage subsystem or the default provisioning type. I removed those here to keep things simple and focused on how you select the physical disks.

Some people (particularly those with a programming background) might prefer to store the list of physical disks in a variable and use that variable in the other cmdlets.

$Disks = Get-PhysicalDisk | ? CanPool

New-StoragePool -FriendlyName Pool1 -PhysicalDisk $Disks

If you’re writing a complex script, creating the variable helps break tasks into smaller chunks that are hopefully easier to understand.

 

4. Filtering by other properties

 

If you have just a simple configuration, it might be OK to put all your disks in a single pool.

However, you might want to create separate pools for different purposes and that’s when you want to make sure you can select exactly the disks you want.

For instance, you might want to put half your SSDs in a “high performance” pool by themselves and put all your HDDs plus the other half of your SSDs in a second pool where you will use tiering.

Or maybe you will put all your 4TB, 7.2k rpm disks in one pool and all your 1TB 15K rpm disks in a second pool.

 

Here are a few ways to filter disks, shown as commands to create a $Disks variable that you could later use to create a pool or a virtual disk.

1: All the HDDs:
   $Disks = Get-PhysicalDisk | ? CanPool | ? MediaType –eq HDD

2: All disks of a certain size:
   $Disks = Get-PhysicalDisk | ? CanPool | ? Size –gt 1TB

3: A specific disk model:
   $Disks = Get-PhysicalDisk | ? CanPool | ? Model –like ST95*

4: Specific Serial Numbers:
   $Disks = Get-PhysicalDisk | ? {"6VEK9B89;a011c94e;13110930".Contains($_.SerialNumber)}

5: A certain quantity of SSDs:
   $Disks = Get-PhysicalDisk | ? CanPool | ? MediaType –eq SSD| Select –First 10

 

Most of the examples above show the use of simple comparisons using a property and a constant value.

I used a few tricks like using the Contains string function to match a list or using the –like operator for patter matching using * as a wildcard.

PowerShell is indeed a powerful language and there are many, many ways to filter or select from a list.

 

5. Complex scenarios with enclosures

 

I find that the most challenging scenarios for selecting disks involve the use of enclosures.

In those cases, you want to spread the disks across enclosures for additional fault tolerance when using the IsEnclosureAware property of the pool.

For instance, you might have 4 enclosures with 40 disks each and you want to create 2 pools, each with 20 disks from each enclosure.

That will require a little scripting, which I show below. You basically create a variable to keep the list of disks and add to it as you loop through the enclosures:

 

# To select 20 HDDs from each enclosure

$PDisks = @()

$HDDsPerE = 20

Get-StorageEnclosure | % {

   $EDisks = $_ | Get-PhysicalDisk –CanPool $true | ? MediaType –eq HDD |

             Sort Slot | Select –First $HDDsPerEnc

   If ($EDisks.Count –ne $HDDsPerE) {

      Write-Error “Could not find $HDDsPerE HDDs on the enclosure” –ErrorAction Stop

   }

   $PDisks += $EDisks

}

New-StoragePool -FriendlyName Pool1 -PhysicalDisk $PDisks -EnclosureAwareDefault $true

 

In the example above, the $PDisks variable will hold all disks to pool and the $EDisks hold the disks to pool from a specific enclosure.

We basically enumerate the enclosures and get a subset of the physical disks using the object filtering techniques we discussed previously.

Then we add the $EDisks variable to the $PDisks variable, which will accumulate disks from the various enclosures.

We finally use the $PDisks variable to actually create the pool. Note again that you will need more parameters in the cmdlet to create the pool, but that’s not our focus here.

 

For our final example, we’ll use 4 SSDs and 16 HDDs per enclosure. It’s somewhat similar to the example above, but it is a more realistic scenario if you are using tiering:

 

# To select 16 HDDs and 4 SSDs from each enclosure

$PDisks = @()

$HDDsPerE = 16

$SSDsPerE = 4

Get-StorageEnclosure | % {

   $EName = $_.FriendlyName

   $EDisks = $_ | Get-PhysicalDisk –CanPool $true | ? MediaType –eq HDD |

             Sort Slot | Select –First $HDDsPerE

   If ($EDisks.Count –ne $HDDsPerE) {

      Write-Error “Could not find $HDDsPerE HDDs on enclosure $EName ” –ErrorAction Stop

   }

   $PDisks += $EDisks

   $EDisks = $_ | Get-PhysicalDisk –CanPool $true | ? MediaType –eq SSD |

             Sort Slot | Select –First $SSDsPerE

   If ($EDisks.Count –ne $SSDsPerE) {

      Write--Error “Could not find $SSDsPerE SSDs on enclosure $EName ” –ErrorAction Stop

   }

   $PDisks += $EDisks

}

New-StoragePool -FriendlyName Pool1 -PhysicalDisk $PDisks -EnclosureAwareDefault $true

 

Conclusion

 

I am sure you will need to customize things for your own environment, but I hope this blog post has put you on the right track.

It might be a good idea to write a little function for disk selection, maybe with a few parameters to fit your specific requirements.

And always remember to test your scripts carefully before deploying anything in a production environment.