C# .NET获取AD计算机的完整属性列表(以匹配Powershell获取AD计算机API)

C# .NET获取AD计算机的完整属性列表(以匹配Powershell获取AD计算机API),c#,.net,powershell,active-directory,C#,.net,Powershell,Active Directory,我正在将Powershell代码转换为C#,在Powershell中我将此API称为“Get ADComputer”。当您查看链接中的示例时,它显示了可以返回的属性的详尽列表 我试图在C#中复制这一点,但我得到了Powershell调用返回的一个子集。例如,我正在寻找“PrimaryGroup”,它只会在Powershell调用中返回 以下是代码片段: 动力壳 Get-ADComputer -Filter "*" -Properties "*" C# 使用系统; 使用System.Collec

我正在将Powershell代码转换为C#,在Powershell中我将此API称为“Get ADComputer”。当您查看链接中的示例时,它显示了可以返回的属性的详尽列表

我试图在C#中复制这一点,但我得到了Powershell调用返回的一个子集。例如,我正在寻找“PrimaryGroup”,它只会在Powershell调用中返回

以下是代码片段:

动力壳

Get-ADComputer -Filter "*" -Properties "*"
C#

使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.DirectoryServices;
使用System.DirectoryServices.ActiveDirectory;
使用System.IO;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
名称空间测试
{
班级计划
{
静态void Main(字符串[]参数)
{
foreach(GetProperties()中的var p)
控制台写入线(p);
}
私有静态IEnumerable GetDomainNames()
{
ICollection域=新列表();
foreach(林中的域。GetCurrentForest().Domains)
domains.Add(domain.Name);
返回域;
}
公共静态列表GetProperties()
{
列表属性=新列表();
foreach(GetDomainNames()中的var domainName)
{
使用(DirectoryEntry DirectoryEntry=newdirectoryentry(@“LDAP://”+domainName))
{
使用(DirectorySearcher mysearch=newdirectorysearcher(directoryEntry))
{
mySearcher.Filter=(“(objectClass=computer)”);
mySearcher.SizeLimit=0;//没有大小限制
mySearcher.PageSize=250;//分页
mySearcher.PropertiesToLoad.Add(“PrimaryGroup”);//只需要此属性,对于测试,请注释掉此行以获取返回的所有属性
foreach(在mySearcher.FindAll()中重新发送搜索结果)
{
foreach(resEnt.Properties.PropertyNames中的var p)
添加(p.ToString());
}
}
}
}
properties.Sort();
归还财产;
}
}
}
我猜我只是没有完全正确地设置C代码中的所有内容。我得到了许多相同的财产,但不是全部。我希望得到指导

谢谢。

PowerShell有时会对属性使用“显示名称”,而AD中属性的实际名称略有不同。PowerShell还添加了一些属性,可以将AD中的一些数据转换为有用的内容。这就是一个例子

PrimaryGroup
属性返回主组的可分辨名称。但是,在AD中没有存储该属性的属性。主要组由
primaryGroupId
属性确定,该属性是组的RID(相对标识符)

因此,您必须请求
primaryGroupId
属性并将其转换为实际的组。我写了一篇文章,介绍了我在哪里分享的一种方法。它接受一个
DirectoryEntry
,但它实际上只需要知道
primaryGroupId
objectSid
(因为它使用用户的SID来构造组的SID):

私有静态字符串GetUserPrimaryGroup(DirectoryEntry de){
de.RefreshCache(新[]{“primaryGroupID”,“objectSid”});
//以字符串形式获取用户的SID
var sid=new SecurityIdentifier((字节[])de.Properties[“objectSid”].Value,0.ToString();
//用primaryGroupId替换用户SID的RID部分
//我们只剩下小组的SID了
sid=sid.Remove(sid.LastIndexOf(“-”,StringComparison.Ordinal)+1);
sid=sid+de.Properties[“primaryGroupId”].Value;
//按组的SID查找组
var group=newdirectoryEntry($“LDAP://”);
RefreshCache(新[]{“cn”});
返回组。属性[“cn”]。值为字符串;
}
您应该能够对其进行调整,以便从DirectorySearcher中提取值


作为旁注,如果不触摸
PropertiesToLoad
集合,它将返回每个具有值的属性(不包括构造的属性)。也就是说,如果您不需要合法地查看每个属性,那么最好使用
PropertiesToLoad

感谢Gabriel的回复。但是,在Powershell调用的返回值中,我看到“PrimaryGroup”和“primaryGroupID”,两者的值不同。如果我注释掉“mySearcher.PropertiesToLoad.Add”(“PrimaryGrou”)”,C代码将返回“primaryGroupID”,但不会返回“PrimaryGroup”。是的,这是预期的
PrimaryGroup
实际上不存在于AD中。它是一个PowerShell属性,可根据AD中的
primaryGroupId
属性查找主组。抱歉,我重新阅读了我的答案,并意识到了为什么我会把您弄糊涂:)我更新了答案,以便更清楚发生了什么,以及如何获取主组。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            foreach (var p in GetProperties())
                Console.WriteLine(p);
        }

        private static IEnumerable<string> GetDomainNames()
        {
            ICollection<string> domains = new List<string>();

            foreach (Domain domain in Forest.GetCurrentForest().Domains)
                domains.Add(domain.Name);

            return domains;
        }

        public static List<string> GetProperties()
        {
            List<string> properties = new List<string>();

            foreach (var domainName in GetDomainNames())
            {
                using (DirectoryEntry directoryEntry = new DirectoryEntry(@"LDAP://" + domainName))
                {
                    using (DirectorySearcher mySearcher = new DirectorySearcher(directoryEntry))
                    {
                        mySearcher.Filter = ("(objectClass=computer)");
                        mySearcher.SizeLimit = 0; // no size limit
                        mySearcher.PageSize = 250; // paging
                        mySearcher.PropertiesToLoad.Add("PrimaryGroup"); // only want this property, for testing, comment out this line to get all properties returned

                        foreach (SearchResult resEnt in mySearcher.FindAll())
                        {
                            foreach (var p in resEnt.Properties.PropertyNames)
                                properties.Add(p.ToString());
                        }
                    }
                }
            }

            properties.Sort();

            return properties;
        }
    }
}
private static string GetUserPrimaryGroup(DirectoryEntry de) {
    de.RefreshCache(new[] {"primaryGroupID", "objectSid"});

    //Get the user's SID as a string
    var sid = new SecurityIdentifier((byte[])de.Properties["objectSid"].Value, 0).ToString();

    //Replace the RID portion of the user's SID with the primaryGroupId
    //so we're left with the group's SID
    sid = sid.Remove(sid.LastIndexOf("-", StringComparison.Ordinal) + 1);
    sid = sid + de.Properties["primaryGroupId"].Value;

    //Find the group by its SID
    var group = new DirectoryEntry($"LDAP://<SID={sid}>");
    group.RefreshCache(new [] {"cn"});

    return group.Properties["cn"].Value as string;
}