receives compensation from some of the companies listed on this page. Advertising Disclosure


Essential PowerShell Cmdlets For Auditing And Maintaining Storage

Adam Bertram

PowerShell v5 offers some new features for managing storage.

PowerShell v5 offers some new features for managing storage, building on the capabilities that were available in PowerShell 4.

In the days before PowerShell, managing disks via the command line was possible, but it wasn't easy and it certainly didn't feel like a unified experience. PowerShell makes storage management tasks not only much easier to accomplish as standalone tasks, but much easier to integrate into an automated workflow.

PowerShell makes storage management much easier by bringing all of the functions that used to be in lots of separate programs with their own syntax into a unified PowerShell experience with a standard syntax and support for the pipeline and other features for doing things in large groups instead of one at a time.

These cmdlets mostly started in PowerShell 4 but PowerShell 5 brings us some interesting new features for those thinking about server administration from the DevOps mindset of configuration as code where Desired State Configuration (DSC) is the order of the day and servers configure themselves based on our configuration scripts.

You can get a start on what's changed for PowerShell 5 here, and read more details about the *-item cmdlets support for different kinds of links here.

Now, let's take a look at some of the essential PowerShell cmdlets for auditing and maintaining storage.

Getting Disk Information

You might remember in the old days, if you wanted to get information about disks you opened a CMD window and used DISKPART. That meant launching the program, and using its syntax to navigate your way around. That's gone now and all we have to do is type a single PowerShell cmdlet to get the disk information we need.

PS C:\> Get-Disk

The Get-Disk cmdlet will return information about any disk attached to the current operating system, but we can use different cmdlets to get information about disks that are presented to us as either as physical disks or as virtual disks separately. We can use Get-PhysicalDisk to get information about disks the operating system sees as physical disks, and Get-VirtualDisk to see information about virtual disks created from storage pools, which you can also do in Azure. To see that information separately you can use the cmdlets as shown below.

Up to this point though we still don't know which drives we will see if we open the File Explorer. To see those we can use Get-Volume, or as I prefer since we don't care very much about CD-ROM disks or Floppy disks in virtual environments, we can use Get-Partition to look at the assigned drive letters and the physical disks they reside on.

You may have noticed that although there were three physical disks returned from Get-PhysicalDisk, there are only two volumes and two partitions returned in the output above. The reason for this is that I have attached a physical disk to this VM through the Azure management portal, but I haven't prepped that disk's storage space for use or assigned it a drive letter yet.

Using New Storage Space

The output returned from Get-PhysicalDisk showed us that Physical Disk number 2 had a partition style of RAW. If you're used to looking at the GUI that means it's Unallocated Space.

To turn this space into a drive we need to complete a few tasks, which is now easily done without resorting to clicking around with the mouse.

First we initialize the disk using the Initialize-Disk cmdlet.

PS C:\> Initialize-Disk -Number 2

That command won't return any output. It will just return control of the console when it's done. The next task is to create a new partition on the drive. We are actually going to create two partitions on this drive just to show how easy formatting is in the next step.

PS C:\> New-Partition -DiskNumber 2 -AssignDriveLetter -Size 500gb

PS C:\> New-Partition -DiskNumber 2 -AssignDriveLetter –UseMaximumSize

Now when we invoke Get-Partition we see the output below.

By invoking a single command twice we have allocated two new partitions on our disk. Despite having a drive letter though, you can't go charging off and putting folders and files on them just yet. We still need to format these disks.

To do that we will use Format-Volume, but when we use that cmdlet we are only going to invoke a single time to format both of these new drives. To find out how this is possible take a look at the screenshot below.

As I type the dash character for the first parameter, autocomplete shows me the parameters available for use. I hit the down arrow to highlight DriveLetter and the tooltip shows me the expected input type. In this case it can take a character array as input. With that in mind we'll give it the two drive letters we just created and it's going to format both drives for us in a single invocation.

PS C:\> Format-Volume -DriveLetter F,G -FileSystem NTFS

When the cmdlet returns control of the prompt we have two new drives ready for use. The one thing we didn't get to do when we formatted those volumes together instead of individually was assign them a label. We can fix that now using the Set-Volume cmdlet.

PS C:\> Set-Volume -DriveLetter F -NewFileSystemLabel "UserData"

We aren't going to label the G drive because we are going to use it to demonstrate the next two concepts, which will result in deleting it anyway. 

Shrinking, Expanding And Deleting Partitions

Doing these kinds of operations used to be something that involved lots of typing in DISKPART. Now with PowerShell the built-in cmdlets make shrinking, expanding and deleting partitions drop dead easy. We'll start by shrinking the G drive to match the F drive with the simple Resize-Partition cmdlet.

PS C:\> Resize-Partition -DriveLetter G -Size 500gb

That's all it takes to shrink a partition. But now let's say we want to get rid of it completely and then resize the F drive to take up the remaining space. We just invoke Remove-Partition on the G drive and then Resize-Partition on the F drive to expand it.

PS C:\> Remove-Partition -DriveLetter G

When we attempt to resize the remaining F partition to take up the remaining space, however we will run into a snag. Invoking Resize-Partition with the full drive size as a parameter we get an error as shown below.

Calculating drive sizes is rarely as exact as we might expect when dealing with computers. To solve this issue we can back off the size parameter in increments of .01gb until we find a size that works as shown below, and when we're done we have a single partition for the whole drive, ready for use.

PS C:\> Resize-Partition -DriveLetter F -Size 1022.87gb

Be careful about deleting and resizing partitions. Invoking these cmdlets will bring up warning dialogs for a reason. Deleting partitions will almost always result in data loss.

New Features In PowerShell v5

Most of the Storage module cmdlets are the same for PowerShell 5 as they were in PowerShell 4, but PS5 does have some new features to offer. 

The first one is out of the box support for the PowerShell Gallery. One of the great things the gallery has in store for us when dealing with storage is the xStorage module for PowerShell DSC. 

The xStorage module exposes the functionality of the Storage module cmdlets for use with DSC. This is powerful functionality because it allows us to express our configurations declaratively instead of in step by step scripts. To see an example let's delete all of the partitions from disk 2 and for simplicity sake we will configure the drive with the single large volume we ended up with at the end of the previous section.

PS C:> Get-Partition -DiskNumber 2 | Remove-Partition

Now, invoke the following command to install the xStorage module.

PS C:> Install-Module xStorage

To confirm the installation run the following command and see that there are three new resources grouped under a new Module called xStorage.

PS C:> Get-DSCResource

After confirming the installation we can begin writing and executing the following script.

Configuration DataDisks
    Import-DscResource -ModuleName xStorage
    Node Localhost
        xWaitForDisk Disk2
            DiskNumber = 2
            RetryIntervalSec = 60
            RetryCount = 60
        xDisk GVolume
            DiskNumber = 2
            DriveLetter = 'G'
            FSLabel = 'UserData'
DataDisks -outputpath c:DataDisks
Start-DscConfiguration -Path c:dataDisks -wait -force -Verbose

After a lot of verbose output you will have a disk with the new drive letter and label you expect. That script is just a small example of what can be incorporated into a larger DSC script that configures an entire machine.

Another new feature in PowerShell v5 is in an unexpected place. Instead of a new cmdlet we are going to look at the humble New-Item cmdlet.  New-Item now supports symbolic links and hard links. Here's an oldish writup on the kinds of symbolic links in Windows, but don't worry about the syntax for creating them because PowerShell is going to make this easy.

First we will create a target file in our documents directory with the following script.

PS C:> "Test Data" | Out-File -FilePath $env:USERPROFILEdocumentstestFile.txt

Now we will use the improved New-Item cmdlet in PowerShell 5 to create a symlink as shown in the screenshot below.

That file is zero bytes and if you look at its icon in the file explorer you will see a shortcut because that's exactly what it is.

Now we can create a Hard Link to the same file and see what that looks like in the next screenshot.

This new file has a length that matches the file we linked to. If you open this new file and edit its contents and then close it and open the original file you will find its contents altered as well. 

We can do some powerful things with links like this, but one thing that might bite us in the future is once these links are set up, you can't always tell easily by looking in a file explorer window what is a link and what is real. Fortunately, PowerShell can show us much easier what is a link and what is real. 

If we create a new file at the top level of the c: drive we can see the differences immediately because the Get-ChildItem cmdlet will show us immediately, as we can see below.

Administering servers with PowerShell is getting better and better, and storage management is just one facet of the awesomeness. Keep exploring and happy PowerShelling. 

Image Credit: Undrey/Shutterstock
Adam Bertram Contributing Writer
Adam Bertram is a 20-year veteran of IT and experienced online business professional. He's an entrepreneur, IT influencer, Microsoft MVP, blogger, trainer and content marketing writer for multiple technology companies. Adam is also the founder of the popular IT career development platform TechSnips. Catch up on Adam's articles at, connect on LinkedIn, or follow him on Twitter at @adbertram or the TechSnips Twitter account at @techsnips_io.