PowerShell: Benchmark Disk Speed

function getDiskSpeed{
Purpose: to measure IOPS of local volumes or UNC paths
- This function must be ran with Administrator privileges, especially when triggered for the first time on a local system
- Two utilities will be required and installed on the system: chocolatey (DevOps Tool) and diskspd.exe (Microsoft's disk benchmark app, similar to SQLIO)
- Call the function with a valid path to test disk speed, such as:
getDiskSpeed C:\
getDiskSpeed D
if($driveLetter.Length -eq 1){$driveLetter+=":";}

function isPathWritable{
# Create random test file name
$filename = "diskSpeedTest-"+[guid]::NewGuid()
$tempFilename = (Join-Path $tempFolder $filename)
New-Item -ItemType Directory -Path $tempFolder -Force -EA SilentlyContinue|Out-Null

Try {
# Try to add a new file
# New-Item -ItemType Directory -Path $tempFolder -Force -EA SilentlyContinue
#Write-Host -ForegroundColor Green "$testPath is writable."

# Delete test file after done
# Remove-Item $tempFilename -Force -ErrorAction SilentlyContinue

# Set return value
Catch {
# Return 'false' if there are errors

return $feasible;

# Check if input is a valid drive letter
function validatePath{
if (Test-Path $path -EA SilentlyContinue){
$validLocalPath=$path.SubString(0,2) -match $regexValidDriveLetters
if ($validLocalPath){
write-Host "Local directory detected."
$driveLettersOnThisComputer=ls function:[A-Z]: -n|?{test-path $_}
if (!($driveLettersOnThisComputer -contains $path.SubString(0,2))){
Write-Host "The provided local path's first 2 characters do not match any volumes in this system.";
return $false;
return $(isPathWritable $path)
if ($path -match $regexUncPath){
write-Host "UNC directory detected."
return $(isPathWritable $path)
}else{Write-Host "The provided path does not match a UNC pattern nor a local drive.";return $false;}
Write-Host "The path $path currently does NOT exist";
Return $false;

if (validatePath){

# Set variables
# New-Item -ItemType Directory -Force -Path $tempDirectory|Out-Null
$processors=(Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors

# Ensure that diskspd.exe is available in the system
$diskSpeedUtilityAvailable=get-command diskspd.exe -ea SilentlyContinue
if (!($diskSpeedUtilityAvailable)){
if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
choco install diskspd -y;

function getIops{
# Sometimes, the test result throws this error "diskspd Error opening file:" if no switches were used
# The work around is to specify more parameters
# Other variations:
# $testResult=diskspd.exe-d1 -o4 -t4 -b8k -r -L -w50 -c1G $testFile
# $testResult=diskspd.exe -b4K -t1 -r -w50 -o32 -d10 -c8192 $testFile
# Note: remove the -c option to avoid this error when running with unprivileged accounts
# diskspd.exe : WARNING: Error adjusting token privileges for SeManageVolumePrivilege (error code: 1300)

$testResult=invoke-expression "diskspd.exe -b8k -d1 -o$processors -t$processors -r -L -w25 -c1G $testfile";
<# diskspd.exe -b8k -d1 -o4 -t4 -r -L -w25 -c1G $testfile
8K block size; 1 second random I/O test;4 threads; 4 outstanding I/O operations;
25% write (implicitly makes read 75% ratio);
$errorMessage = $_.Exception.Message
$failedItem = $_.Exception.ItemName
Write-Host "$errorMessage $failedItem";
$x=$testResult|select-string -Pattern "total*" -CaseSensitive|select-object -First 1|out-String
return $iops

function selectHighIops{
for($i=1;$i -le $sampleSize;$i++){
$errorMessage = $_.Exception.Message
$failedItem = $_.Exception.ItemName
Write-Host "$errorMessage $failedItem";
$highestResult=($testArray|measure -Maximum).Maximum
return $highestResult

# Trigger several tests and select the highest value

# Cleanup
# cmd /c rd $tempDirectory
function isFileLocked{
param($file=$(New-Object System.IO.FileInfo $testFile))
if (Test-Path $testFile){
try {
$fileHandle = $file.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
if ($fileHandle){
# File handle is open, which means file is not locked
return $false
# file is locked
return $true
}else{return $false}

do {
sleep 1;
Remove-Item -Recurse -Force $tempDirectory

return "$mebibytesPerSecond MiB/s ($selectedIops IOPS)";
}else{return "Cannot get disk speed"}

Leave a Reply

Your email address will not be published. Required fields are marked *