英文:
What is the C# equivalent code for the Powershell sript to remove user from Adminstrators group?
问题
以下是您要翻译的内容:
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine))
{
    UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.Name, args[0]);
    GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, "Administrators");
    if (user != null && group != null)
    {
        try
        {
            if (group.Members.Remove(user))
            {
                Console.WriteLine("User successfully removed from Local Administrators.");
            }
            else
            {
                Console.WriteLine("User is not a Local Administrator1.");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("User is not a Local Administrator.");
            Console.WriteLine(ex.ToString());
        }
    }
    else
    {
        Console.WriteLine("User was not found.");
    }
}
请注意,代码部分不要翻译。
英文:
I have a PowerShell script. It is to remove the user from the Administrators group. It's working fine for local and domain users both.
Remove-LocalGroupMember -Group "Administrators" -Member "Admin02"
I want to implement this in C#. I have tried the below code. But it's not working for the domain account.
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine))
{
    UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.Name, args[0]);
    GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, "Administrators");
    if (user != null && group != null)
    {
        try
        {
            if (group.Members.Remove(user))
            {
                Console.WriteLine("User successfully removed from Local Administrators.");
            }
            else
            {
                Console.WriteLine("User is not a Local Administrator1.");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("User is not a Local Administrator.");
            Console.WriteLine(ex.ToString());
        }
    }
    else
    {
        Console.WriteLine("User was not found.");
    }
}
Its printing User was not found.
I have tried with ContextType.Domain as well.
Edit: Thank you @Gabriel Luci. for providing the solution. I tried his solution, but there is a challenge with it.
I have a domain user name T1/spreda (forward slash).
But when I run your code and see the value of member, it shows users like this (with back slash). I have written this code to check the user.
var group = new DirectoryEntry("WinNT://./Administrators");
                
foreach (var m in (IEnumerable)group.Invoke("Members"))
{
    var member = new DirectoryEntry(m);
    var str = JsonConvert.SerializeObject(member);
    Console.WriteLine(str);
    //if (str.Contains(args[0]))
    //{
    //    Console.WriteLine("Found");
    //    var returnVal = group.Invoke("Remove", new[] { member.Path });
    //    Console.WriteLine(returnVal.ToString());
    //    break;
So Is there a way to handle this?
答案1
得分: 1
使用AccountManagement命名空间来处理(GroupPrincipal/UserPrincipal)的问题在于创建对象时会加载所有属性。这意味着需要连接到AD以创建AD用户的UserPrincipal对象,但我们不需要这样做来从组中移除用户。
您可以使用DirectoryEntry来执行此操作,而GroupPrincipal和UserPrincipal在幕后也使用它。代码如下:
var group = new DirectoryEntry("WinNT://./Administrators");
foreach (var m in (IEnumerable)group.Invoke("Members"))
{
    var member = new DirectoryEntry(m);
    if (member.Name == args[0]) {
        group.Invoke("Remove", new [] {member.Path});
        break;
    }
}
这使用了WinNT提供程序(而不是LDAP)来加载本地组。.表示本地计算机。如果要从远程计算机加载管理员组,可以将计算机名称放入路径中,如WinNT://computer1/Administrators。
DirectoryEntry是本机Windows C++ COM ADSI对象的包装器。在这种情况下,因为我们正在加载一个组,它是一个IADsGroup对象。我们使用DirectoryEntry.Invoke()来调用底层对象的方法。因此,group.Invoke("Members")调用IADsGroup::Members,它返回成员列表。同样,group.Invoke("Remove", new [] {member.Path})调用IADsGroup::Remove来移除成员。
我总是更喜欢使用DirectoryEntry,即使纯粹处理AD对象时也是如此。它让您更好地控制性能。我在我写的一篇文章中讨论了这一点:Active Directory: Better performance。
英文:
The problem with using the AccountManagement namespace for this (GroupPrincipal/UserPrincipal) is that the act of creating the object loads all the properties. That means that it needs to connect to AD to create a UserPrincipal object of an AD user, but we don't need to to do that to remove a user from a group.
You can do this with DirectoryEntry, which GroupPrincipal and UserPrincipal use behind the scenes anyway. It would look like this:
var group = new DirectoryEntry("WinNT://./Administrators");
foreach (var m in (IEnumerable)group.Invoke("Members"))
{
    var member = new DirectoryEntry(m);
    if (member.Name == args[0]) {
        group.Invoke("Remove", new [] {member.Path});
        break;
    }
}
This uses the WinNT provider (as opposed to LDAP) to load the local group. The . means the local computer. If you wanted to load the Administrators group from a remote computer, you can put the computer name in the path, like WinNT://computer1/Administrators.
DirectoryEntry is a wrapper around the native Windows C++ COM ADSI objects. In this case, because we're loading a group, it's an IADsGroup object. We use DirectoryEntry.Invoke() to call a method from the underlying object. So group.Invoke("Members") calls IADsGroup::Members, which returns a list of the members. Likewise, group.Invoke("Remove", new [] {member.Path}) calls IADsGroup::Remove to remove the member.
I always prefer using DirectoryEntry, even when working purely with AD objects. It gives you far more control over performance. I talked about that in an article I wrote: Active Directory: Better performance
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。




评论