如何在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
相关产品推荐
相关产品推荐

