You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SCCM中通过C#从集合移除单个资源

SCCM WMI 删除直接成员规则问题

问题背景

我对WMI了解不够深入,不清楚问题出在哪里,但看起来逻辑上可行却无法正常运行。

已成功使用以下代码向SCCM集合添加资源:

private void Add_SCCM(DirectoryObject selectedObject)
{
    string computerName = selectedObject.Name;

    try
    {
        // Connect to SCCM WMI namespace
        ManagementScope scope = new ManagementScope(@"\\MyCOMPUTER\root\sms\site_XXX");
        scope.Connect();

        // Query ResourceID of the computer
        string query = $"SELECT ResourceID FROM SMS_R_System WHERE Name = '{computerName}'";
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, new ObjectQuery(query));
        ManagementObjectCollection results = searcher.Get();

        string resourceId = null;
        foreach (ManagementObject result in results)
        {
            resourceId = result["ResourceID"]?.ToString();
        }

        if (!string.IsNullOrEmpty(resourceId))
        {
            // Check if the computer is already in the collection as a direct rule
            string ruleQuery = $"SELECT * FROM SMS_FullCollectionMembership WHERE CollectionID = '{SCCM_COLLID}' AND ResourceID = '{resourceId}'";
            ManagementObjectSearcher ruleSearcher = new ManagementObjectSearcher(scope, new ObjectQuery(ruleQuery));
            ManagementObjectCollection ruleResults = ruleSearcher.Get();

            if (ruleResults.Count > 0)
            {
                string infoTitle = "Information";
                string infoMessage = $"Computer {computerName} is already part of the SCCM collection {SCCM_COLLID}. Skipping.";
                MessageBox.Show(infoMessage, infoTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
                return; // Exit without adding
            }

            // Instantiate a direct membership rule
            ManagementClass ruleClass = new ManagementClass(scope, new ManagementPath("SMS_CollectionRuleDirect"), null);
            ManagementObject ruleInstance = ruleClass.CreateInstance();
            ruleInstance["ResourceClassName"] = "SMS_R_System";
            ruleInstance["ResourceID"] = resourceId;
            ruleInstance["RuleName"] = computerName;

            // Add the membership rule to the SCCM collection
            ManagementPath collectionPath = new ManagementPath($"SMS_Collection.CollectionID='{SCCM_COLLID}'");
            ManagementObject collection = new ManagementObject(scope, collectionPath, null);

            ManagementBaseObject inParams = collection.GetMethodParameters("AddMembershipRule");
            inParams["CollectionRule"] = ruleInstance;

            collection.InvokeMethod("AddMembershipRule", inParams, null);

            string successTitle = "Success";
            string successMessage = $"Successfully added {computerName} to SCCM collection {SCCM_COLLID}";
            MessageBox.Show(successMessage, successTitle, MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        else
        {
            string errorTitle = "Error";
            string errorMessage = $"Failed to find ResourceID for computer: {computerName}";
            MessageBox.Show(errorMessage, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    catch (Exception ex)
    {
        string errorTitle = "Error";
        string errorMessage = $"Error adding {computerName} to SCCM collection {SCCM_COLLID}: {ex.Message}";
        MessageBox.Show(errorMessage, errorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

但遇到删除问题:SCCM的SMS_Collection类没有GetRules方法,无法获取规则后调用DeleteMembership方法删除。ChatGPT给出的以下代码会导致无效查询:

// Query the collection rule
string query = $"SELECT * FROM SMS_CollectionRuleDirect WHERE ResourceID IN " +
               $"(SELECT ResourceID FROM SMS_R_System WHERE Name = '{computerName}')";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, new ObjectQuery(query));
ManagementObjectCollection results = searcher.Get();

foreach (ManagementObject rule in results)
{
    rule.Delete();
}

解决方案

核心问题说明

  • 直接查询SMS_CollectionRuleDirect时必须指定CollectionID,否则会遍历所有集合的规则,且无法定位到目标集合中的规则。
  • SCCM WMI不支持直接调用rule.Delete()删除成员规则,必须通过SMS_Collection类的DeleteMembershipRule方法完成删除操作。

正确的删除代码示例

private void Remove_SCCM(DirectoryObject selectedObject)
{
    string computerName = selectedObject.Name;
    string targetCollectionId = SCCM_COLLID; // 替换为你的目标集合ID

    try
    {
        // 连接SCCM WMI命名空间
        ManagementScope scope = new ManagementScope(@"\\MyCOMPUTER\root\sms\site_XXX");
        scope.Connect();

        // 1. 获取目标计算机的ResourceID
        string resourceQuery = $"SELECT ResourceID FROM SMS_R_System WHERE Name = '{computerName}'";
        ManagementObjectSearcher resourceSearcher = new ManagementObjectSearcher(scope, new ObjectQuery(resourceQuery));
        ManagementObjectCollection resourceResults = resourceSearcher.Get();
        
        if (resourceResults.Count == 0)
        {
            MessageBox.Show($"未找到计算机「{computerName}」的ResourceID", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

        string resourceId = null;
        foreach (ManagementObject resource in resourceResults)
        {
            resourceId = resource["ResourceID"].ToString();
            break;
        }

        // 2. 查询目标集合中关联该计算机的直接成员规则
        string ruleQuery = $"SELECT * FROM SMS_CollectionRuleDirect WHERE CollectionID = '{targetCollectionId}' AND ResourceID = '{resourceId}'";
        ManagementObjectSearcher ruleSearcher = new ManagementObjectSearcher(scope, new ObjectQuery(ruleQuery));
        ManagementObjectCollection ruleResults = ruleSearcher.Get();
        
        if (ruleResults.Count == 0)
        {
            MessageBox.Show($"计算机「{computerName}」不在集合「{targetCollectionId}」中", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            return;
        }

        // 3. 获取集合对象并调用删除方法移除规则
        ManagementPath collectionPath = new ManagementPath($"SMS_Collection.CollectionID='{targetCollectionId}'");
        ManagementObject collection = new ManagementObject(scope, collectionPath, null);

        foreach (ManagementObject rule in ruleResults)
        {
            ManagementBaseObject inParams = collection.GetMethodParameters("DeleteMembershipRule");
            inParams["CollectionRule"] = rule;
            collection.InvokeMethod("DeleteMembershipRule", inParams, null);
        }

        MessageBox.Show($"成功从集合「{targetCollectionId}」中移除计算机「{computerName}」", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
    catch (Exception ex)
    {
        MessageBox.Show($"移除失败:{ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

关键要点

  • 必须通过CollectionID过滤SMS_CollectionRuleDirect,确保只查询目标集合中的规则。
  • 删除操作必须借助SMS_Collection的DeleteMembershipRule方法,传入对应的SMS_CollectionRuleDirect实例作为参数。
  • 异常处理需覆盖连接失败、ResourceID未找到、规则不存在等场景,提升代码健壮性。

内容的提问来源于stack exchange,提问作者dragonspeed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 09:47:35