Hey Checkyourlogs Fans,
Recently I have been working on a Storage Spaces Direct project with an amazing scripter and Dev/OPS admin named Sammy Shuck. He has taken the liberty to clean up the code in the Clear-SDSConfig.PS1. As many of you know I love to use this script to factory reset Storage Spaces Direct Nodes. The source script can be found at the Technet Scripting Gallery.
https://gallery.technet.microsoft.com/scriptcenter/Completely-Clearing-an-ab745947
The issue with this script is there isn’t much for logging included with it. So, what Sammy has done is added some additional warning contexts to the code and then generate an eventlog entry when the script is run.
You can check out his code and his Github Repositories here: https://raw.githubusercontent.com/ToxicSamN/powershell/master/hyperv/Nuke-ClusterAndS2D.ps1
Let’s have a look at the script in action shall we.
For my test I have recently updated to Windows Server 2019 LTSC on some of my lab nodes and they have an orphaned Storage Spaces Direct Configuration.
When I run Get-PhysicalDisk you can see the output with my node having a bunch of disks with Lost Communication.
I just want to Factory Reset Storage Spaces Direct and prepare these nodes to be rejoined to a newly created Cluster. When we do the factory reset I expect that the disks will come back to a state of CanPool =True
On with the show…. I have downloaded the code form Sammy’s Github repo and I just need to run this via an Administrative PowerShell Prompt.
Here is the output by simply running this on the node.
After running the script my disks were returned to Disk Management and it appears to have nicely cleaned them for me.
Let’s try Get-PhysicalDisk on more time.
As we can see the CanPool property is now True which means these are ready for me to commence the build of Storage Spaces Direct again.
Finally, let’s have a look at the EventID 1337 that was created as part of this script’s execution.
Here is the code from the script. I think this one just might make it into Master PowerShell Tricks V4.
################################## WARNING ################################ # # # *** USE AT YOUR OWN RISK *** # # PERMANANT DATA LOSS WILL OCCUR # # # # This script completely clears any existing Storage Spaces configuration # # and all data on EVERY non-system drive PERMANENTLY! # # # # Notes: # # # # If certain drives cannot be cleared and the reason given is # # 'Redundant Path' then MPIO may need to be installed and/or configured. # # # # Power cycling the JBOD enclosures can also remove additional # # errors encountered during the run. # # # # Run cmdlet with Administrator rights. # # # ################################## WARNING ################################ ################################# Change Log ################################ # # # 02/13/2014: Changed logic to remove SAS-connected boot/system disks # # 02/13/2014: Changed output for clearing disks and tracking runtime # # 04/07/2014: Corrected logic to deal boot and system drives # # 04/07/2014: Added logic to deal with non-core cluster objects # # 07/23/2015: Changes to better support Storage Spaces Direct # # 04/23/2018: Added warnings and Event logging (github.com/ToxicSamN) # # # ############################################################################# [CmdletBinding(SupportsShouldProcess=$true, ConfirmImpact="High")] param() $warning_msg1 = "PERMANANT DATA LOSS WILL OCCUR!!!`nIf your intention is to Nuke the configuration of ONLY THIS NODE $($env:ComputerName) then you MUST ensure this node has been evicted from the cluster first.`nIf not then this could Nuke the configuration of EVERY node in the cluster.`nExercise caution!" $confirm_prompt1 = "By Continuing you are acknowledging that you understand this process fully and understand this will completely wipe ALL data and there is NO recovery.`nWould you like to continue? (y/n): " $confirm_prompt2 = "This is your last chance, there is no going back after this. Data will be lost.`nAre you absolutely sure you would like to continue? (y/n): " Write-Warning $warning_msg1 $usr_input1 = Read-Host $confirm_prompt1 if ($usr_input1 -eq "y" -or $usr_input1 -eq "yes"){ $usr_input2 = Read-Host $confirm_prompt2 if ($usr_input2 -ne "y" -and $usr_input2 -ne "yes") { exit -1 } else{ $nuke_info = "Username: $(whoami)`nComputerName: $($env:ComputerName)`nClusterStatus: `n`tMemberOf: $((Get-Cluster).Name)`nMessage: Node was wiped with script Nuke-ClusterAndS2D.ps1 by user $(whoami)`n `nUser was warned: `n$($warning_msg1) `nUser Acknowledged Data Destruction:`n$($confirm_prompt1) $($usr_input1) `nUser Was warned a final time: `n$($confirm_prompt2) $($usr_input2) " Write-Warning "The following information is being logged: $($nuke_info)" # attempt to register a new Event Log source. If already registered then throw an exception and continue. this suppresses the error try{New-EventLog -LogName "System" -Source "Nuke-ClusterAndS2D" -MessageResourceFile "C:\utils\NukeClusterS2D.dll" -ErrorAction Stop | Out-Null}catch{<#Do Nothing#>} Write-EventLog -LogName "System" -Source "Nuke-ClusterAndS2D" -EventID 1337 -EntryType Warning -Message $nuke_info } }else{ exit -1 } if ($PSCmdlet.ShouldProcess("localhost","Clear Storage Spaces configuration and wipe disks")) { Write-Host "" Write-Host Clearing existing Storage Spaces configuration and wiping disks... Write-Host "" $runStart = [DateTime]::Now # Install necessary tools if needed $toolsInstalled = $false if (!(Get-WindowsFeature -Name "RSAT-Clustering-PowerShell").Installed) { Write-Host Installing required tools... -ForegroundColor Cyan -NoNewline Install-WindowsFeature -Name "RSAT-Clustering-PowerShell" $toolsInstalled = $true Write-Host Done. Write-Host "" } # Remove any cluster objects if present Write-Host "Removing any cluster objects" -NoNewline -ForegroundColor Cyan Write-Host "..." -NoNewline foreach ($clusterGroup in (Get-ClusterGroup -ErrorAction SilentlyContinue -WarningAction SilentlyContinue)) { if (!$clusterGroup.IsCoreGroup) { Remove-ClusterGroup -Name $clusterGroup.Name -Force:$true -RemoveResources:$true -ErrorAction SilentlyContinue } } Remove-Cluster -Force -CleanupAD -ErrorAction SilentlyContinue -WarningAction SilentlyContinue Write-Host "Done." $disks = Get-PhysicalDisk | Where-Object {($_.BusType -EQ "SAS") -or ($_.BusType -EQ "SATA")} # -or ($_.BusType -EQ "RAID")} Write-Host "" Write-Host "Removing any stale PRs" -NoNewline -ForegroundColor Cyan Write-Host "..." -NoNewline foreach ($disk in $disks) { Clear-ClusterDiskReservation -Disk $disk.DeviceId -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } Write-Host "Done." Write-Host "" Write-Host "Updating the storage provider cache (x2)" -NoNewline -ForegroundColor Cyan Write-Host "..." -NoNewline Update-StorageProviderCache -DiscoveryLevel Full Start-Sleep 1 Update-StorageProviderCache -DiscoveryLevel Full Write-Host "Done." # Remove virtual disks and storage pools Write-Host "" Write-Host "Removing Virtual Disks and Pools" -NoNewline -ForegroundColor Cyan Write-Host "..." -NoNewline $storagePools = Get-StoragePool | ? FriendlyName -NE "primordial" $storagePools | Set-StoragePool -IsReadOnly:$false Get-VirtualDisk | Set-VirtualDisk -IsManualAttach:$false Get-VirtualDisk | Remove-VirtualDisk -Confirm:$false $storagePools | Remove-StoragePool -Confirm:$false Write-Host "Done." Write-Host "" Write-Host "Updating the storage provider cache (x2)" -NoNewline -ForegroundColor Cyan Write-Host "..." -NoNewline Update-StorageProviderCache -DiscoveryLevel Full Start-Sleep 1 Update-StorageProviderCache -DiscoveryLevel Full Write-Host "Done." Write-Host "" # Collect IDs of any system/boot disks $disks = Get-Disk $diskIdsToRemove = @() foreach ($disk in $disks) { if ($disk.IsBoot -or $disk.IsSystem) { $diskIdsToRemove += $disk.UniqueId } } # Get collection of physical disks $allPhysicalDisks = Get-PhysicalDisk | Where-Object {($_.BusType -EQ "SAS") -or ($_.BusType -EQ "SATA")} # -or ($_.BusType -EQ "RAID")} # Create a new collection of physical disks without any system/boot disks $physicalDisks = @() foreach ($physicalDisk in $allPhysicalDisks) { $addDisk = $true foreach ($diskIdToRemove in $diskIdsToRemove) { if ($physicalDisk.UniqueId -eq $diskIdToRemove) { $addDisk = $false } } if ($addDisk) { $physicalDisks += $physicalDisk } } # Iterate through all remaining physcial disks and wipe Write-Host "Cleaning disks" -ForegroundColor Cyan -NoNewline Write-Host "..." $totalDisks = $physicalDisks.Count $counter = 1 foreach ($physicalDisk in $physicalDisks) { $disk = $physicalDisk | Get-Disk # Make sure disk is Online and not ReadOnly otherwise, display reason # and continue $disk | Set-Disk –IsOffline:$false -ErrorAction SilentlyContinue $disk | Set-Disk –IsReadOnly:$false -ErrorAction SilentlyContinue # Re-instantiate disks to update changes $disk = $physicalDisk | Get-Disk if ($disk.IsOffline -or $disk.IsReadOnly) { Write-Host "Warning: " -NoNewline -ForegroundColor Yellow Write-Host "Unable to process disk " -NoNewline Write-Host $disk.Number -NoNewline Write-Host ": Offline Reason: " -NoNewline Write-Host ($disk.OfflineReason) -NoNewline -ForegroundColor Yellow Write-Host ", HealthStatus: " -NoNewline Write-Host $disk.HealthStatus -ForegroundColor Yellow } else { Write-Host "Cleaning disk " -NoNewline Write-Host $disk.Number -NoNewline -ForegroundColor Cyan Write-Host " (" -NoNewline Write-Host $counter -NoNewline -ForegroundColor Cyan Write-Host " of " -NoNewline Write-Host $totalDisks -NoNewline -ForegroundColor Cyan Write-Host ")..." -NoNewline # Wipe disk and initialize $disk | ? PartitionStyle -NE "RAW" | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false $disk | Initialize-Disk -PartitionStyle GPT Write-Host Done. } $counter++ } # Remove any installed roles/tools if ($toolsInstalled) { Write-Host Uninstalling Failover Cluster tool... -NoNewline -ForegroundColor Cyan Remove-WindowsFeature -Name "Failover-Clustering","RSAT-Clustering-PowerShell" Write-Host Done. } Write-Host "" Write-Host "Updating the storage provider cache (x2)" -NoNewline -ForegroundColor Cyan Write-Host "..." -NoNewline Update-StorageProviderCache -DiscoveryLevel Full Start-Sleep 1 Update-StorageProviderCache -DiscoveryLevel Full Write-Host "Done." # Output physical disk counts Write-Host "" Write-Host Physical Disks: Get-PhysicalDisk | Group-Object Manufacturer,Model,MediaType,Size | ft Count,Name -AutoSize Write-Host Configuration and data cleared! Write-Host "" Write-Host "Run duration: " -NoNewline Write-Host ([Math]::Round((([DateTime]::Now).Subtract($runStart)).TotalMinutes,2)) -ForegroundColor Yellow -NoNewline Write-Host " minutes" }
Thanks,
Dave
Hey Dave, I know this is an old one but there is a small change that makes it better:
$allPhysicalDisks = Get-PhysicalDisk | Where-Object {($_.BusType -EQ “SAS”) -or ($_.BusType -EQ “SATA”)} # -or ($_.BusType -EQ “RAID”)}
should really be:
$allPhysicalDisks = Get-PhysicalDisk | Where-Object {($_.BusType -EQ “SAS”) -or ($_.BusType -EQ “SATA”) -or ($_.BusType -EQ “NVME”)} # -or ($_.BusType -EQ “RAID”)}
For those who have NVME disks in the S2D configurations.