diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fa6570 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.code-workspace +.vscode \ No newline at end of file diff --git a/.vscode/ltex.hiddenFalsePositives.en-US.txt b/.vscode/ltex.hiddenFalsePositives.en-US.txt new file mode 100644 index 0000000..9569d9f --- /dev/null +++ b/.vscode/ltex.hiddenFalsePositives.en-US.txt @@ -0,0 +1,7 @@ +{"rule":"MORFOLOGIK_RULE_EN_US","sentence":"^\\QThe script can coerce them to be MediaType:HDD\nThe entire virtual drive is added to the system as a single large volume\nYou need at least\n1 SSD and 1 HDD to run cached storage / Simple resiliency\n2 SSD and 2 HDDs to run cached storage / Mirror resiliency /\n1 SSD and 2 HDDs to run cached storage / Simple resiliency / striped storage (sum of HDD space)\\E$"} +{"rule":"ENGLISH_WORD_REPEAT_RULE","sentence":"^\\QSimple Mirrored Mirrored and Striped\\E$"} +{"rule":"MASS_AGREEMENT","sentence":"^\\QThe HDD drive media types are not recognized.\\E$"} +{"rule":"MORFOLOGIK_RULE_EN_US","sentence":"^\\QCredits\nMost of the script came from this great blog article by Nils Schimmelmann\nSee Joe's blog for any updates\\E$"} +{"rule":"MORFOLOGIK_RULE_EN_US","sentence":"^\\QResiliancyName: Simple vs Mirror\nThe “Mirror” resiliency level attempts to mirror both SSD and HDD tiers, so you would need 4 drives run mirror, to mirror both tiers\\E$"} +{"rule":"MORFOLOGIK_RULE_EN_US","sentence":"^\\QRemove-TieredStorageSpace.ps1\nRemoves the virtual drive, the storage tiers and then the storage pool.\\E$"} +{"rule":"MORFOLOGIK_RULE_EN_US","sentence":"^\\QScripts\nNew-TieredStorageSpace.ps1\nCreates a tiered storage pool and allocates all the disk space to a single drive\nYou can change the drive letter and label by editing the variables at the top.\\E$"} diff --git a/New-TieredStorageSpace.ps1 b/New-TieredStorageSpace.ps1 new file mode 100644 index 0000000..05e1c52 --- /dev/null +++ b/New-TieredStorageSpace.ps1 @@ -0,0 +1,167 @@ +# RUN AS ADMINISTRATOR +# https://nils.schimmelmann.us/post/153541254987/intel-smart-response-technology-vs-windows-10 +#Tested with one SSD and two HDD +#Requires -RunAsAdministrator + +[CmdletBinding()] +param ( + [Parameter(Mandatory = $False, ValueFromPipeline = $True)] + [string[]] + $ConfigFile +) + +Begin{ + #Initialize Variables + $Script:StorageSpacesParams = @() + #Makes $PhysicalDisks a hashtable for easier management. + $PhysicalDisks = @() + $Script:TieredDiskName + + + function defaultPrompt { + if ($null -eq $ConfigFile) { + $DefaultPrompt = Read-Host = "Would you like to load the default values to the config file? (Y/N)" + + if ($DefaultPrompt.ToUpper() -eq "Y" ) { + $Script:StorageSpacesParams = setDefaultValues + $Script:StorageSpacesParams | ConvertTo-Json | Out-File $PSScriptRoot + "\TieredStorageSpace-Config.json" + } + elseif ($DefaultPrompt.ToUpper() -eq "N") { + Read-Host "Ether pass the config file to the script or use default values. Exiting..." + Exit + } + else { + Write-Output "Invalid Selection. Try Again." + defaultPrompt + } + } + if ($null -ne $ConfigFile) { + #This will load all values from the $ConfigFile var to $Script:StorageSpacesParams. + $PSversion = $PSVersionTable.PSVersion.Major + if ($PSversion -le "5") { + $ConfigObj = $ConfigFile | ConvertFrom-Json + foreach ($obj in ($ConfigObj.StorageSpace | Get-Member * -MemberType NoteProperty).Name) { + $Script:StorageSpacesParams =+ $($ConfigObj.StorageSpace.$obj) + } + + } + elseif ($PSversion -ge "6") { + $Script:StorageSpacesParams = $ConfigFile | ConvertFrom-Json -AsHashtable + } + else { + Read-Host "Invalid PS Version. Exiting..." + Exit + } + + } + } + function setDefaultValues { + @{ + #Pool that will suck in all drives + StoragePoolFriendlyName = "My Storage Pool" + #Virtual Disk Name made up of disks in both tiers + TieredDiskName = "My Tiered VirtualDisk" + #Simple = striped. Mirror only works if both can mirror AFIK + #https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/dn387076(v=ws.11) + DriveTierResiliency = "Simple" + #Change to suit - drive later and the label name + DriveLetter = "Z" + NewFileSystemLabel = "StorageDrive" + #Override the default sizing here - useful if have two different size SSDs or HDDs - set to smallest of pair + #These must be Equal or smaller than the disk size available in that tier SSD and HDD + #SSD:cache - HDD:data + #set to null so copy/paste to command prompt doesn't have previous run values + SSDTierSize = $null + HDDTierSize = $null + #Drives cannot always be fully allocated - probably broken for drives < 10GB + UsableSpace = 0.98 # I had an issue with 0.99, so I lowered it to 0.98. + #Tiers in the storage pool + SSDTierName = "SSDTier" + HDDTierName = "HDDTier" + #Uncomment and put your HDD type here if it shows up as unspecified with "Get-PhysicalDisk -CanPool $True + # If your HDDs show up as Unspecified instead of HDD + UseUnspecifiedDriveIsHDD = "$True" + } + } + function loadValuesFromParamsToVariables { + [CmdletBinding()] + param ( + [Parameter()] + [TypeName] + $ParameterName + ) + + $Script:StorageSpacesParams + + } + + defaultPrompt + loadValuesFromParamsToVariables +} + + #TODO: Write a pester test. + +Process { + #List all disks that can be pooled and output in table format (format-table) + Get-PhysicalDisk -CanPool $True | Format-Table FriendlyName, OperationalStatus, Size, MediaType + + + #TODO: Create selectable options to fine tune what disks are selected. + + #Store all physical disks that can be pooled into a variable, $PhysicalDisks + # This assumes you want all raw / unpartitioned disks to end up in your pool - + # Add a clause like the example with your drive name to stop that drive from being included + # Example " | Where FriendlyName -NE "ATA LITEONIT LCS-256" + if ($null -ne $UseUnspecifiedDriveIsHDD) { + Get-PhysicalDisk -CanPool $True | Where-Object MediaType -eq Unspecified | Set-PhysicalDisk -MediaType HDD + # show the type changed + Get-PhysicalDisk -CanPool $True | Format-Table FriendlyName, OperationalStatus, Size, MediaType + } + $PhysicalDisks = (Get-PhysicalDisk -CanPool $True | Where-Object MediaType -NE UnSpecified) + if ($null -eq $PhysicalDisks) { + throw "Abort! No physical Disks available" + } + + #Create a new Storage Pool using the disks in variable $PhysicalDisks with a name of My Storage Pool + $SubSysName = (Get-StorageSubSystem).FriendlyName + New-StoragePool -PhysicalDisks $PhysicalDisks -StorageSubSystemFriendlyName $SubSysName -FriendlyName $StoragePoolName + #View the disks in the Storage Pool just created + Get-StoragePool -FriendlyName $StoragePoolName | Get-PhysicalDisk | Select-Object FriendlyName, MediaType + + #Set the number of columns used for each resiliency - This setting assumes you have at least 2-SSD and 2-HDD + # Get-StoragePool $StoragePoolName | Set-ResiliencySetting -Name Simple -NumberOfColumnsDefault 2 + # Get-StoragePool $StoragePoolName | Set-ResiliencySetting -Name Mirror -NumberOfColumnsDefault 1 + + #Create two tiers in the Storage Pool created. One for SSD disks and one for HDD disks + $SSDTier = New-StorageTier @StorageSpacesParams -FriendlyName $SSDTierName -MediaType SSD + $HDDTier = New-StorageTier @StorageSpacesParams -FriendlyName $HDDTierName -MediaType HDD + + #Calculate tier sizes within this storage pool + #Can override by setting sizes at top + if ($null -eq $SSDTierSize) { + $SSDTierSize = (Get-StorageTierSupportedSize -FriendlyName $SSDTierName -ResiliencySettingName $DriveTierResiliency).TierSizeMax + $SSDTierSize = [int64]($SSDTierSize * $UsableSpace) + } + if ($null -eq $HDDTierSize) { + $HDDTierSize = (Get-StorageTierSupportedSize -FriendlyName $HDDTierName -ResiliencySettingName $DriveTierResiliency).TierSizeMax + $HDDTierSize = [int64]($HDDTierSize * $UsableSpace) + } + Write-Output "TierSizes: ( $SSDTierSize , $HDDTierSize )" + + # you can end up with different number of columns in SSD - Ex: With Simple 1SSD and 2HDD could end up with SSD-1Col, HDD-2Col + New-VirtualDisk @StorageSpacesParams -FriendlyName $TieredDiskName -StorageTiers @($SSDTier, $HDDTier) -StorageTierSizes @($SSDTierSize, $HDDTierSize) @StorageSpacesParams -AutoWriteCacheSize -AutoNumberOfColumns + + # initialize the disk, format and mount as a single volume + Write-Output "Preparing volume..." + Get-VirtualDisk $TieredDiskName | Get-Disk | Initialize-Disk -PartitionStyle GPT + # This will be Partition 2. Storage pool metadata is in Partition 1 + Get-VirtualDisk $TieredDiskName | Get-Disk | New-Partition @StorageSpacesParams -UseMaximumSize + Initialize-Volume -FileSystem NTFS -Confirm:$false @StorageSpacesParams + Get-Volume @StorageSpacesParams +} + +End{ +Write-Output "Operation complete." + +Clear-Variable StorageSpacesParams -Scope Script +} \ No newline at end of file diff --git a/README.md b/README.md index 332c74e..4a7996d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -# Create Storage Spaces in Windows 10 + + + +# Create Tiered Storage Spaces in Windows 10 Windows Server O/S contains Storage Spaces support for Server Spaces tiered storage. You can front slower spinning disks with smaller faster SSDs. Windows 10 has a Storage Spaces GUI Control Panel that does not include the tiered storage GUI. -This means Powershell must be used for all configuration. +This means PowerShell must be used for all configuration. ![Physical Disks](./images_folder/physical-disks.png) @@ -13,28 +16,28 @@ This means Powershell must be used for all configuration. * The entire virtual drive is added to the system as a single large volume * You need at least * 1 SSD and 1 HDD to run cached storage / Simple resiliency - * 2 SSD and 2 HDD to run cached storage / Mirror resiliency / - * 1 SSD and 2 HDD to run cached storage / Simple resiliency / striped storage (sum of HDD space) + * 2 SSD and 2 HDDs to run cached storage / Mirror resiliency / + * 1 SSD and 2 HDDs to run cached storage / Simple resiliency / striped storage (sum of HDD space) ![Simple](./images_folder/simple.png) ![Mirrored](./images_folder/mirror-simple.png) ![Mirrored and Striped](./images_folder/mirror-stripe.png) # Scripts -## new-storage-space.ps1 +## New-TieredStorageSpace.ps1 Creates a tiered storage pool and allocates all the disk space to a single drive * You can change the drive letter and label by editing the variables at the top. -* the script can auto size the drive and cache. That didn't work for me so the script supports manual sizing. +* The script can auto size the drive and cache. That didn't work for me, so the script supports manual sizing. -## remove-storage-space +## Remove-TieredStorageSpace.ps1 Removes the virtual drive, the storage tiers and then the storage pool. -* All drives are returned the _Primordial_ pool +* All drives are returned the _Primordial_ pool. # Sample configuration *new-storage-space.ps* created a Virtual drive from 3 physical drives | Physical Drives | Storage Space Virtual Drive| |-----------------|-----------------------------| -| two 2TB HDD | single 3.6TB data volume _striped_ across my two HDD | -| one 200GB SSD. | with a 200GB read/write cache | +| Two 2 TB HDD | Single 3.6 TB data volume _striped_ across my two HDD | +| One 200 GB SSD. | With a 200 GB read/write cache. | ![Simple resiliency with striped drives](./images_folder/stripe-simple.png) @@ -45,10 +48,10 @@ The control panel does not display or manipulate tiers ## ResiliancyName: Simple vs Mirror -The "Mirror" resiliency level attempts to mirror both SSD and HDD tiers so you would need 4 drives run mirror, to mirror both tiers +The “Mirror” resiliency level attempts to mirror both SSD and HDD tiers, so you would need 4 drives run mirror, to mirror both tiers ## Caching Impact Benchmark -All Storage Pool drives connected to 3Gb/s SATA. The write-back cache is not used with sequential writes over 256KB +All Storage Pool drives connected to 3Gb/s SATA. The write-back cache is not used with sequential writes over 256 KB. ``` [Read] *Single 2TB no cache* *Two 2TB mirrored with 200GB cache* @@ -67,7 +70,7 @@ Sequential 1MiB (Q= 1, T= 1): 154.147 MB/s [ 147.0 IOPS] 230.149 MB/s [ ## Example state ### Before script -Three drives can pool. The HDD drive media types are not recognized +Three drives can pool. The HDD drive media types are not recognized. ``` PS C:\WINDOWS\system32> Get-PhysicalDisk Number FriendlyName SerialNumber MediaType CanPool OperationalStatus HealthStatus Usage Size @@ -112,4 +115,4 @@ My Tiered VirtualDisk OK # Credits * Most of the script came from this great [blog article by Nils Schimmelmann](https://nils.schimmelmann.us/post/153541254987/intel-smart-response-technology-vs-windows-10) -* See [joe's blog](https://joe.blog.freemansoft.com) for any updates \ No newline at end of file +* See [Joe's blog](https://joe.blog.freemansoft.com) for any updates \ No newline at end of file diff --git a/remove-storage-space.ps1 b/Remove-TieredStorageSpace.ps1 similarity index 73% rename from remove-storage-space.ps1 rename to Remove-TieredStorageSpace.ps1 index c7aa2f3..cbc231f 100644 --- a/remove-storage-space.ps1 +++ b/Remove-TieredStorageSpace.ps1 @@ -1,9 +1,14 @@ +#TODO: Adapt to new format. + +#Requires -RunAsAdministrator #Variables names here MUST MATCH create-storage-space.ps1 $StoragePoolName = "My Storage Pool" $SSDTierName = "SSDTier" $HDDTierName = "HDDTier" $TieredDiskName = "My Tiered VirtualDisk" +#TODO: Config file ingestion. + # Make sure they really want to do this! $choices = '&Yes', '&No' $decision = $Host.UI.PromptForChoice('Remove Storage Space', 'Are you sure you wish to remove the storage space named "' + $TieredDiskName + '"?' + [Environment]::NewLine + 'ALL DATA WILL BE PERMANENTLY LOST', $choices, 1) @@ -12,7 +17,7 @@ if ($decision -ne 0) { } # In reverse order of creation -if ((Get-VirtualDisk -FriendlyName $TieredDiskName) -ne $null){ +if ($null -ne (Get-VirtualDisk -FriendlyName $TieredDiskName)){ Write-Output "Removing drive: $TieredDiskName" Get-VirtualDisk -FriendlyName $TieredDiskName Remove-virtualdisk -friendlyName $TieredDiskName -Confirm:$false @@ -21,16 +26,16 @@ if ((Get-VirtualDisk -FriendlyName $TieredDiskName) -ne $null){ } # Remove Storage Tier -if ((Get-StorageTier -FriendlyName $HDDTierName) -ne $null){ +if ($null -ne (Get-StorageTier -FriendlyName $HDDTierName)){ Write-Output "Removing storage tiers: $HDDTierName" - Get-StorageTier -FriendlyName $HDDTierName | FT FriendlyName, MediaType, Size -AutoSize + Get-StorageTier -FriendlyName $HDDTierName | Format-Table FriendlyName, MediaType, Size -AutoSize Remove-StorageTier -FriendlyName $HDDTierName -Confirm:$false } else { Write-Output "Tier does not exist: $HDDTierName" } -if ((Get-StorageTier -FriendlyName $SSDTierName) -ne $null){ +if ($null -ne (Get-StorageTier -FriendlyName $SSDTierName)){ Write-Output "Removing storage tiers: $SSDTierName" - Get-StorageTier -FriendlyName $SSDTierName | FT FriendlyName, MediaType, Size -AutoSize + Get-StorageTier -FriendlyName $SSDTierName | Format-Table FriendlyName, MediaType, Size -AutoSize Remove-StorageTier -FriendlyName $SSDTierName -Confirm:$false } else { Write-Output "Tier does not exist: $SSDTierName" @@ -38,9 +43,9 @@ if ((Get-StorageTier -FriendlyName $SSDTierName) -ne $null){ Get-StorageTier # Remove the Storage Pool -if ((Get-StoragePool -FriendlyName $StoragePoolName) -ne $null){ +if ($null -ne (Get-StoragePool -FriendlyName $StoragePoolName)){ Write-Output "Removing storage pool: $StoragePoolName" - Get-StoragePool -FriendlyName $StoragePoolName | Get-PhysicalDisk | FT FriendlyName, MediaType + Get-StoragePool -FriendlyName $StoragePoolName | Get-PhysicalDisk | Format-Table FriendlyName, MediaType Remove-StoragePool -FriendlyName $StoragePoolName -Confirm:$false } else { Write-Output "Storage Pool does not exist: $StoragePoolName" diff --git a/TieredStorageSpace-Config.json b/TieredStorageSpace-Config.json new file mode 100644 index 0000000..46392be --- /dev/null +++ b/TieredStorageSpace-Config.json @@ -0,0 +1,37 @@ +{ + "StorageSpace":[ + { + "StoragePoolFriendlyName" : "My Storage Pool" + }, + { + "TieredDiskName": "My Tiered VirtualDisk" + }, + { + "ResiliencySettingName": "Simple" + }, + { + "DriveLetter": "Z" + }, + { + "NewFileSystemLabel": "StorageDrive" + }, + { + "SSDTierSize": "$null" + }, + { + "HDDTierSize": "$null" + }, + { + "UsableSpace": "0.98" + }, + { + "UseUnspecifiedDriveIsHDD": "$True" + }, + { + "SSDTierName": "SSDTier" + }, + { + "HDDTierName": "HDDTier" + } + ] +} \ No newline at end of file diff --git a/VM-Support/README.md b/VM-Support/README.md index 385ad19..5452a26 100644 --- a/VM-Support/README.md +++ b/VM-Support/README.md @@ -1 +1 @@ -This directory was intended to support creating virtual drives that could be mounted into a VM and appear as if they were phsical disks \ No newline at end of file +This directory was intended to support creating virtual drives that could be mounted into a VM and appear as if they were physical disks \ No newline at end of file diff --git a/new-storage-space.ps1 b/new-storage-space.ps1 deleted file mode 100644 index 70e3ff7..0000000 --- a/new-storage-space.ps1 +++ /dev/null @@ -1,89 +0,0 @@ -# RUN AS ADMINISTRATOR -# https://nils.schimmelmann.us/post/153541254987/intel-smart-response-technology-vs-windows-10 -#Tested with one SSD and two HDD -# -#Pool that will suck in all drives -$StoragePoolName = "My Storage Pool" -#Tiers in the storage pool -$SSDTierName = "SSDTier" -$HDDTierName = "HDDTier" -#Virtual Disk Name made up of disks in both tiers -$TieredDiskName = "My Tiered VirtualDisk" - -#Simple = striped. Mirror only works if both can mirror AFIK -#https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/dn387076(v=ws.11) -$DriveTierResiliency = "Simple" - -#Change to suit - drive later and the label name -$TieredDriveLetter = "Z" -$TieredDriveLabel = "StorageDrive" - -#Override the default sizing here - useful if have two different size SSDs or HDDs - set to smallest of pair -#These must be Equal or smaller than the disk size available in that tier SSD and HDD -#SSD:cache - HDD:data -#set to null so copy/paste to command prompt doesn't have previous run values -$SSDTierSize = $null -$HDDTierSize = $null -#Drives cannot always be fully allocated - probably broken for drives < 10GB -$UsableSpace = 0.99 - -#Uncomment and put your HDD type here if it shows up as unspecified with "Get-PhysicalDisk -CanPool $True -# If your HDDs show up as Unspecified instead of HDD -$UseUnspecifiedDriveIsHDD = "Yes" - -#List all disks that can be pooled and output in table format (format-table) -Get-PhysicalDisk -CanPool $True | ft FriendlyName, OperationalStatus, Size, MediaType - -#Store all physical disks that can be pooled into a variable, $PhysicalDisks -# This assumes you want all raw / unpartitioned disks to end up in your pool - -# Add a clause like the example with your drive name to stop that drive from being included -# Example " | Where FriendlyName -NE "ATA LITEONIT LCS-256" -if ($UseUnspecifiedDriveIsHDD -ne $null){ - $DisksToChange = (Get-PhysicalDisk -CanPool $True | where MediaType -eq Unspecified) - Get-PhysicalDisk -CanPool $True | where MediaType -eq Unspecified | Set-PhysicalDisk -MediaType HDD - # show the type changed - Get-PhysicalDisk -CanPool $True | ft FriendlyName, OperationalStatus, Size, MediaType -} -$PhysicalDisks = (Get-PhysicalDisk -CanPool $True | Where MediaType -NE UnSpecified) -if ($PhysicalDisks -eq $null){ - throw "Abort! No physical Disks available" -} - -#Create a new Storage Pool using the disks in variable $PhysicalDisks with a name of My Storage Pool -$SubSysName = (Get-StorageSubSystem).FriendlyName -New-StoragePool -PhysicalDisks $PhysicalDisks -StorageSubSystemFriendlyName $SubSysName -FriendlyName $StoragePoolName -#View the disks in the Storage Pool just created -Get-StoragePool -FriendlyName $StoragePoolName | Get-PhysicalDisk | Select FriendlyName, MediaType - -#Set the number of columns used for each resiliency - This setting assumes you have at least 2-SSD and 2-HDD -# Get-StoragePool $StoragePoolName | Set-ResiliencySetting -Name Simple -NumberOfColumnsDefault 2 -# Get-StoragePool $StoragePoolName | Set-ResiliencySetting -Name Mirror -NumberOfColumnsDefault 1 - -#Create two tiers in the Storage Pool created. One for SSD disks and one for HDD disks -$SSDTier = New-StorageTier -StoragePoolFriendlyName $StoragePoolName -FriendlyName $SSDTierName -MediaType SSD -$HDDTier = New-StorageTier -StoragePoolFriendlyName $StoragePoolName -FriendlyName $HDDTierName -MediaType HDD - -#Calculate tier sizes within this storage pool -#Can override by setting sizes at top -if ($SSDTierSize -eq $null){ - $SSDTierSize = (Get-StorageTierSupportedSize -FriendlyName $SSDTierName -ResiliencySettingName $DriveTierResiliency).TierSizeMax - $SSDTierSize = [int64]($SSDTierSize * $UsableSpace) -} -if ($HDDTierSize -eq $null){ - $HDDTierSize = (Get-StorageTierSupportedSize -FriendlyName $HDDTierName -ResiliencySettingName $DriveTierResiliency).TierSizeMax - $HDDTierSize = [int64]($HDDTierSize * $UsableSpace) -} -Write-Output "TierSizes: ( $SSDTierSize , $HDDTierSize )" - -# you can end up with different number of columns in SSD - Ex: With Simple 1SSD and 2HDD could end up with SSD-1Col, HDD-2Col -New-VirtualDisk -StoragePoolFriendlyName $StoragePoolName -FriendlyName $TieredDiskName -StorageTiers @($SSDTier, $HDDTier) -StorageTierSizes @($SSDTierSize, $HDDTierSize) -ResiliencySettingName $DriveTierResiliency -AutoWriteCacheSize -AutoNumberOfColumns - -# initialize the disk, format and mount as a single volume -Write-Output "preparing volume" -Get-VirtualDisk $TieredDiskName | Get-Disk | Initialize-Disk -PartitionStyle GPT -# This will be Partition 2. Storage pool metadata is in Partition 1 -Get-VirtualDisk $TieredDiskName | Get-Disk | New-Partition -DriveLetter $TieredDriveLetter -UseMaximumSize -Initialize-Volume -DriveLetter $TieredDriveLetter -FileSystem NTFS -Confirm:$false -NewFileSystemLabel $TieredDriveLabel -Get-Volume -DriveLetter $TieredDriveLetter - -Write-Output "Operation complete" \ No newline at end of file