PowerShell for Failover Clustering: Creating Highly Available Workloads

Hi Clustering PowerShell Scripters,

One of the things we’ve provided in Failover Clustering PowerShell is a set of CMDlets to easily create highly available workloads in a cluster.

PS C:\Windows\system32> Get-Command -Module FailoverClusters | ?{ $_.Name -like "Add-Cluster*Role" }

CommandType     Name                                                Definition
-----------     ----                                                ----------
CMDlet          Add-ClusterFileServerRole                           Add-ClusterFileServerRole [[-Name] <String>] [-S...
CMDlet          Add-ClusterGenericApplicationRole                   Add-ClusterGenericApplicationRole [[-Name] <Stri...
CMDlet          Add-ClusterGenericScriptRole                        Add-ClusterGenericScriptRole [[-Name] <String>] ...
CMDlet          Add-ClusterGenericServiceRole                       Add-ClusterGenericServiceRole [[-Name] <String>]...
CMDlet          Add-ClusterPrintServerRole                          Add-ClusterPrintServerRole [[-Name] <String>] [-...
CMDlet          Add-ClusterServerRole                               Add-ClusterServerRole [[-Name] <String>] [-Stora...
CMDlet          Add-ClusterVirtualMachineRole                       Add-ClusterVirtualMachineRole [[-Name] <String>]...

Each of the above CMDlets takes care of:

  • Creating the cluster group
  • Moving disk resource(s) into the group
  • Creating resources which may include creating the correct IP resources depending on your cluster network configuration (number of IPs and DHCP vs. static IPs)
  • Setting properties for each resource created
  • Setting dependencies between resources
  • Bringing the resources online

With that said, you’ll notice that we have not provided a CMDlet for each and every clustered workload we can create through our HA Wizard in our Failover Cluster Manager GUI. 

 

In this blog, I will show you how easy it is to create other workloads using PowerShell without the extra steps above.  The secret lies in the Add-ClusterServerRole CMDlet.

To illustrate this, I’ll be using the Microsoft Distributed Transaction Coordinator, MSDTC, role as an example. That might be useful if you’re trying to automate your SQL Server installs. Note that while this is focused on MSDTC, you can use the same concepts for other workloads.

For comparison purposes, I created a DTC workload named ahmedbc4Dtc on my cluster using the Failover Cluster Manager GUI. As seen here, that populated the group with the right resources and the correct dependencies between the resources.

 

PS C:\Windows\system32> Get-ClusterGroup ahmedbc4Dtc

Name                                    OwnerNode
----                                    ---------
ahmedbc4Dtc                             ahmedbc4-n2


PS C:\Windows\system32> Get-ClusterGroup ahmedbc4Dtc | Get-ClusterResource | ft -auto

Name                                                State  Group       ResourceType
----                                                -----  -----       ------------
ahmedbc4Dtc                                         Online ahmedbc4Dtc Network Name
Cluster Disk 6                                      Online ahmedbc4Dtc Physical Disk
IP Address 157.55.88.0 (2)                          Online ahmedbc4Dtc IP Address
IP Address 2001:4898:0:fff:200:5efe:157.55.88.0 (2) Online ahmedbc4Dtc IPv6 Tunnel Address
IP Address 2001:4898:f0:1000:: (2)                  Online ahmedbc4Dtc IPv6 Address
MSDTC-ahmedbc4Dtc                                   Online ahmedbc4Dtc Distributed Transaction Coordinator


PS C:\Windows\system32> Get-ClusterGroup ahmedbc4Dtc | Get-ClusterResource | Get-ClusterResourceDependency | ft -auto

Resource                                            DependencyExpression
--------                                            --------------------
ahmedbc4Dtc                                         [IP Address 157.55.88.0 (2)] or [IP Address 2001:4898:f0:1000:: ...
Cluster Disk 6
IP Address 157.55.88.0 (2)
IP Address 2001:4898:0:fff:200:5efe:157.55.88.0 (2) ([IP Address 157.55.88.0 (2)])
IP Address 2001:4898:f0:1000:: (2)
MSDTC-ahmedbc4Dtc                                   ([ahmedbc4Dtc]) and ([Cluster Disk 6])

 

Now, how can I create something similar with PowerShell?

The easiest way is to create a base server role with the Add-ClusterServerRole CMDlet. I named it ahmedbc4Dtc1. This CMDlet does the heavy weight lifting for you, including creating the right number of IP resources and whether they are DHCP or statically configured based on your cluster networking configuration.  It also moves the disk resource for you in the group and sets the right dependencies between the network name resource and the IP resources created.

PS C:\> Add-ClusterServerRole -Name ahmedbc4Dtc1 -Storage "Cluster Disk 7"

Name                     OwnerNode                  State
----                     ---------                  -----
ahmedbc4Dtc1             ahmedbc4-n2                Online


PS C:\> Get-ClusterGroup ahmedbc4Dtc1 | Get-ClusterResource | ft -auto

Name                                                State  Group        ResourceType
----                                                -----  -----        ------------
ahmedbc4Dtc1                                        Online ahmedbc4Dtc1 Network Name
Cluster Disk 7                                      Online ahmedbc4Dtc1 Physical Disk
IP Address 157.55.88.0 (3)                          Online ahmedbc4Dtc1 IP Address
IP Address 2001:4898:0:fff:200:5efe:157.55.88.0 (3) Online ahmedbc4Dtc1 IPv6 Tunnel Address
IP Address 2001:4898:f0:1000:: (3)                  Online ahmedbc4Dtc1 IPv6 Address


PS C:\> Get-ClusterGroup ahmedbc4Dtc1 | Get-ClusterResource | Get-ClusterResourceDependency | ft -auto

Resource                                            DependencyExpression
--------                                            --------------------
ahmedbc4Dtc1                                        [IP Address 157.55.88.0 (3)] or [IP Address 2001:4898:f0:1000:: ...
Cluster Disk 7
IP Address 157.55.88.0 (3)
IP Address 2001:4898:0:fff:200:5efe:157.55.88.0 (3) ([IP Address 157.55.88.0 (3)])
IP Address 2001:4898:f0:1000:: (3)

 

Notice it is missing the DTC resource.  So, just add that to the group and add the right dependency.  In this case, the DTC resource depends on a disk resource and network name resource as you can see above with the group I created earlier for comparison purposes through the GUI.

 

PS C:\> Get-ClusterGroup ahmedbc4Dtc1 | Add-ClusterResource -Name MSDTC-ahmedbc4Dtc1 -ResourceType "Distributed Transaction Coordinator"

Name                          State                Group                         ResourceType
----                          -----                -----                         ------------
MSDTC-ahmedbc4Dtc1            Offline              ahmedbc4Dtc1                  Distributed Transaction Co...


PS C:\> Add-ClusterResourceDependency MSDTC-ahmedbc4Dtc1 ahmedbc4Dtc1

Name                          State                Group                         ResourceType
----                          -----                -----                         ------------
MSDTC-ahmedbc4Dtc1            Offline              ahmedbc4Dtc1                  Distributed Transaction Co...

 

PS C:\> Add-ClusterResourceDependency MSDTC-ahmedbc4Dtc1 "Cluster Disk 7"

Name                          State                Group                         ResourceType
----                          -----                -----                         ------------
MSDTC-ahmedbc4Dtc1            Offline              ahmedbc4Dtc1                  Distributed Transaction Co...

 

PS C:\> Get-ClusterGroup ahmedbc4Dtc1 | Get-ClusterResource | Get-ClusterResourceDependency | ft -auto

Resource                                            DependencyExpression
--------                                            --------------------
ahmedbc4Dtc1                                        [IP Address 157.55.88.0 (3)] or [IP Address 2001:4898:f0:1000:: ...
Cluster Disk 7
IP Address 157.55.88.0 (3)
IP Address 2001:4898:0:fff:200:5efe:157.55.88.0 (3) ([IP Address 157.55.88.0 (3)])
IP Address 2001:4898:f0:1000:: (3)
MSDTC-ahmedbc4Dtc1                                  ([ahmedbc4Dtc1]) and ([Cluster Disk 7])

 

And, now, I’ll online the group.

 

PS C:\> Start-ClusterGroup ahmedbc4Dtc1

Name                                    OwnerNode                                            State
----                                    ---------                                            -----
ahmedbc4Dtc1                            ahmedbc4-n2                                          Online

 

That’s all for the group. But, one thing you’ll notice in the Failover Cluster Manager is the difference between the group the GUI created and the one I just created with PowerShell.  Notice the nice icon for the DTC group (icon beside the group name and type on the tabular view in the first diagram) and the “Manage MSDTC” action link (in the second diagram). 

 

The reason this is not the same with the group I created via PowerShell is that I didn’t set the group type for the group properly when I added the DTC resource to the group. 

PS C:\> gwmi -Namespace root/MSCluster -Class MSCluster_ResourceGroup | ?{ $_.Name -eq "ahmedbc4Dtc" } | fl Name,GroupType

Name      : ahmedbc4Dtc
GroupType : 103
 
PS C:\> gwmi -Namespace root/MSCluster -Class MSCluster_ResourceGroup | ?{ $_.Name -eq "ahmedbc4Dtc1" }| fl Name,GroupType

Name      : ahmedbc4Dtc1
GroupType : 9999

 

To “fix” this up, set the group type via WMI.

 

PS C:\> ( gwmi -Namespace root/MSCluster -Class MSCluster_ResourceGroup | ?{ $_.Name -eq "ahmedbc4Dtc1" } ).SetGroupType(103)

 

Now, you’re set.

 

Happy scripting!

 

Regards,
Ahmed Bisht
Senior Program Manager
Clustering & High-Availability
Microsoft