PowerShell Function to Determine Available Drive Letters

I've recently been working on some file server drive migrations. One of the steps I needed to perform was to change the drive letter of a current drive to a different available drive letter so I decided to write a PowerShell function to accomplish the task of determining what drive letters are available.

The Get-MrAvailableDriveLetter function shown in the following code example will run on systems with PowerShell version 2.0 or higher (I tested it all the way down to version 1.0, but that was a no go).

 1#Requires -Version 2.0
 2function Get-MrAvailableDriveLetter {
 3
 4<#
 5.SYNOPSIS
 6    Returns one or more available drive letters.
 7
 8.DESCRIPTION
 9    Get-MrAvailableDriveLetter is an advanced PowerShell function that returns one or more available
10    drive letters depending on the specified parameters.
11
12.PARAMETER ExcludeDriveLetter
13    Drive letter(s) to exclude regardless if they're available or not. The default excludes drive letters
14    A-F and Z.
15
16.PARAMETER Random
17    Return one or more available drive letters at random instead of the next available drive letter.
18
19.PARAMETER All
20    Return all available drive letters. The default is to only return the first available drive letter.
21
22.EXAMPLE
23     Get-MrAvailableDriveLetter
24
25.EXAMPLE
26     Get-MrAvailableDriveLetter -ExcludeDriveLetter A-C
27
28.EXAMPLE
29     Get-MrAvailableDriveLetter -Random
30
31.EXAMPLE
32     Get-MrAvailableDriveLetter -All
33
34.EXAMPLE
35     Get-MrAvailableDriveLetter -ExcludeDriveLetter A-C, M, Q, T, W-Z -All
36
37.EXAMPLE
38     Get-MrAvailableDriveLetter -Random -All
39
40.EXAMPLE
41     Get-MrAvailableDriveLetter -ExcludeDriveLetter $null -Random -All
42
43.INPUTS
44    None
45
46.OUTPUTS
47    String
48
49.NOTES
50    Author:  Mike F Robbins
51    Website: http://mikefrobbins.com
52    Twitter: @mikefrobbins
53#>
54
55    [CmdletBinding()]
56    param (
57        [string[]]$ExcludeDriveLetter = ('A-F', 'Z'),
58
59        [switch]$Random,
60
61        [switch]$All
62    )
63
64    $Drives = Get-ChildItem -Path Function:[a-z]: -Name
65
66    if ($ExcludeDriveLetter) {
67        $Drives = $Drives -notmatch "[$($ExcludeDriveLetter -join ',')]"
68    }
69
70    if ($Random) {
71        $Drives = $Drives | Get-Random -Count $Drives.Count
72    }
73
74    if (-not($All)) {
75
76        foreach ($Drive in $Drives) {
77            if (-not(Test-Path -Path $Drive)){
78                return $Drive
79            }
80        }
81
82    }
83    else {
84        Write-Output $Drives | Where-Object {-not(Test-Path -Path $_)}
85    }
86
87}

It contains a requires statement and comment based help as all well written functions that you plan to share should:

 1#Requires -Version 2.0
 2function Get-MrAvailableDriveLetter {
 3
 4<#
 5.SYNOPSIS
 6    Returns one or more available drive letters.
 7
 8.DESCRIPTION
 9    Get-MrAvailableDriveLetter is an advanced PowerShell function that returns one or more available
10    drive letters depending on the specified parameters.
11
12.PARAMETER ExcludeDriveLetter
13    Drive letter(s) to exclude regardless if they're available or not. The default excludes drive letters
14    A-F and Z.
15
16.PARAMETER Random
17    Return one or more available drive letters at random instead of the next available drive letter.
18
19.PARAMETER All
20    Return all available drive letters. The default is to only return the first available drive letter.
21
22.EXAMPLE
23     Get-MrAvailableDriveLetter
24
25.EXAMPLE
26     Get-MrAvailableDriveLetter -ExcludeDriveLetter A-C
27
28.EXAMPLE
29     Get-MrAvailableDriveLetter -Random
30
31.EXAMPLE
32     Get-MrAvailableDriveLetter -All
33
34.EXAMPLE
35     Get-MrAvailableDriveLetter -ExcludeDriveLetter A-C, M, Q, T, W-Z -All
36
37.EXAMPLE
38     Get-MrAvailableDriveLetter -Random -All
39
40.EXAMPLE
41     Get-MrAvailableDriveLetter -ExcludeDriveLetter $null -Random -All
42
43.INPUTS
44    None
45
46.OUTPUTS
47    String
48
49.NOTES
50    Author:  Mike F Robbins
51    Website: http://mikefrobbins.com
52    Twitter: @mikefrobbins
53#>

Drive letters can be excluded via parameter input and by default A-F and Z are excluded. This can be negated by specifying $null or an empty string for the ExcludeDriveLetter parameter:

1[CmdletBinding()]
2param (
3    [string[]]$ExcludeDriveLetter = ('A-F', 'Z'),

By default only the first available drive letter is returned and it can be randomized by specifying the Random parameter:

1    [switch]$Random,

All available drive letters can be returned by specifying the All parameter and they can also be returned in random order with the Random parameter:

1    [switch]$All
2)

The drive letters themselves are obtained from the Function PSDrive:

1$Drives = Get-ChildItem -Path Function:[a-z]: -Name

The excluded drive letters are converted to a regular expression to minimize the amount of code that had to be written to exclude multiple drive letters and/or ranges of drive letters:

1if ($ExcludeDriveLetter) {
2    $Drives = $Drives -notmatch "[$($ExcludeDriveLetter -join ',')]"
3}

If the Random parameter is specified, all of the available drive letters are randomized once the exclusions are removed. This allows a single line of code to be used regardless if a single or all results are desired to be returned in randomized order:

1if ($Random) {
2    $Drives = $Drives | Get-Random -Count $Drives.Count
3}

Unless the All parameter is specified, the Return keyword is used to terminate execution once an available drive letter is found and tested to not be in use. Read more about the PowerShell Return keyword in a previous blog article that I've written.

1if (-not($All)) {
2
3    foreach ($Drive in $Drives) {
4        if (-not(Test-Path -Path $Drive)){
5            return $Drive
6        }
7    }
8
9}

If the All parameter is specified, all drive letters are tested and returned if they are not in use. This seemed to be the most efficient way to accomplish this task without testing all of them early on only to return a single result by default:

1else {
2    Write-Output $Drives | Where-Object {-not(Test-Path -Path $_)}
3}

The function itself is simple to use:

availabledriveletter1a.png

The Get-MrAvailableDriveLetter function shown in this blog article can be downloaded from my PowerShell repository on GitHub.

µ