Перечислите членов группы пользователей Windows в удаленной системе с помощью С#

StackOverflow https://stackoverflow.com/questions/21514

Вопрос

В С# мне нужно иметь возможность

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

Например, я подключаюсь к \SOMESYSTEM с соответствующими учетными данными и получаю обратно список локальных администраторов, включая SOMESYSTEM\Administrator, SOMESYSTEM\Bob, DOMAIN\AlanH, «DOMAIN\Domain Администраторы».

Я пробовал это с помощью system.directoryservices.accountmanagement, но столкнулся с проблемами с аутентификацией.Иногда я получаю:

Множественные подключения к серверу или общему ресурсу одного и того же пользователя с использованием более одного имени пользователя не допускаются.Отключите все предыдущие подключения к серверу или общему ресурсу и повторите попытку.(Исключение из HRESULT:0x800704C3)

Вышеупомянутое является попыткой, потому что будут ситуации, когда я просто не смогу отключить существующие диски или соединения UNC.

В других случаях моя программа получает НЕИЗВЕСТНУЮ ОШИБКУ, а журнал безопасности удаленной системы сообщает об ошибке 675, код 0x19, который имеет значение KDC_ERR_PREAUTH_REQUIRED.

Мне нужен более простой и менее подверженный ошибкам способ сделать это!

Это было полезно?

Решение

Это должно быть легко сделать с помощью WMI.Здесь у вас есть указатель на некоторые документы:

Документация WMI для Win32_UserAccount

Даже если у вас нет опыта работы с WMI, вам будет довольно легко превратить код VB Script внизу страницы в некоторый код .NET.

Надеюсь, это помогло!

Другие советы

Дэвид был на правильном пути, и я благодарю его за ответ.

Но необходимый запрос WMI был немного сложнее, чем простой, поскольку мне нужен был не просто список пользователей для всей машины, а подмножество пользователей. и группы, локальные или доменные, которые были членами локальной группы администраторов.Для справки, этот запрос WMI был:

SELECT PartComponent FROM Win32_GroupUser WHERE GroupComponent = "Win32_Group.Domain='thehostname',Name='thegroupname'"

Вот полный фрагмент кода:

public string GroupMembers(string targethost, string groupname, string targetusername, string targetpassword)
        {
            StringBuilder result = new StringBuilder(); 
            try
            {
                ConnectionOptions Conn = new ConnectionOptions();
                if (targethost != Environment.MachineName) //WMI errors if creds given for localhost
                {
                    Conn.Username = targetusername; //can be null
                    Conn.Password = targetpassword; //can be null
                }
                Conn.Timeout = TimeSpan.FromSeconds(2);
                ManagementScope scope = new ManagementScope("\\\\" + targethost + "\\root\\cimv2", Conn);
                scope.Connect();
                StringBuilder qs = new StringBuilder();
                qs.Append("SELECT PartComponent FROM Win32_GroupUser WHERE GroupComponent = \"Win32_Group.Domain='");
                qs.Append(targethost);
                qs.Append("',Name='");
                qs.Append(groupname);
                qs.AppendLine("'\"");
                ObjectQuery query = new ObjectQuery(qs.ToString());
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
                ManagementObjectCollection queryCollection = searcher.Get();
                foreach (ManagementObject m in queryCollection)
                {
                    ManagementPath path = new ManagementPath(m["PartComponent"].ToString());                                        
                    { 
                        String[] names = path.RelativePath.Split(',');
                        result.Append(names[0].Substring(names[0].IndexOf("=") + 1).Replace("\"", " ").Trim() + "\\"); 
                        result.AppendLine(names[1].Substring(names[1].IndexOf("=") + 1).Replace("\"", " ").Trim());                    
                    }
                }
                return result.ToString();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error. Message: " + e.Message);
                return "fail";
            }
        }

Итак, если я вызываю Groupmembers("Server1", "Administrators", "myusername", "mypassword");Я получаю одну строку, возвращаемую с:

СЕРВЕР1\Администратор
МОЙДОМЕН\Администраторы домена

Фактический возврат WMI выглядит примерно так:

\\SERVER1 oot\cimv2:Win32_UserAccount.Domain="SERVER1",Name="Администратор"

...как видите, мне пришлось немного поработать со строками, чтобы привести это в порядок.

Я бы рекомендовал использовать функцию Win32 API. NetLocalGroupGetMembers.Это гораздо проще, чем пытаться разобраться в безумном синтаксисе LDAP, который необходим для некоторых других решений, рекомендуемых здесь.Пока вы выдаете себя за пользователя, под которым хотите запустить проверку, вызывая «LoginUser», у вас не должно возникнуть никаких проблем с безопасностью.

Вы можете найти пример кода для олицетворения. здесь.

Если вам нужна помощь в выяснении того, как вызвать «NetLocalGroupGetMembers» из C#, я рекомендую вам воспользоваться помощником PInvoke Джареда Парсона, который вы можете скачать из кодплекса.

Если вы запускаете код в приложении ASP.NET, работающем в IIS, и хотите выдать себя за пользователя, обращающегося к веб-сайту, чтобы выполнить вызов, вам может потребоваться предоставить разрешение «Доверено для делегирования» рабочему веб-серверу.

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

Вполне возможно, что ваш сетевой администратор запретил доступ к «Защищаемому объекту» для конкретного компьютера, к которому вы пытаетесь получить доступ.К сожалению, этот доступ необходим для всех API управления сетью функции для работы.В этом случае вам необходимо будет предоставить доступ к «Защищаемому объекту» всем пользователям, от имени которых вы хотите работать.Однако при настройках безопасности Windows по умолчанию все прошедшие проверку подлинности пользователи должны иметь доступ.

Надеюсь, это поможет.

-Скотт

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

Если Windows не позволяет вам подключиться через свой механизм входа в систему, я думаю, что ваш единственный вариант — запустить что-то на удаленном компьютере с открытым портом (либо напрямую, либо через удаленное взаимодействие или веб-службу, как уже упоминалось).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top