Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.code-workspace
.vscode
7 changes: 7 additions & 0 deletions .vscode/ltex.hiddenFalsePositives.en-US.txt
Original file line number Diff line number Diff line change
@@ -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$"}
167 changes: 167 additions & 0 deletions New-TieredStorageSpace.ps1
Original file line number Diff line number Diff line change
@@ -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)"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to save defaults to a config file or load them from a config file. I'm not sure from the prompt.


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..."
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Ether" should be "Either"

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
}
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# Create Storage Spaces in Windows 10

<!--TODO: Update README documrntaion to match new scripts usage. /--->
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

documrntation should be "documentation".


# 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)

Expand All @@ -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
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a line here or at the top that tells us how to run the script with the external configuration file?

* 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)

Expand All @@ -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*
Expand All @@ -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
Expand Down Expand Up @@ -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
* See [Joe's blog](https://joe.blog.freemansoft.com) for any updates
19 changes: 12 additions & 7 deletions remove-storage-space.ps1 → Remove-TieredStorageSpace.ps1
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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
Expand All @@ -21,26 +26,26 @@ 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"
}
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"
Expand Down
37 changes: 37 additions & 0 deletions TieredStorageSpace-Config.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
2 changes: 1 addition & 1 deletion VM-Support/README.md
Original file line number Diff line number Diff line change
@@ -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
This directory was intended to support creating virtual drives that could be mounted into a VM and appear as if they were physical disks
Loading