Манипулировать Windows группой «Пользователи» без доступа к домену? - PullRequest
0 голосов
/ 10 июля 2020

У меня есть приложение C # / WPF, которое используется для управления локальными пользователями и группами в системе. Нас интересуют только локальные пользователи и группы, независимо от того, присоединена ли машина к домену или нет. Когда мы создаем пользователя в нашем приложении, я хочу добавить его в группу «Пользователи». Обычно это работает нормально, но если машина присоединена к домену и НЕ подключена к сети (например, ноутбук вне офиса), я получаю ошибки «сетевой путь не найден» при попытке добавить локального пользователя в « Группа «Пользователи».

Я думаю, причина в том, что группа «Пользователи» содержит пользователей домена, как показано на этом снимке экрана.

введите описание изображения здесь

И это, по сути, мой код:

        public static void AddUserToGroup(UserPrincipal oUserPrincipal, string groupName)
        {
            using (PrincipalContext pc = new PrincipalContext(ContextType.Machine))
            {
                GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, groupName);
                if (group == null)
                {
                    group = CreateLocalWindowsGroup(groupName);
                }
                if (!group.Members.Contains(oUserPrincipal)) // this line throws "network path not found" exception if the machine is domain joined, but can't contact the domain controller
                    group.Members.Add(oUserPrincipal);
                group.Save();
            }
        }

Я не могу понять, как подойти к этому с помощью API, но похоже, что это должно быть возможно, потому что я могу добавить одного и того же пользователя в одну и ту же группу вручную с помощью инструмента «Локальные пользователи и группы» без проблем, независимо от подключения к сети. Как я могу обойти эту проблему?

1 Ответ

1 голос
/ 10 июля 2020

Это одна из причин, по которой мне не нравится использовать пространство имен AccountManagement.

Свойство GroupPrincipal.Members возвращает PrincipalCollection, т.е. просто набор из Principal объектов. Фактический тип будет UserPrincipal или GroupPrincipal в зависимости от того, что является фактическим членом.

Но эти Principal классы, когда они созданы, загружают все детали для этого объекта. Таким образом, просто создание UserPrincipal для пользователя домена запускает его для go выхода в домен и получения всех деталей для пользователя.

Лучше использовать DirectoryEntry напрямую, что в любом случае использует пространство имен AccountManagement в фоновом режиме. Это дает вам больше контроля над тем, что на самом деле происходит.

var usersGroup = new DirectoryEntry($"WinNT://{Environment.MachineName}/{groupName}");

usersGroup.Invoke("Add", new object[] { $"WinNT://{Environment.MachineName}/{userName}" });

Это предполагает переменную userName с именем локального пользователя. Если пользователь уже находится в группе, он вызовет исключение, поэтому вы можете захотеть это поймать. всех существующих членов, если вы не собираетесь использовать какие-либо из этих данных.

Обновление: Чтобы прочитать всех членов локальной группы, используйте .Invoke("Members"). Затем вы должны создать новый DirectoryEntry для каждого члена коллекции. Например:

foreach (var member in (IEnumerable) usersGroup.Invoke("Members")) {
    using (var memberDe = new DirectoryEntry(member)) {
        Console.WriteLine(memberDe.Name);
    }
}

Класс DirectoryEntry на самом деле является оболочкой для Windows собственных интерфейсов ADSI . Для группы базовый объект действительно будет IADsGroup. Когда вы вызываете .Invoke для объекта DirectoryEntry, это позволяет вам вызывать методы IADsGroup (вы увидите метод Members, указанный в документации). Все специфичные для объекта классы c, такие как IADsGroup и IADsUser, все наследуются от IADs, поэтому методы из него тоже можно использовать.

Это относится только к местным группам. С группами Active Directory вам не нужно прибегать к использованию методов IADs.

...