Skip to content

Instantly share code, notes, and snippets.

@nanoDBA
Last active June 28, 2025 19:59
Show Gist options
  • Select an option

  • Save nanoDBA/fbee092058bd7e8956c8d9b261c5b231 to your computer and use it in GitHub Desktop.

Select an option

Save nanoDBA/fbee092058bd7e8956c8d9b261c5b231 to your computer and use it in GitHub Desktop.
Download / Extract and Run DiskSpd - Automated EC2 volume and DiskSpd benchmarking for Windows
# ------------------------------------------------------------------------------
# File: Test-DiskSpd.ps1
# Description: 🚀 Automated EC2 volume and DiskSpd benchmarking for Windows
# Purpose: Retrieves detailed EC2 volume info and runs robust DiskSpd I/O
# benchmarks on specified drives. Handles AWS, local, and hybrid
# scenarios with safety checks, resumable downloads, and cleanup.
# Built for DBAs and sysadmins who want to know their storage is
# actually as fast as the cloud bill says! 😎
# Created: 2025-06-26
# Modified: 2025-06-26
# Adapted
# from: https://sqlperformance.com/2015/08/io-subsystem/diskspd-test-storage
# ------------------------------------------------------------------------------
# AI-Updated: 2025-06-26 12:00:00 | Marker: AIUPD-20250626120000-546573742d4469736b5370642e707331 #|
# Summary:
# 📊 This script combines AWS EC2 volume discovery with DiskSpd performance
# testing. It auto-detects drive details, benchmarks with best-practice
# parameters, and logs results with context for later analysis. Handles
# download, extraction, and cleanup of DiskSpd, and works even if BITS is
# missing. All output is designed for clarity and confidence.
#
# Features:
# - 🔍 EC2 volume info (type, IOPS, throughput, etc.)
# - ⚡ DiskSpd download with BITS or iwr fallback
# - 🏗️ Automated extraction and cleanup
# - 📝 Timestamped, descriptive results files
# - 🛡️ Safety checks for free space and test file cleanup
# - 🤖 Wrapper for Expand-Archive for user-friendly params
# - 💬 Verbose and error output for troubleshooting
#
# Recommendations:
# - 🔧 Test in a non-prod environment first (I/O tests can be disruptive)
# - ⏰ Run during maintenance windows for best results
# - 📈 Monitor disk and network usage during tests
# - 🛑 Clean up large test files to avoid storage surprises
#
# DBA Pro Tip: Trust, but verify your cloud storage claims. This script makes
# it easy (and fun) to catch underperforming volumes before your users do! 😜
#region Configuration 🛠️
# Let's get this party started by making sure all our ducks (and drives) are in a row.
# If you don't have AWS Tools or DiskSpd, this script will try to help you out.
# If it can't, well... you probably didn't want to benchmark anything anyway. 😏
#endregion
#region Helper Functions 🤖
# Because PowerShell is better with friends (and subroutines).
function Expand-ArchiveCompat {
[CmdletBinding()]
param()
Expand-Archive @PSBoundParameters
}
# Helper: Parse DiskSpd XML and export summary to CSV
function Get-DiskSpdSummary {
param (
[Parameter(Mandatory = $true)]
[string]$XmlFile,
[Parameter(Mandatory = $true)]
[string]$CsvFile,
[Parameter(Mandatory = $true)]
[string]$DriveLetter
)
$x = [xml](Get-Content $XmlFile)
$testTime = [double]$x.Results.TimeSpan.TestTimeSeconds
$blockSize = ($x.Results.Profile.TimeSpans.TimeSpan.Targets.Target.BlockSize | Select-Object -First 1)
$threadCount = $x.Results.TimeSpan.ThreadCount
$rb = ($x.Results.TimeSpan.Thread.Target | Measure-Object -Sum -Property ReadBytes).Sum
$wb = ($x.Results.TimeSpan.Thread.Target | Measure-Object -Sum -Property WriteBytes).Sum
$rc = ($x.Results.TimeSpan.Thread.Target | Measure-Object -Sum -Property ReadCount).Sum
$wc = ($x.Results.TimeSpan.Thread.Target | Measure-Object -Sum -Property WriteCount).Sum
$readMBps = [math]::Round($rb / $testTime / 1MB, 2)
$writeMBps = [math]::Round($wb / $testTime / 1MB, 2)
$totalMBps = [math]::Round(($rb + $wb) / $testTime / 1MB, 2)
$readIOPS = [math]::Round($rc / $testTime, 2)
$writeIOPS = [math]::Round($wc / $testTime, 2)
$totalIOPS = [math]::Round(($rc + $wc) / $testTime, 2)
$avgReadLat = [math]::Round($x.Results.TimeSpan.AvgReadLatencyMilliseconds, 2)
$avgWriteLat = [math]::Round($x.Results.TimeSpan.AvgWriteLatencyMilliseconds, 2)
$o = [PSCustomObject]@{
ComputerName = $x.Results.System.ComputerName
Drive = $DriveLetter
TestTime = Get-Date
TestTimeSeconds = $testTime
BlockSize = $blockSize
ThreadCount = $threadCount
ReadThroughputMBps = $readMBps
WriteThroughputMBps = $writeMBps
TotalThroughputMBps = $totalMBps
ReadIOPS = $readIOPS
WriteIOPS = $writeIOPS
TotalIOPS = $totalIOPS
AvgReadLatencyMs = $avgReadLat
AvgWriteLatencyMs = $avgWriteLat
}
# Export all details to CSV (including bytes/counts for later analysis)
$csvObj = [PSCustomObject]@{
ComputerName = $x.Results.System.ComputerName
Drive = $DriveLetter
TestTime = Get-Date
TestTimeSeconds = $testTime
BlockSize = $blockSize
ThreadCount = $threadCount
ReadThroughputMBps = $readMBps
WriteThroughputMBps = $writeMBps
TotalThroughputMBps = $totalMBps
ReadIOPS = $readIOPS
WriteIOPS = $writeIOPS
TotalIOPS = $totalIOPS
AvgReadLatencyMs = $avgReadLat
AvgWriteLatencyMs = $avgWriteLat
ReadCount = $rc
WriteCount = $wc
ReadBytes = $rb
WriteBytes = $wb
}
$csvObj | Export-Csv -Path $CsvFile -NoTypeInformation -Append
return $o
}
#endregion
#region EC2 Volume Details Retrieval 🔍
# This function tries every trick in the book to figure out what disks you have.
# If your disk layout is weird, it will get weird right back at you. 🙃
# It even talks to AWS, so make sure your credentials are less flaky than your storage.
function Get-EC2DriveVolumeDetails {
<#!
.SYNOPSIS
Retrieves details about EC2 instance drive volumes, including size, type, IOPS, and more. 🔍
.DESCRIPTION
This function tries every trick in the book to figure out what disks you have on your EC2 instance. If your disk layout is weird, it will get weird right back at you. 🙃 It even talks to AWS, so make sure your credentials are less flaky than your storage. Returns a custom object with drive, size, and EBS details.
.PARAMETER DriveLetter
One or more characters representing the Windows drive letters (e.g., 'C', 'D'). If omitted, retrieves details for all lettered drives (C, D, E, etc.).
.EXAMPLE
Get-EC2DriveVolumeDetails
# Retrieves details for all local drives on the EC2 instance.
.EXAMPLE
Get-EC2DriveVolumeDetails -DriveLetter C
# Retrieves details for the C: drive only.
.EXAMPLE
Get-EC2DriveVolumeDetails -DriveLetter C, D
# Retrieves details for both C: and D:.
.NOTES
Requires AWS Tools for PowerShell: Install-Module AWS.Tools.Common; Install-Module AWS.Tools.EC2
Ensure valid AWS credentials/permissions (ec2:DescribeVolumes) are in place.
Verbose output can help debug fallback paths (dynamic disks, WMI).
.LINK
https://docs.aws.amazon.com/powershell/latest/reference/items/Get-EC2Volume.html
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[char[]]$DriveLetter
)
#--------------------------------------------
# Helper: WMI fallback for dynamic disks
#--------------------------------------------
function Get-WmiDiskSize ([char]$letter) {
try {
$cimVolume = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter='$($letter):'"
if (-not $cimVolume) { return $null }
$partitions = Get-CimAssociatedInstance -InputObject $cimVolume -Association Win32_VolumeToDiskPartition
if (-not $partitions) { return $null }
foreach ($p in $partitions) {
$drives = Get-CimAssociatedInstance -InputObject $p -Association Win32_DiskDriveToDiskPartition
foreach ($d in $drives) {
if ($d.Size -and [long]$d.Size -gt 0) {
return [long]$d.Size
}
}
}
return $null
}
catch {
Write-Verbose "WMI fallback error: $($_.Exception.Message)"
return $null
}
}
#--------------------------------------------
# 1) Retrieve IMDSv2 token or fallback to IMDSv1
#--------------------------------------------
$token = $null
try {
$token = Invoke-RestMethod -Uri "http://169.254.169.254/latest/api/token" `
-Method PUT `
-Headers @{ "X-aws-ec2-metadata-token-ttl-seconds" = "21600" } `
-ErrorAction Stop
}
catch {
Write-Verbose "IMDSv2 token retrieval failed: $($_.Exception.Message). Falling back to IMDSv1."
}
#--------------------------------------------
# 2) Get instance identity (InstanceId, Region)
#--------------------------------------------
try {
if ($token) {
$instanceIdentityDoc = Invoke-RestMethod -Uri "http://169.254.169.254/latest/dynamic/instance-identity/document" `
-Headers @{ "X-aws-ec2-metadata-token" = $token } `
-ErrorAction Stop
}
else {
$instanceIdentityDoc = Invoke-RestMethod -Uri "http://169.254.169.254/latest/dynamic/instance-identity/document" -ErrorAction Stop
}
}
catch {
Write-Error "Unable to retrieve instance metadata: $($_.Exception.Message)"
return
}
$instanceId = $instanceIdentityDoc.instanceId
$region = $instanceIdentityDoc.region
#--------------------------------------------
# 3) Determine which drive letters to process
#--------------------------------------------
if (-not $PSBoundParameters.ContainsKey('DriveLetter')) {
# If DriveLetter not specified, gather all lettered volumes
$allVolumes = Get-Volume -ErrorAction SilentlyContinue | Where-Object { $_.DriveLetter }
$driveLetters = $allVolumes.DriveLetter
Write-Verbose "No DriveLetter param given; auto-detected letters: $driveLetters"
}
else {
$driveLetters = $DriveLetter
}
$results = @()
foreach ($drv in $driveLetters) {
#--------------------------------------------
# 4) Get disk size
#--------------------------------------------
$diskSizeBytes = $null
# Attempt partition->disk
$partition = Get-Partition -ErrorAction SilentlyContinue | Where-Object { $_.DriveLetter -eq $drv } | Select-Object -First 1
if ($partition) {
$disk = Get-Disk -Number $partition.DiskNumber -ErrorAction SilentlyContinue
if ($disk) {
$diskSizeBytes = $disk.Size
}
}
else {
# Attempt volume->disk
$vol = Get-Volume -DriveLetter $drv -ErrorAction SilentlyContinue
if ($vol) {
$disk = $vol | Get-Disk -ErrorAction SilentlyContinue
if ($disk) {
$diskSizeBytes = $disk.Size
}
else {
# Possibly dynamic
if ($vol.Size) {
$diskSizeBytes = [long]$vol.Size
Write-Verbose "Using Get-Volume.Size = $($vol.Size) for drive $drv (likely dynamic disk)."
}
}
}
}
# If still no size, use WMI fallback
if (-not $diskSizeBytes) {
Write-Verbose "No size found for drive $drv. Trying WMI fallback..."
$diskSizeBytes = Get-WmiDiskSize $drv
if ($diskSizeBytes) {
Write-Verbose "WMI fallback returned $diskSizeBytes bytes for drive $drv."
}
}
# If still no size, skip
if (-not $diskSizeBytes) {
Write-Error "Failed to determine physical disk size for drive $drv. Skipping."
continue
}
$diskSizeGB = [math]::Round($diskSizeBytes / 1GB)
Write-Verbose "Drive $drv is approx. $diskSizeGB GB."
#--------------------------------------------
# 5) Match to EBS volume
#--------------------------------------------
if (-not (Get-Command Get-EC2Volume -ErrorAction SilentlyContinue)) {
Write-Warning "AWS.Tools.EC2 module not installed. Install with: Install-Module AWS.Tools.EC2"
$results += [PSCustomObject]@{
DriveLetter = $drv
DiskSizeGB = $diskSizeGB
Note = "Install AWS.Tools.EC2 for IOPS/Throughput/VolumeType details."
}
continue
}
try {
$volumes = Get-EC2Volume -Region $region -ErrorAction Stop |
Where-Object { $_.Attachments.InstanceId -contains $instanceId }
$matchedVolume = $volumes | Where-Object { $_.Size -eq $diskSizeGB } | Select-Object -First 1
if (-not $matchedVolume) {
Write-Warning "No EBS volume matched drive $drv by size = $diskSizeGB GB."
continue
}
$attachment = $matchedVolume.Attachments | Where-Object { $_.InstanceId -eq $instanceId }
$results += [PSCustomObject]@{
DriveLetter = $drv
DiskSizeGB = $diskSizeGB
VolumeId = $matchedVolume.VolumeId
VolumeType = $matchedVolume.VolumeType
IOPS = $matchedVolume.Iops
Throughput = $matchedVolume.Throughput
State = $matchedVolume.State
Device = $attachment.Device
DeleteOnTermination = $attachment.DeleteOnTermination
}
}
catch {
Write-Error "Error calling Get-EC2Volume: $($_.Exception.Message)"
}
}
return $results
}
#endregion
#region DiskSpd Test Execution & Download ⚡🚚
# This is where the magic happens. We'll hammer your disk with I/O and see if it
# cries uncle. If you run this on production, don't blame us if your users revolt. 😜
# Handles DiskSpd download (with BITS/iwr), extraction, test execution, and cleanup.
function Test-DiskSpd {
<#!
.SYNOPSIS
Runs a DiskSpd test on a specified drive letter or all local drives (with -AllDrives -Force). ⚡
.DESCRIPTION
The Test-DiskSpd function executes a storage performance test using Microsoft's DiskSpd tool. It dynamically retrieves EC2 volume details (if applicable) and ensures sufficient disk space before creating the test file. Results are saved with a timestamped filename. Handles download, extraction, and cleanup of DiskSpd, and works even if BITS is missing. All output is designed for clarity and confidence. If you run this on production, don't blame us if your users revolt. 😜
If you specify -AllDrives without -Force, the function will throw an error and abort without running any tests. This is a safety feature to prevent accidental I/O tests on all drives.
.PARAMETER DiskSpdDriveLetter
The drive letter on which to run the DiskSpd test. Defaults to 'M'.
.PARAMETER AllDrives
If specified, runs the test on every local volume with a drive letter. Requires -Force. If -AllDrives is used without -Force, the function will throw an error and abort without running any tests.
.PARAMETER Force
Required with -AllDrives. Confirms you really want to run I/O tests on all drives. If not specified with -AllDrives, the function will throw an error and abort.
.PARAMETER WritePercentage
The percentage of the workload that should be writes (remaining percentage will be reads). Defaults to 20%.
.PARAMETER TestTimeSeconds
The duration of the DiskSpd test in seconds. Defaults to 60.
.PARAMETER TestFileSize
The size of the test file to be created. Defaults to '20G'.
.PARAMETER BlockSize
The block size for DiskSpd I/O operations (e.g., '8K', '4K'). Defaults to '8K'.
.PARAMETER KeepTestFile
If specified, the test file will not be deleted after execution. Defaults to $false.
.PARAMETER DownloadDiskSpd
If specified, will download and extract DiskSpd if not found. Defaults to $true.
.PARAMETER CsvResultsFile
The path for the CSV summary output. Defaults to the same base as the TXT results file, but with .csv extension.
.PARAMETER KeepXml
If specified, keeps the intermediate XML file. By default, the XML is deleted after CSV export.
.EXAMPLE
Test-DiskSpd -DiskSpdDriveLetter D -WritePercentage 10 -TestTimeSeconds 120
# Runs a 120-second test on D: with 10% writes.
.NOTES
Requires DiskSpd.exe from Microsoft. Ensures sufficient free space before creating a large test file. Optionally keeps the test file for later review. DBA Pro Tip: Trust, but verify your cloud storage claims. This script makes it easy (and fun) to catch underperforming volumes before your users do! 😜
.LINK
https://sqlperformance.com/2015/08/io-subsystem/diskspd-test-storage
https://github.com/microsoft/diskspd
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param (
[string]$DiskSpdDriveLetter = 'M',
[switch]$AllDrives,
[switch]$Force,
[int]$WritePercentage = 20,
[int]$TestTimeSeconds = 60,
[string]$TestFileSize = "20G",
[string]$BlockSize = "8K",
[switch]$KeepTestFile,
[switch]$DownloadDiskSpd = $true,
[string]$CsvResultsFile,
[switch]$KeepXml
)
# Handle -AllDrives logic
if ($AllDrives) {
if (-not $Force) {
throw "ERROR: -AllDrives is a dangerous operation and requires -Force. Aborting. No tests will be run."
}
$drives = Get-Volume | Where-Object { $_.DriveLetter -and $_.DriveType -eq 'Fixed' } | Select-Object -ExpandProperty DriveLetter
$results = @()
foreach ($drv in $drives) {
$params = @{
DiskSpdDriveLetter = $drv
WritePercentage = $WritePercentage
TestTimeSeconds = $TestTimeSeconds
TestFileSize = $TestFileSize
BlockSize = $BlockSize
KeepTestFile = $KeepTestFile
DownloadDiskSpd = $DownloadDiskSpd
KeepXml = $KeepXml
}
$result = & $MyInvocation.MyCommand @params
$results += $result
}
return $results
}
# Store original working directory
$originalDirectory = Get-Location
try {
# Validate drive letter format and convert if needed
$DiskSpdDriveLetter = $DiskSpdDriveLetter.TrimEnd(':')
# Retrieve EC2 volume details for the selected drive letter
Write-Verbose "Getting EC2 volume details for drive $DiskSpdDriveLetter"
$ec2VolumeDetails = Get-EC2DriveVolumeDetails -DriveLetter $DiskSpdDriveLetter
# Ensure volume details are properly set to prevent issues in the filename
$volumeType = if ($ec2VolumeDetails.VolumeType) { $ec2VolumeDetails.VolumeType } else { 'unknown' }
$diskSizeGB = if ($ec2VolumeDetails.DiskSizeGB) { $ec2VolumeDetails.DiskSizeGB } else { 'unknown' }
$iops = if ($ec2VolumeDetails.IOPS) { $ec2VolumeDetails.IOPS } else { 'unknown' }
$throughput = if ($ec2VolumeDetails.Throughput) { $ec2VolumeDetails.Throughput } else { 'unknown' }
$fileSystem = (Get-Volume -DriveLetter $DiskSpdDriveLetter -ErrorAction SilentlyContinue).FileSystem
if (-not $fileSystem) { $fileSystem = 'unknownFS' }
$allocUnitSize = (Get-Volume -DriveLetter $DiskSpdDriveLetter -ErrorAction SilentlyContinue).AllocationUnitSize
if (-not $allocUnitSize) { $allocUnitSize = 'unknown' } else { $allocUnitSize = "${allocUnitSize}B" }
$computerName = $env:COMPUTERNAME
$fileDescription = "volume_${DiskSpdDriveLetter}_${volumeType}_${diskSizeGB}GB_${iops}_iops_${throughput}_throughput_${BlockSize}_blocksize_${allocUnitSize}_allocunit_${fileSystem}_formatted_${computerName}"
$timestamp = Get-Date -Format "yyyy-MM-dd__HHmmss"
$resultsFile = "$env:USERPROFILE\Documents\${timestamp}_${fileDescription}.txt"
$testFile = "${DiskSpdDriveLetter}:\DiskSpd_testfile.dat"
# Set up paths and variables
$diskSpdUrl = 'https://aka.ms/getdiskspd'
$diskSpdZip = "$env:TEMP\DiskSpd.zip"
$diskSpdPath = 'C:\DiskSpd'
$diskSpdExe = "$diskSpdPath\amd64\diskspd.exe"
# Download DiskSpd ZIP if needed
if (-not (Test-Path $diskSpdExe)) {
Write-Verbose "DiskSpd not found at $diskSpdExe"
if ($DownloadDiskSpd) {
if ($PSCmdlet.ShouldProcess("Download and extract DiskSpd tool", "Download DiskSpd")) {
Write-Output "Downloading DiskSpd from $diskSpdUrl..."
if (-not (Test-Path $diskSpdPath)) {
New-Item -Path $diskSpdPath -ItemType Directory -Force | Out-Null
}
if (Get-Command Start-BitsTransfer -ErrorAction SilentlyContinue) {
Write-Output "Downloading DiskSpd with Start-BitsTransfer..."
Start-BitsTransfer -Destination $diskSpdZip -Source $diskSpdUrl
} else {
Write-Output "Downloading DiskSpd with Invoke-WebRequest..."
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $diskSpdUrl -OutFile $diskSpdZip -UseBasicParsing
}
# Extract DiskSpd using .NET (works everywhere)
Add-Type -AssemblyName System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::ExtractToDirectory($diskSpdZip, $diskSpdPath)
# Verify extraction
if (Test-Path $diskSpdExe) {
Write-Output "DiskSpd extracted successfully."
} else {
Write-Error "Failed to extract DiskSpd. Please download and extract manually."
return
}
} else {
Write-Output "DiskSpd download skipped."
return
}
} else {
Write-Error "DiskSpd not found at $diskSpdExe. Please install DiskSpd or use -DownloadDiskSpd parameter."
return
}
}
# Check for sufficient free space
$drive = Get-PSDrive -Name $DiskSpdDriveLetter -ErrorAction SilentlyContinue
if (-not $drive) {
Write-Error "Drive $DiskSpdDriveLetter not found or not accessible."
return
}
# Parse test file size
$sizeValue = $TestFileSize -replace '[^0-9]', ''
$sizeUnit = $TestFileSize -replace '[0-9]', ''
$requiredBytes = switch ($sizeUnit.ToUpper()) {
'G' { [long]$sizeValue * 1GB }
'M' { [long]$sizeValue * 1MB }
'K' { [long]$sizeValue * 1KB }
default { [long]$sizeValue }
}
if ($drive.Free -lt $requiredBytes) {
Write-Error "Insufficient free space on drive $DiskSpdDriveLetter. Required: $($requiredBytes / 1GB) GB, Available: $($drive.Free / 1GB) GB"
return
}
# Before launching DiskSpd, use console output for phase status
Write-Output "Preparing to run DiskSpd on drive $DiskSpdDriveLetter..."
# ... any setup, checks, etc. ...
Write-Output "Launching DiskSpd test for $TestTimeSeconds seconds on drive $DiskSpdDriveLetter..."
# Execute DiskSpd test
if ($PSCmdlet.ShouldProcess("Run DiskSpd test on drive $DiskSpdDriveLetter", "Run DiskSpd test")) {
Write-Output "Running DiskSpd test on drive $DiskSpdDriveLetter with $WritePercentage% write workload and $TestFileSize test file size..."
# Use $TestTimeSeconds for DiskSpd -d parameter
$diskSpdCmd = "& '$diskSpdExe' -Rxml -b$BlockSize -d$TestTimeSeconds -o4 -t8 -w$WritePercentage -Z1G -Suw -Ln -si -c$TestFileSize '$testFile'"
# Launch DiskSpd and show test progress
$job = Start-Job -ScriptBlock { param($cmd) Invoke-Expression $cmd } -ArgumentList $diskSpdCmd
$startTime = Get-Date
$progressActivity = "DiskSpd test running on drive $DiskSpdDriveLetter"
while ($true) {
$elapsed = (Get-Date) - $startTime
$percent = [math]::Min([math]::Round(($elapsed.TotalSeconds / $TestTimeSeconds) * 100), 100)
Write-Progress -Activity $progressActivity -Status "$percent% complete" -PercentComplete $percent
if ($job.State -ne 'Running') { break }
Start-Sleep -Seconds 1
}
# Retrieve output and clean up job
$output = Receive-Job $job -Wait
Remove-Job $job
Write-Progress -Activity $progressActivity -Completed
$output | Out-File -FilePath $resultsFile -Encoding utf8
# Delete test file if not keeping it
if (-not $KeepTestFile -and (Test-Path $testFile)) {
Remove-Item -Path $testFile -Force
Write-Verbose "Test file deleted: $testFile"
}
# Verify results file
if (Test-Path $resultsFile) {
Write-Output "DiskSpd test completed. Results saved to: $resultsFile"
} else {
Write-Error "Results file $resultsFile not found. Test may have failed."
}
} else {
Write-Output "DiskSpd test simulation complete. Would have saved results to: $resultsFile"
}
# After DiskSpd execution, produce both TXT and XML output, then export summary to CSV
$xmlFile = [System.IO.Path]::ChangeExtension($resultsFile, 'xml')
if (-not $CsvResultsFile) {
$CsvResultsFile = [System.IO.Path]::ChangeExtension($resultsFile, 'csv')
}
# Save XML output
if (Test-Path $xmlFile) { Remove-Item $xmlFile -Force }
$output | Out-File -FilePath $xmlFile -Encoding utf8
# Export summary to CSV
$summary = Get-DiskSpdSummary -XmlFile $xmlFile -CsvFile $CsvResultsFile -DriveLetter $DiskSpdDriveLetter
# Delete XML unless -KeepXml is set
if (-not $KeepXml) {
Remove-Item $xmlFile -Force -ErrorAction SilentlyContinue
}
return $summary
}
catch {
Write-Error "Error in Test-DiskSpd: $($_.Exception.Message)"
}
finally {
# Restore original working directory
Set-Location $originalDirectory
}
}
#endregion
#region Results & Cleanup ☄️
# We save the results with a filename so descriptive, even your future self will
# know what you did. Then we clean up after ourselves, because we're not monsters.
# This is handled at the end of Test-DiskSpd.
#endregion
# Example calls
# Get-EC2DriveVolumeDetails -DriveLetter C
# Test-DiskSpd -DiskSpdDriveLetter 'M' -WritePercentage 25 -TestFileSize "20G"
# Test-DiskSpd -DiskSpdDriveLetter 'D' -WritePercentage 50 -TestFileSize "50G" -KeepTestFile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment