Search code examples
powershellpowershell-remoting

How to Capture Cluster info Remotely from a non-Clustered Node


I've been banging my head on this for a few days now, and I just can't figure out the best way to do it. I've got a script where I collect a bunch of data and output it to an html file (using PSWriteHTML Module, which is where the New-HTMLTable at the end comes from).

I've piecemealed the script together over time so I can gather the data from multiple servers at once, and for the most part, it all works great. As I've added data to the script to collect new info, there's a few parts that I just can't get to work right remotely. I know the piecemeal approach has left me with some redundant code, but I'm just trying to make it all work right before I re-write it again to clean it up, so my apologies for its current state.

The following code works great when I run the script from a server in a Windows Cluster, but I want things to work from any server, not necessarily a Cluster Node.

Here's orig code for this section:

try
{
    $ClusterIPInfo = Invoke-command -computer $Computer {
        Get-Cluster | Get-ClusterResource | %{
            $_ | select Name,
                        @{ Name = "Address"; Expression = { $_ | Get-ClusterParameter -Name Address -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
                        @{ Name = "SubnetMask"; Expression = { $_ | Get-ClusterParameter -Name SubnetMask -ErrorAction SilentlyContinue | select -ExpandProperty Value } }
        }
    } | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
    
    $ClusterResourceInfo = Invoke-command -computer $Computer {
        Get-ClusterResource | Select Cluster, Name, State, ResourceType, OwnerGroup, OwnerNode, ID, IsCoreResource, IsNetworkClassResource, IsStorageClassResource | Sort-Object -Property OwnerGroup, Name
    } | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
    
    $ResourceInfo = @()
    
    
    foreach ($rec in $ClusterResourceInfo)
    {
        $Owner = (Get-ClusterResource | Sort-Object -Property OwnerGroup, Name | Get-ClusterOwnerNode | %{
                $_ | select @{ Name = "Name"; Expression = { $_.ClusterObject } },
                            @{ Name = "PossibleOwners"; Expression = { $_.OwnerNodes } }
            } | Where { $_.Name -eq $rec.Name }).PossibleOwners
        
        $Dependency = (Get-ClusterResource | Sort-Object -Property OwnerGroup, Name | Get-ClusterResourceDependency | %{
                $_ | select @{ Name = "Name"; Expression = { $_.Resource } },
                            @{ Name = "Dependency"; Expression = { $_ | Select-Object -ExpandProperty "DependencyExpression" } }
                
            } | Where { $_.Name -eq $rec.Name }).Dependency
        
        $address = ($ClusterIPInfo | Where { $_.Name -eq $rec.Name }).Address
        $subnetmask = ($ClusterIPInfo | Where { $_.Name -eq $rec.Name }).SubnetMask
        
        
        $recObj = New-Object PSObject
        
        $recObj | Add-Member NoteProperty -Name "Cluster" -Value $rec.Cluster
        $recObj | Add-Member NoteProperty -Name "Name" -Value $rec.Name
        $recObj | Add-Member NoteProperty -Name "State" -Value $rec.State
        $recObj | Add-Member NoteProperty -Name "Resource Type" -Value $rec.ResourceType
        $recObj | Add-Member NoteProperty -Name "Owner Group" -Value $rec.OwnerGroup
        $recObj | Add-Member NoteProperty -Name "Owner Node" -Value $rec.OwnerNode
        $recObj | Add-Member NoteProperty -Name "Possible Owners" -Value $Owner
        $recObj | Add-Member NoteProperty -Name "Dependency" -Value $Dependency
        $recObj | Add-Member NoteProperty -Name "IP Address" -Value $address
        $recObj | Add-Member NoteProperty -Name "Subnet Mask" -Value $subnetmask
        $recObj | Add-Member NoteProperty -Name "Is Core Resource" -Value $rec.IsCoreResource
        $recObj | Add-Member NoteProperty -Name "Is Network Resource" -Value $rec.IsNetworkClassResource
        $recObj | Add-Member NoteProperty -Name "Is Storage Resource" -Value $rec.IsStorageClassResource
        
        
        $ResourceInfo += $recObj
    }
    
    New-HTMLTable -DataTable $ResourceInfo -HideFooter -HideButtons -DisableSearch

The parts that don't work correctly remotely are the Dependency and PossibleOwners. I know the reason it doesn't work is because when the server running the script isn't a Cluster Node, it doesn't recognize the command under the Foreach loop Get-ClusterResource. But I just can't figure out how to make those pass correctly from within the Foreach loop, but still use the info from $ClusterResourceInfo.

I've re-written this a hundred different ways, i.e. make a single Invoke-command with basically one big Get-Cluster variable (couldn't get it to capture the Dependency/PossOwners, always $null), splitting up the Dependency and PossOwners to their own separate Invoke-Command (best I can get it to do is display System.Object[], or when I did get it to display, it captured ALL of the Dependencies for all objects and displayed on every line instead of splitting it up correctly).

I've tried every possible way I can think of or found online, but just can't get it to work correctly remotely.

Here's how the orig code above outputs (which is what I want, but I just want to fix it so it works remotely):

Output

I am desperately hoping for some brilliance or guidance to set me on the right track. I tried so many ways, but just never quite got it where it needs to be, so any help is most appreciated and welcome. Thanks.


Solution

  • So the piecemeal approach is what got me in trouble. In trying to merge things together, I kept breaking it (mainly because I think had doubled up the %{}). So instead of merging, I just replicated the parts that were already working as intended.

    Ultimately this code worked fine:

    $ClusterInfo = Invoke-command -computer $Computer {
                                                Get-Cluster | Get-ClusterResource | %{
                                                    $_ | select Name,
                                                                @{ Name = "Address"; Expression = { $_ | Get-ClusterParameter -Name Address -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
                                                                @{ Name = "SubnetMask"; Expression = { $_ | Get-ClusterParameter -Name SubnetMask -ErrorAction SilentlyContinue | select -ExpandProperty Value } },
                                                                @{ Name = "PossibleOwners"; Expression = { $_ | Get-ClusterOwnerNode | select  OwnerNodes | select -ExpandProperty OwnerNodes } },
                                                                @{ Name = "Dependency"; Expression = { $_ | Get-ClusterResourceDependency | select -ExpandProperty "DependencyExpression" } }
                                                }
                                            } | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
                                            
                                            $ClusterResourceInfo = Invoke-command -computer $Computer {
                                                Get-ClusterResource | Select Cluster, Name, State, ResourceType, OwnerGroup, OwnerNode, IsCoreResource, IsNetworkClassResource, IsStorageClassResource | Sort-Object -Property OwnerGroup, Name
                                            } | Select -Property * -ExcludeProperty PSComputerName, RunSpaceID, PSShowComputerName
                                            
                                            $ResourceInfo = @()
                                            
                                            
                                            foreach ($rec in $ClusterResourceInfo)
                                            {
                            
    
                                                $Owner = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).PossibleOwners
                                                $Dependency = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).Dependency
                                                $address = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).Address
                                                $subnetmask = ($ClusterInfo | Where { $_.Name -eq $rec.Name }).SubnetMask
                                                
                                                
                                                $recObj = New-Object PSObject
                                                
                                                $recObj | Add-Member NoteProperty -Name "Cluster" -Value $rec.Cluster
                                                $recObj | Add-Member NoteProperty -Name "Name" -Value $rec.Name
                                                $recObj | Add-Member NoteProperty -Name "State" -Value $rec.State
                                                $recObj | Add-Member NoteProperty -Name "Resource Type" -Value $rec.ResourceType
                                                $recObj | Add-Member NoteProperty -Name "Owner Group" -Value $rec.OwnerGroup
                                                $recObj | Add-Member NoteProperty -Name "Owner Node" -Value $rec.OwnerNode
                                                $recObj | Add-Member NoteProperty -Name "Possible Owners" -Value $Owner
                                                $recObj | Add-Member NoteProperty -Name "Dependency" -Value $Dependency
                                                $recObj | Add-Member NoteProperty -Name "IP Address" -Value $address
                                                $recObj | Add-Member NoteProperty -Name "Subnet Mask" -Value $subnetmask
                                                $recObj | Add-Member NoteProperty -Name "Is Core Resource" -Value $rec.IsCoreResource
                                                $recObj | Add-Member NoteProperty -Name "Is Network Resource" -Value $rec.IsNetworkClassResource
                                                $recObj | Add-Member NoteProperty -Name "Is Storage Resource" -Value $rec.IsStorageClassResource
                                                
                                                
                                                $ResourceInfo += $recObj
                                            }
                                            
                                            New-HTMLTable -DataTable $ResourceInfo -HideFooter -HideButtons -DisableSearch