Genutzte Skripte:

Skript von Author: Darryl van der Peijl
Website: http://www.DarrylvanderPeijl.nl/
Email: DarrylvanderPeijl@outlook.com
Date created: 3.january.2018
Last modified: 12.february.2018
Version: 1.1

<#
	.DESCRIPTION
    
		Get-CacheDiskStatus is a script that can be used verify the boundings to cache devices
        with Storage Spaces Direct
                
	.INPUTS
 
		None
 
	.OUTPUTS
 
		None
 
	.NOTES
 
		Author: Darryl van der Peijl
		Website: http://www.DarrylvanderPeijl.nl/
		Email: DarrylvanderPeijl@outlook.com
		Date created: 3.january.2018
		Last modified: 12.february.2018
		Version: 1.1

 
	.LINK
    
		http://www.DarrylvanderPeijl.nl/
		
#>


Param (
        [parameter(Position=0, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ClusterName
)

function Get-PCStorageReportSSBCache ()
{
    BEGIN {
            $csvf = New-TemporaryFile

            function Format-SSBCacheDiskState
            ([string] $DiskState)
                {
                    $DiskState -replace 'CacheDiskState',''
                }
    }

    <#
    These are the possible DiskStates
    typedef enum
    {
        CacheDiskStateUnknown                   = 0,
        CacheDiskStateConfiguring               = 1,
        CacheDiskStateInitialized               = 2,
        CacheDiskStateInitializedAndBound       = 3,     <- expected normal operational
        CacheDiskStateDraining                  = 4,     <- expected during RW->RO change (waiting for dirty pages -> 0)
        CacheDiskStateDisabling                 = 5,
        CacheDiskStateDisabled                  = 6,     <- expected post-disable of S2D
        CacheDiskStateMissing                   = 7,
        CacheDiskStateOrphanedWaiting           = 8,
        CacheDiskStateOrphanedRecovering        = 9,
        CacheDiskStateFailedMediaError          = 10,
        CacheDiskStateFailedProvisioning        = 11,
        CacheDiskStateReset                     = 12,
        CacheDiskStateRepairing                 = 13,
        CacheDiskStateIneligibleDataPartition   = 2000,
        CacheDiskStateIneligibleNotGPT          = 2001,
        CacheDiskStateIneligibleNotEnoughSpace  = 2002,
        CacheDiskStateIneligibleUnsupportedSystem = 2003,
        CacheDiskStateIneligibleExcludedFromS2D = 2004,
        CacheDiskStateIneligibleForS2D          = 2999,
        CacheDiskStateSkippedBindingNoFlash     = 3000,
        CacheDiskStateIgnored                   = 3001,
        CacheDiskStateNonHybrid                 = 3002,
        CacheDiskStateInternalErrorConfiguring  = 9000,
        CacheDiskStateMarkedBad                 = 9001,
        CacheDiskStateMarkedMissing             = 9002,
        CacheDiskStateInStorageMaintenance      = 9003   <- expected during FRU/maint
    }
    CacheDiskState;
    #>

    PROCESS {

            $log = get-clusterlog -Node $env:computername -Destination C:\Clusterlog
            dir C:\clusterlog\*cluster.log | sort -Property BaseName |% {
            $node = "<unknown>"
            if ($_.BaseName -match "^(.*)_cluster$") {
                $node = $matches[1]
            }

            Write-Output ("-"*40) "Node: $node"


            ##
            # Parse cluster log for the SBL Disk section
            ## 

            $sr = [System.IO.StreamReader]$_.FullName

            $in = $false
            $parse = $false
            $(do {
                $l = $sr.ReadLine()
        
                # Heuristic ...
                # SBL Disks comes before System

                if ($in) {
                    # in section, blank line terminates
                    if ($l -notmatch '^\s*$') {
                        $l
                    } else {
                        # parse was good
                        $parse = $true
                        break
                    }
                } elseif ($l -match '^\[=== SBL Disks') {
                    $in = $true
                } elseif ($l -match '^\[=== System') {
                    break
                }
        
            } while (-not $sr.EndOfStream)) > $csvf

            ##
            # With a good parse, provide commentary
            ##

            if ($parse) {
                $d = import-csv $csvf

                ##
                # Table of raw data, friendly cache device numbering
                ##

                $idmap = @{}
                $d |% {
                    $idmap[$_.DiskId] = $_.DeviceNumber
                }

                
                    $d | sort IsSblCacheDevice,CacheDeviceId,DiskState | ft -AutoSize @{ Label = 'DiskState'; Expression = { Format-SSBCacheDiskState $_.DiskState }},
                        DiskId,DeviceNumber,@{
                        Label = 'CacheDeviceNumber'; Expression = {
                            if ($_.IsSblCacheDevice -eq 'true') {
                                '= cache'
                            } elseif ($idmap.ContainsKey($_.CacheDeviceId)) {
                                $idmap[$_.CacheDeviceId]
                            } elseif ($_.CacheDeviceId -eq '{00000000-0000-0000-0000-000000000000}') {
                                "= unbound"
                            } else {
                                # should be DiskStateMissing or OrphanedWaiting? Check live.
                                "= not present $($_.CacheDeviceId)"
                            }
                        }
                    },HasSeekPenalty,PathId,BindingAttributes,DirtyPages
                

                ##
                # Now do basic testing of device counts
                ##

                $dcache = $d |? IsSblCacheDevice -eq 'true'
                $dcap = $d |? IsSblCacheDevice -ne 'true'

                Write-Output "Device counts: cache $($dcache.count) capacity $($dcap.count)"
        
                ##
                # Test cache bindings if we do have cache present
                ##

                if ($dcache) {

                    # first uneven check, the basic count case
                    $uneven = $false
                    if ($dcap.count % $dcache.count) {
                        $uneven = $true
                        Write-Warning "Capacity device count does not evenly distribute to cache devices"
                    }

                    # now look for unbound devices
                    $unbound = $dcap |? CacheDeviceId -eq '{00000000-0000-0000-0000-000000000000}'
                    if ($unbound) {
                        Write-Warning "There are $(@($unbound).count) unbound capacity device(s)"
                    }

                    # unbound devices give us the second uneven case
                    if (-not $uneven -and ($dcap.count - @($unbound).count) % $dcache.count) {
                        $uneven = $true
                    }

                    $gdev = $dcap |? DiskState -eq 'CacheDiskStateInitializedAndBound' | group -property CacheDeviceId

                    if (@($gdev).count -ne $dcache.count) {
                        Write-Warning "Not all cache devices in use"
                    }

                    $gdist = $gdev |% { $_.count } | group

                    # in any given round robin binding of devices, there should be at most two counts; n and n-1

                    # single ratio
                    if (@($gdist).count -eq 1) {
                        Write-Output "Binding ratio is even: 1:$($gdist.name)"
                    } else {
                        # group names are n in the 1:n binding ratios
                        $delta = [math]::Abs([int]$gdist[0].name - [int]$gdist[1].name)

                        if ($delta -eq 1 -and $uneven) {
                            Write-Output "Binding ratios are as expected for uneven device ratios"
                        } else {
                            Write-Warning "Binding ratios are uneven"
                        }

                        # form list of group sizes
                        $s = $($gdist |% {
                            "1:$($_.name) ($($_.count) total)"
                        }) -join ", "

                        Write-Output "Groups: $s"
                    }
                }

                ##
                # Provide summary of diskstate if more than one is present in the results
                ##

                $g = $d | group -property DiskState

                if (@($g).count -ne 1) {
                    write-output "Disk State Summary:"
                    $g | sort -property Name | ft @{ Label = 'DiskState'; Expression = { Format-SSBCacheDiskState $_.Name}},@{ Label = "Number of Disks"; Expression = { $_.Count }}
                } else {
                    $gname = (($g.name) -replace 'CacheDiskState','')
                    write-output "All disks are in $gname"
                }
            }
        }
    }

    END {

        del $csvf
    }
}



Function Get-CacheDiskStatus 
{
Param (
        [parameter(Position=0, Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string]
        $ClusterName
)

    Get-clusternode -Cluster $ClusterName | % {
    
        Invoke-Command -ComputerName $_.NodeName -ScriptBlock ${Function:Get-PCStorageReportSSBCache}
    
    }

}


Get-CacheDiskStatus -ClusterName $Clustername

Eigenes Skript mit Anleitung vom MS Support für das Rebinden von Disks zu Cache Devices:

#Erste Checks
#Health Service muss Online sein
Get-ClusterResource *Health*
#Alles sollte Healthy sein
Get-VirtualDisk
Get-Volume
Get-StoragePool
Get-Disk
#Alles sollte Healthy sein
Get-PhysicalDisk | Sort-Object DeviceID
#Keine laufenden Jobs
Get-StorageJob

#Disk auswählen die im Cache-Binding Skript angemeckert wurde:
#PhysicalDisk anhand ObjectID filtern Hinter PD
Get-PhysicalDisk -ObjectId *dc6f5de*

#Variabel für pDisk erstellen
$Disk = Get-PhysicalDisk -ObjectId *dc6f5de*
#pDisk in Pause setzen
Set-PhysicalDisk -InputObject $Disk -Usage Retired
#Check Retire Status
Get-PhysicalDisk | Sort-Object Usage

#Check Footprint sollte jetzt bei 0 sein!
Get-PhysicalDisk -ObjectId *dc6f5de* | fl uni*,VirtualDiskFootprint

#Storage Job abwarten
Get-StorageJob

#Check pDisk
Get-PhysicalDisk | Sort-Object Usage


#Remove pDisk from Pool
$PDToRemove = Get-PhysicalDisk -ObjectId *dc6f5de*
Get-StoragePool
Remove-PhysicalDisk -PhysicalDisks $PDToRemove -StoragePoolFriendlyName "S2D on Cluster-4"

#Unclaiming Disk
#Info zu Unterschied zwischen Server 2016 und Server 2016
#Version für 2016 benötigt die UniquieID der Disk
Get-PhysicalDisk $Disk | FL UniquieId
$DiskUQID = Get-PhysicalDisk -UniqueId XXXXXXXXXXXXXX
#Check Variable
$DiskUQID.UniqueId
Set-ClusterStorageSpacesDirectDisk -CanBeClaimed $false -PhysicalDisk $DiskUQID.UniqueId


#Version für 2019 funktioniert mit der pDisk $Disk oben schon deklariert.
Set-ClusterStorageSpacesDirectDisk -CanBeClaimed 0 -PhysicalDisk $Disk

#Check pDisk
Get-PhysicalDisk | Sort-Object Usage

#Cleanen des Disks
Get-Disk
#Korrekte Nummer Auswählen und Ausführung des Clearens
$disknumber = "7"
Get-Disk | ? Number -e $disknumber | Set-Disk -isoffline:$false
Get-Disk | ? Number -e $disknumber | Set-Disk -isreadonly:$false
Get-Disk | ? Number -e $disknumber | Clear-Disk -RemoveData -RemoveOEM -Confirm:$false
Get-Disk | ? Number -e $disknumber | Set-Disk -isreadonly:$true
Get-Disk | ? Number -e $disknumber | Set-Disk -isoffline:$true

#Reclaiming the Disk
Get-PhysicalDisk | Sort-Object CanPool
#Health Service muss Online sein
Get-ClusterResource *Health*
(get-clusterresource health | Get-ClusterParameter).Value
#Kann jetzt wieder verbunden werden
Set-ClusterStorageSpacesDirectDisk -CanBeClaimed $true -PhysicalDisk $DiskUQID.UniqueId
#pDisk sollte sich eigentlich automatisch wieder in das Pool integrieren sonst manuell:
#$PDToAdd = Get-PhysicalDisk -ObjectId *dc6f5de9-a3fa-bc32*
#Add-PhysicalDisk -PhysicalDisks $PDToAdd -StoragePoolFriendlyName "S2D on Cluster-4"

#Check Disks
Get-PhysicalDisk | Sort-Object SerialNumber
Get-PhysicalDisk | Sort-Object Usage

#Rebalance Volume auf Disks
Get-StorageJob
Get-StoragePool -FriendlyName "S2D *" | Optimize-StoragePool

Fehler erkannt im Cache Bindings Skript

image-132 S2D: Cache Bindings Error / Rebind

Disk Id = dc6fxxxxxxxxxxxxxx

Ausführen des Skriptes Rebind S2D Disks mit der entsprechenden Disk

Ergebnis:

Disk Id = dc6fxxxxxxxxxxxxxx wieder einem Cache Device zugeordnet

image-133 S2D: Cache Bindings Error / Rebind

Info von MS:

Binding der Disks kann man auch im PerfMon überprüfen.

Node für Node unter:

Links die Disk Ids der Capacity Drives

Rechts die Disk Ids der Cache Drives

image-134 S2D: Cache Bindings Error / Rebind