How to set cluster resource "Use Network Name for computer name" checkbox programmatically?

1k Views Asked by At

I am programmatically setting up a cluster resource (specifically, a Generic Service), using the Windows MI API (Microsoft.Management.Infrastructure).

I can add the service resource just fine. However, my service requires the "Use Network Name for computer name" checkbox to be checked (this is available in the Cluster Manager UI by looking at the Properties for the resource).

I can't figure out how to set this using the MI API. I have searched MSDN and multiple other resources for this without luck. Does anybody know if this is possible? Scripting with Powershell would be fine as well.

1

There are 1 best solutions below

0
On

I was able to figure this out, after a lot of trial and error, and the discovery of an API bug along the way.

It turns out cluster resource objects have a property called PrivateProperties, which is basically a property bag. Inside, there's a property called UseNetworkName, which corresponds to the checkbox in the UI (and also, the ServiceName property, which is also required for things to work).

The 'wbemtest' tool was invaluable in finding this out. Once you open the resource instance in it, you have to double-click the PrivateProperties property to bring up a dialog which has a "View Embedded" button, which is then what shows you the properties inside. Somehow I had missed this before.

Now, setting this property was yet another pain. Due to what looks like a bug in the API, retrieving the resource instance with CimSession.GetInstance() does not populate property values. This misled me into thinking I had to add the PrivateProperties property and its inner properties myself, which only resulted in lots of cryptic errors.

I finally stumbled upon this old MSDN post about it, where I realized the property is dynamic and automatically set by WMI. So, in the end, all you have to do is know how to get the property bag using CimSession.QueryInstances(), so you can then set the inner properties like any other property.

This is what the whole thing looks like (I ommitted the code for adding the resource):

using (var session = CimSession.Create("YOUR_CLUSTER", new DComSessionOptions()))
{
    // This query finds the newly created resource and fills in the
    // private props we'll change. We have to do a manual WQL query
    // because CimSession.GetInstance doesn't populate prop values.
    var query =
        "SELECT PrivateProperties FROM MSCluster_Resource WHERE Id=\"{YOUR-RES-GUID}\"";

    // Lookup the resource. For some reason QueryInstances does not like
    // the namespace in the regular form - it must be exactly like this
    // for the call to work!
    var res = session.QueryInstances(@"root/mscluster", "WQL", query).First();

    // Add net name dependency so setting UseNetworkName works.
    session.InvokeMethod(
        res,
        "AddDependency",
        new CimMethodParametersCollection
        {
            CimMethodParameter.Create(
                "Resource", "YOUR_NET_NAME_HERE", CimFlags.Parameter)
        });

    // Get private prop bag and set our props.
    var privProps =
        (CimInstance)res.CimInstanceProperties["PrivateProperties"].Value;
    privProps.CimInstanceProperties["ServiceName"].Value = "YOUR_SVC_HERE";
    privProps.CimInstanceProperties["UseNetworkName"].Value = 1;

    // Persist the changes.
    session.ModifyInstance(@"\root\mscluster", res);
}

Note how the quirks in the API make things more complicated than they should be: QueryInstances expects the namespace in a special way, and also, if you don't add the network name dependency first, setting private properties fails silently.

Finally, I also figured out how to set this through PowerShell. You have to use the Set-ClusterParameter command, see this other answer for the full info.