Changing Drive Letters and Labels via PowerShell

@DoctorDNS

Q: I want to change the drive letter and the drive label for a new USB drive. Is there a way with PowerShell?

A: Of course. One way is to use WMI and the CIM cmdlets.

PowerShell does not have a cmdlet to change the drive letter or the caption directly. But the good news is that you can use WMI and the CIM cmdlets to change both the drive letter and drive label. The Windows management tools have cmdlets (Set-Partition and Set-Volume) to change the drive letter and the caption directly. But it is also good to know how to do it via WMI and the CIM cmdlets to change both the drive letter and drive label. And under the covers, when you use Set-Partition, you are actually using WMI. Both the Windows Storage and Windows Networking teams make heavy use of WMI and expose cmdlets via CDXML modules. The *-Partition cmdlets are implemented by the CDXML Storage module.

WMI Classes, Class properties and Class Methods

WMI holds a huge amount of information about a Windows host in the form of WMI classes. Every IT professional should know about WMI.

WMI holds a hierarchical database of classes and class occurrences. These classes describe the hardware and software in your computer. This database is organized in to namespaces each which contains classes and, optionally, additional namespaces. You can use the CIM cmdlets to both retrieve and update this information.

For example, you can discover the drive letter and drive label for a drive from the Win32_Volume class. This class in in the rootCimV2 namespace.

Many WMI classes also contain methods that you can use to act on the WMI object. You can use the Format() method of the Win32_Volume class to format a Windows volume.

To obtain the values of the properties of a WMI class, or to invoke a class method, you can use the WMI cmdlets, which shipped with Windows PowerShell V1. However, these cmdlets no longer ship with PowerShell 7. Of course, a determined IT Pro could find a way around that – but you don’t have to!

With PowerShell 7, you use the CIM cmdlets to access this information. The CIM cmdlets first shipped with Windows PowerShell V3 and represented a major overhaul in how IT Pros access WMI. The newer cmdlets do the same job as the WMI cmdlets but have different cmdlets, and different ways of working as you can see in this article.

Discovering WMI Class Properties

You use the cmdlet Get-CimClass to discover the names (and type) of the properties of any given class. You can discover the properties of the Win32_Volume class like this:

Get-CimClass -ClassName Win32_Volume |
  Select-Object -ExpandProperty CimClassProperties |
    Sort-Object -Property Name |
      Format-Table Name, CimType, Qualifiers

The output from this commands looks like this:

Name                             CimType Qualifiers
----                             ------- ----------
Access                            UInt16 {read}
Automount                        Boolean {read}
Availability                      UInt16 {MappingStrings, read, ValueMap}
BlockSize                         UInt64 {MappingStrings, read}
BootVolume                       Boolean {read}
Capacity                          UInt64 {read}
Caption                           String {MaxLen, read}
Compressed                       Boolean {read}
ConfigManagerErrorCode            UInt32 {read, Schema, ValueMap}
ConfigManagerUserConfig          Boolean {read, Schema}
CreationClassName                 String {CIM_Key, read}
Description                       String {read}
DeviceID                          String {CIM_Key, read, key, MappingStrings, Override}
DirtyBitSet                      Boolean {read}
DriveLetter                       String {read, write}
DriveType                         UInt32 {MappingStrings, read}
ErrorCleared                     Boolean {read}
ErrorDescription                  String {read}
ErrorMethodology                  String {read}
FileSystem                        String {read}
FreeSpace                         UInt64 {read}
IndexingEnabled                  Boolean {read, write}
InstallDate                     DateTime {MappingStrings, read}
Label                             String {read, write}
LastErrorCode                     UInt32 {read}
MaximumFileNameLength             UInt32 {read}
Name                              String {read}
NumberOfBlocks                    UInt64 {MappingStrings}
PageFilePresent                  Boolean {read}
PNPDeviceID                       String {read, Schema}
PowerManagementCapabilities  UInt16Array {read}
PowerManagementSupported         Boolean {read}
Purpose                           String {read}
QuotasEnabled                    Boolean {read}
QuotasIncomplete                 Boolean {read}
QuotasRebuilding                 Boolean {read}
SerialNumber                      UInt32 {read}
Status                            String {MaxLen, read, ValueMap}
StatusInfo                        UInt16 {MappingStrings, read, ValueMap}
SupportsDiskQuotas               Boolean {read}
SupportsFileBasedCompression     Boolean {read}
SystemCreationClassName           String {CIM_Key, Propagated, read}
SystemName                        String {CIM_Key, Propagated, read}
SystemVolume                     Boolean {read}

In this list, you see each property of the Win32_Volume WMI class, the data type of the property and qualifiers. Qualifiers tell you more about the property – in particular whether a given property is read-only or read-write. The PageFilePresent property tells whether a given volume contains a Windows paging file. This property can not be changed using the CIM cmdlets. The DriveLetter and Label properties, on the other hand, are ones you can update. Let’s look at how you can change those properties.

Getting WMI properties

Suppose you want to change the volume label of a disk drive. In my host, the M: drive contains a collection of digitised music and my collection of thousands of Grateful Dead live concerts. I have been collecting for a long time and have a disk deadicated [SIC] to the task. But sometimes, when I plug in my USB backup drives to perform a backup, Windows changes the drive letter for me. To ensure my backup scripts work, I need to change it back so my backup scripts work properly.

To obtain the value of the drive label and drive letter, you can do this:

$Drive = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'M:'"
$Drive | Select-Object -Property SystemName, Label, DriveLetter

On my Windows 10 host (Cookham24), the output looks like this:

PS C:> $Drive | Select-Object -Property SystemName, DriveLetter, Label, DriveLetter

SystemName DriveLetter Label
---------- ----------- -----
COOKHAM24  M:          Master GD

Changing Drive Label

You saw above that both the drive label and the drive letter are writable properties. To change the label for this disk volume, you assign a new value to the label property of $Drive. Changing the property value updates the in-memory class instance which is not a permanent change. In order to persist the change, you need to use the Set-CimInstance CMDLET. Here is how you can change the drive label, and then confirm the change:

$Drive = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'M:'"
$Drive | Set-CimInstance -Property @{Label='Grateful Dead'}
Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'M:'" |
  Select-Object -Property SystemName, Label, DriveLetter

The output form this command, which shows the updated system label, looks like this

SystemName Label         DriveLetter
---------- -----         -----------
COOKHAM24  Grateful Dead M:  

Changing Drive Letter

To change the drive letter for a volume, you use Set-CimInstance to change the drive letter, like this:

$Drive = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'M:'"
$Drive | Set-CimInstance -Property @{DriveLetter ='X:'}

If you are running PowerShell 7 in a non-elevated session, this operation fails like this:

PS C:Foo> $Drive = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'M:'"
PS C:Foo> $Drive | Set-CimInstance -Property @{DriveLetter ='X:'}
Set-CimInstance: Access is denied.

This error is expected since you are not running PowerShell as an administrator. To overcome this error, re-run the command in an elevated session (run as administrator). Then your output looks like this:

PS C:Foo> $Drive = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'M:'"
PS C:Foo> $Drive | Set-CimInstance -Property @{DriveLetter ='X:'}
PS C:Foo> Get-Volume | Where-Object FileSystemLabel -eq 'Grateful Dead'

DriveLetter FriendlyName  FileSystemType DriveType HealthStatus OperationalStatus SizeRemaining    Size
----------- ------------  -------------- --------- ------------ ----------------- -------------    ----
X           Grateful Dead NTFS           Fixed     Healthy      OK                    591.78 GB 3.64 TB

Changing the drive letter can take a while – so be patient.

And as a final point – you can combine the two property updates in a single call to Set-CimInstance. To revert this drive to the old drive letter (M:) and it’s Label (GD Master) and confirm the change, you can do it like this:

$Drive = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = 'X:'"
$Drive | Set-CimInstance -Property @{DriveLetter = 'M:'; Label = 'GD Master'}

You can view the resulting change to drive letter and label using Get-Volume. The output should look this:

PS C:Foo> Get-Volume | Where-Object FileSystemLabel -match 'GD Master'
DriveLetter FriendlyName FileSystemType DriveType HealthStatus OperationalStatus SizeRemaining    Size
----------- ------------ -------------- --------- ------------ ----------------- -------------    ----
M           GD Master    NTFS           Fixed     Healthy      OK                    591.78 GB 3.64 TB

Note


One issue you may encounter when you change a drive letter then revert it as shown here. It appears that Windows holds on to the old drive letter and does not allow you revert it back immediately. Thus you may get a “Set-CimInstance: not available” error message when trying to revert the drive letter. To get around this, you have to reboot Windows – it appears just logging off and back on is not adequate.

Summary

Changing drive letters using PowerShell 7 is simple and straightforward. As you can see, using the Set-CimInstance PowerShell cmdlet to modify writable WMI properties is easy. I feel it’s more intuitive than making multiple property value assignments (once you you master the hash table). The cool thing is that multiple properties can be modified at one time instead of making multiple value assignments.

And as ever, this post shows there is often more than one way to achieve any aim.

Tip of the Hat

This article was inspired by an earlier Scripting Guys Blog post: Change drive letters and labels via a simple PowerShell command. That article was written by the most excellent Ed Wilson – thanks Ed!

8 comments

Discussion is closed. Login to edit/delete existing comments.

  • e.m. halap 0

    Hmm, I was quite sure I could do that with PowerShell anyway, without digging into WMI. Power to those who dare do it, but I’ve always been intimidated a bit by WMI. This is great help, thanks. I’ll probably be back here often.

  • ALIEN Quake 0

    “PowerShell does not have a cmdlet to change the drive letter or the caption directly”

    WRONG!

    “Changing drive letters using PowerShell 7 is simple and straightforward.”

    Sure it is when you do it properly:

    To change drive letter:

    Set-Partition -DriveLetter D -NewDriveLetter E

    To change drive name:

    Set-Volume -FileSystemLabel 'Data' -NewFileSystemLabel 'NewData'

    And that’s it!

    With all due respect, this article is wrong on so many levels. It is a great example of overengineering. It requires programming knowledge of objects, properties, hashtables, and internal features of Windows OS. It uses workarounds instead of standard and common measures to achieve the same goal. It shows a lack of PowerShell usage fundamentals as even Get-Command volume / drive / partition would give you a clue to handle this properly.

    And lastly, it will be an example for newcomers when they will compare PowerShell to other shells:
    “If simple things like changing drive letter or label require FOUR pages of explanation and hackiery, what about complicated things? PowerShell can’t be good!”

    Please always refresh your knowledge and get a second opinion before you publish a blog on official channels. Right now it is a guide for developers on how to use WMI. IMHO, putting this article into the PowerShell section is doing more harm than good. I would suggest moving it to ‘WMI’ section of some other ‘developer blogs’ section.

    • @DoctorDNS 0

      Thanks for the comment. I have updated the article although it’ll take a day or two to get the change online. You can read the PR here https://github.com/PowerShell/Community-Blog/pull/24 in the meantime.

      The reason for wanting to introduce WMI here is that, under the covers, the Storage Module is based on WMI anyway. Since I think Windows PowerShell 4, you have been able to use CDXML files to define cmdlets based on WMI classes. The Networking and Storage teams inside Windows make heavy use of this technology to release their WMI classes as cmdlets. So when you use Set-Volume, you are actually updating a WMI class via Volume.cdxml. The Storage module, for example, has 28 CDXML files for storage-related classes/cmdlets. I had intended to make this clear and I thank you for catching this.

      I note your other comments. If you have specific ideas for potential blog articles, please come over to GItHub and file an issue suggesting a topic. You can file an issue at https://github.com/PowerShell/Community-Blog/issues. There is an issue template for a suggested article and I’m really happy to see any specific suggestions. Even better if you want to write it or help write it.

      • Dwayne Gibbs 0

        @Thomas I commend you on the generous response to @Aliens’ comments regarding this first blog post. I am also thankful for the efforts made towards kicking this initiative off regarding a community improved PowerShell blogging experience.

        The interaction here goes to highlight beautiful differences that one can answer and solve a question one way while not wrong and another correct response to the same question can be provided in another way. Thus, teaching both old schoolers and new schoolers in the process. Though, I am still just getting started and will continue too until well, I get started. Is there a command for that? #Getting-Started 🙂

      • ALIEN Quake 0

        Thanks for updating the article. Now I understand the reason why you were so focused on WMI. You wanted to cover the lowest common denominator which works even for Windows 2008 R2, to cover the widest audience. My concerns were mainly about “How PS is viewed by newcomers”. Now I’m certain that it can be both ways: first, provide the most simple and straightforward way (notice that I didn’t even use | for the pipeline) so PS would appear neet. Then provide an alternative example to cover the widest audience of systems/solutions without necessarily focusing on simplicity. I will post this suggestion on GitHub for wider discussion.

    • Daniel Taylor 0

      Many organizations/enterprise, industry-wide is barely off PowerShell v2 and v3. I support customers globally, and I can count the number of customers using PowerShellv6/7 on one hand.

      Set-Partition 

      is only available after Windows PowerShell v5x as noted below

      Set-Partition
      
      ModuleType Name    PowerShellVersion CmdletName_FinctionName
      ---------- ----    ----------------- -----------------------
        Manifest Storage 5.1               Set-Partition          
      
      
      Get-Command -Name Set-Partition
      
      CommandType     Name           Version    Source        
      -----------     ----           -------    ------        
      Function        Set-Partition  2.0.0.0    Storage 

      So, you are valid relative to what WPSv5x and PSv7 provide, it does not apply to 80-90% of the rest of the world, or even the USA.

      So, though publishing this to a WMI specific forum is prudent, yet, Set-Partition should have been covered relative to v5/v7. It is just as important this info to be here for much of the world that is not on WPSv5x/PSv7 and who will not get there anytime soon.

      We can/should never assume that anyone is running the latest and greatest of anything (industry is always 5-10 years or more behind the release cycles), and should always write, show, explain code the lowest common (organization/enterprise/industry) denominator to the lastest, to cover the widest audience.

      • ALIEN Quake 0

        Agree. Now when I have seen the whole context, I believe that we can have the best of both worlds: the most simple and straightforward way for newcomers and alternative examples to cover the widest audience of systems/solutions.

    • Anonymous Vito Alvaerz 0

      Thanks for the heads up!!

Feedback usabilla icon