Перечислите членов группы пользователей Windows в удаленной системе с помощью С#
-
09-06-2019 - |
Вопрос
В С# мне нужно иметь возможность
- Подключитесь к удаленной системе, указав имя пользователя и пароль при необходимости.
- Перечислите членов локальной группы в этой системе
- Получите результаты обратно на исполняющий компьютер.
Например, я подключаюсь к \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 не позволяет вам подключиться через свой механизм входа в систему, я думаю, что ваш единственный вариант — запустить что-то на удаленном компьютере с открытым портом (либо напрямую, либо через удаленное взаимодействие или веб-службу, как уже упоминалось).