Public/Get-sqmClusterInfo.ps1
|
<#
.SYNOPSIS Retrieves information about a Windows Failover Cluster: cluster name, nodes and roles including IP addresses. .DESCRIPTION This function queries a Windows Failover Cluster and returns an object containing the cluster name, a list of nodes, and a list of roles (cluster groups). For each role, the associated IP address resources are also provided. By default, the core cluster group ("Cluster Group") and all storage groups ("Available Storage") are excluded from the role list. If the required PowerShell module 'FailoverClusters' is not available, an attempt is made to install the RSAT clustering tools automatically (Windows Server only, administrator rights required). .PARAMETER ClusterName The name of the cluster to query. If not specified, the function attempts to determine the local cluster (only meaningful on a cluster node). .PARAMETER IncludeCoreGroup Switch to include the core cluster group ("Cluster Group") in the roles list. Storage groups are always excluded. .PARAMETER NoAutoInstall Suppresses the automatic installation of RSAT clustering tools if the module is missing. .PARAMETER EnableException When set, errors are thrown as exceptions (by default an error object is returned). .OUTPUTS PSCustomObject with the following properties: - Success : $true on success, $false on error - ErrorMessage : Error description when Success = $false, otherwise $null - ClusterName : Name of the cluster - Nodes : Array of node objects (Name, State) - Roles : Array of role objects (Name, State, OwnerNode, IPAddresses) .EXAMPLE $info = Get-sqmClusterInfo -ClusterName "MYCLUSTER" if (-not $info.Success) { Write-Error $info.ErrorMessage; return } $info.ClusterName $info.Nodes | Format-Table $info.Roles | Where-Object OwnerNode -eq "Node1" | Select Name, IPAddresses .EXAMPLE Get-sqmClusterInfo -IncludeCoreGroup Queries the local cluster and returns all roles including the core group. .NOTES Requires administrator rights for automatic installation of RSAT tools. The function uses Invoke-sqmLogging internally for diagnostic messages. #> function Get-sqmClusterInfo { [CmdletBinding()] param ( [Parameter(Mandatory = $false)] [string]$ClusterName, [Parameter(Mandatory = $false)] [switch]$IncludeCoreGroup, [Parameter(Mandatory = $false)] [switch]$NoAutoInstall, [Parameter(Mandatory = $false)] [switch]$EnableException ) $functionName = $MyInvocation.MyCommand.Name # Hilfsfunktion fuer einheitliche Fehler-Rueckgabe function New-ErrorResult { param ([string]$Message) [PSCustomObject]@{ Success = $false ErrorMessage = $Message ClusterName = $null Nodes = $null Roles = $null } } # Pruefen, ob das FailoverClusters-Modul verfuegbar ist $moduleAvailable = $true try { $null = Get-Module -ListAvailable -Name FailoverClusters -ErrorAction Stop } catch { $moduleAvailable = $false } # Falls Modul fehlt und AutoInstall nicht unterdrueckt wurde, versuchen zu installieren if (-not $moduleAvailable -and -not $NoAutoInstall) { Invoke-sqmLogging -Message "Modul 'FailoverClusters' nicht gefunden. Versuche RSAT-Clustering-Tools zu installieren..." -FunctionName $functionName -Level "INFO" try { # Pruefen, ob das Feature RSAT-Clustering-PowerShell verfuegbar ist (Windows Server) $feature = Get-WindowsFeature -Name RSAT-Clustering-PowerShell -ErrorAction SilentlyContinue if ($feature -and $feature.Installed -eq $false) { # Installation durchfuehren (benoetigt Adminrechte) Invoke-sqmLogging -Message "Installiere Windows-Feature 'RSAT-Clustering-PowerShell'..." -FunctionName $functionName -Level "INFO" $installResult = Install-WindowsFeature -Name RSAT-Clustering-PowerShell -IncludeManagementTools -ErrorAction Stop if ($installResult.Success -eq $false) { throw "Installation von 'RSAT-Clustering-PowerShell' fehlgeschlagen." } Invoke-sqmLogging -Message "Feature 'RSAT-Clustering-PowerShell' erfolgreich installiert." -FunctionName $functionName -Level "INFO" } else { # Versuche mit Add-WindowsCapability fuer Windows 10/11 (Client) $capability = Get-WindowsCapability -Online | Where-Object { $_.Name -like 'Rsat.Clustering*' -and $_.State -eq 'NotPresent' } if ($capability) { Invoke-sqmLogging -Message "Installiere Windows Capability 'Rsat.Clustering'..." -FunctionName $functionName -Level "INFO" Add-WindowsCapability -Online -Name $capability.Name -ErrorAction Stop Invoke-sqmLogging -Message "Capability 'Rsat.Clustering' erfolgreich installiert." -FunctionName $functionName -Level "INFO" } else { throw "Kein installierbares RSAT-Clustering-Paket gefunden. Bitte installieren Sie die RSAT-Tools manuell." } } # Nach erfolgreicher Installation: Modul neu laden Import-Module -Name FailoverClusters -Force -ErrorAction Stop Invoke-sqmLogging -Message "Modul 'FailoverClusters' erfolgreich geladen." -FunctionName $functionName -Level "INFO" $moduleAvailable = $true } catch { $errMsg = "Fehler bei automatischer Installation der RSAT-Clustering-Tools: $_" Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } } # Falls Modul immer noch nicht verfuegbar (und keine AutoInstall oder Fehler) if (-not $moduleAvailable) { $errMsg = "Das PowerShell-Modul 'FailoverClusters' ist nicht verfuegbar. Bitte installieren Sie die RSAT-Clustering-Tools." Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } # Modul importieren (falls noch nicht geladen) try { Import-Module -Name FailoverClusters -ErrorAction Stop } catch { $errMsg = "Fehler beim Importieren des Moduls 'FailoverClusters': $_" Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } # Parameter fuer Get-Cluster vorbereiten $clusterParams = @{ } if ($ClusterName) { $clusterParams['Name'] = $ClusterName } # Cluster-Objekt abrufen $cluster = $null try { $cluster = Get-Cluster @clusterParams -ErrorAction Stop } catch { $errMsg = "Fehler beim Abrufen des Clusters: $_" Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } if (-not $cluster) { $errMsg = "Es wurde kein Cluster gefunden. Stellen Sie sicher, dass das Skript auf einem Clusterknoten ausgefuehrt wird oder geben Sie einen gueltigen Clusternamen an." Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "WARNING" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } $clusterNameValue = $cluster.Name # Knoten (Nodes) abrufen $nodes = $null try { $nodes = Get-ClusterNode -Cluster $cluster -ErrorAction Stop | ForEach-Object { [PSCustomObject]@{ Name = $_.Name State = $_.State } } } catch { $errMsg = "Fehler beim Abrufen der Clusterknoten: $_" Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } # Rollen (Cluster Groups) abrufen $groups = $null try { $groups = Get-ClusterGroup -Cluster $cluster -ErrorAction Stop } catch { $errMsg = "Fehler beim Abrufen der Clustergruppen: $_" Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } # Cluster-Ressourcen abrufen (einmalig) $allResources = $null try { $allResources = Get-ClusterResource -Cluster $cluster -ErrorAction Stop } catch { $errMsg = "Fehler beim Abrufen der Clusterressourcen: $_" Invoke-sqmLogging -Message $errMsg -FunctionName $functionName -Level "ERROR" if ($EnableException) { throw $errMsg } return New-ErrorResult $errMsg } # Rollen filtern und mit IP-Adressen anreichern $roles = foreach ($group in $groups) { if ($group.GroupType -eq 'AvailableStorage') { continue } if (-not $IncludeCoreGroup -and $group.Name -match '^Cluster Group$') { continue } $ipResources = $allResources | Where-Object { $_.OwnerGroup -eq $group.Name -and $_.ResourceType -eq 'IP Address' } $ipAddresses = foreach ($ipRes in $ipResources) { $addrParam = $null try { $addrParam = $ipRes | Get-ClusterParameter -Name Address -ErrorAction SilentlyContinue } catch { } if ($addrParam -and $addrParam.Value) { $addrParam.Value } else { $ipRes.Address } } [PSCustomObject]@{ Name = $group.Name State = $group.State OwnerNode = $group.OwnerNode IPAddresses = @($ipAddresses) } } # Erfolgs-Rueckgabe Invoke-sqmLogging -Message "Cluster-Info erfolgreich abgerufen: $clusterNameValue, $($nodes.Count) Knoten, $($roles.Count) Rollen" -FunctionName $functionName -Level "INFO" [PSCustomObject]@{ Success = $true ErrorMessage = $null ClusterName = $clusterNameValue Nodes = $nodes Roles = $roles } } |