Получение имени пользователя Windows в формате «Имя Фамилия», когда пользователь является частью группы

Я пытаюсь получить имя пользователя Windows, вошедшего в систему в данный момент, в формате «Джон Доу». Я не уверен, есть ли для этого общепринятый термин, но подумайте, имя, которое вы видите, когда открываете меню «Пуск», а не строку, которую вы пишете для входа в систему.

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

string GetName(string userName) => string.Join(' ', Regex.Split(userName, @"[A-Z]"));
string name = GetName(Environment.UserName);

Но понял, что это не совсем хорошее универсальное решение, поскольку имена пользователей, не соответствующие формату ^[A-Z]([^A-Z]*)[A-Z]([^A-Z]*)$, будут форматироваться неправильно или вообще не отформатироваться.

GetName("doejohn") // "doejohn" 
GetName("RonaldMcDonald") // "Ronald Mc Donald" 

Моя следующая остановка была здесь, чтобы посмотреть, смогу ли я найти способ получить значение из системы напрямую, вместо того, чтобы вычислять его самостоятельно, и я продвинулся немного дальше: System.DirectoryServices.AccountManagement.UserPrincipal.Current.DisplayName казалось именно тем, что я хочу в теории, и хотя это может работать, а может и не работать в других сценариях, в моем, похоже, это не работает, потому что я являюсь частью группы.

var name1 = System.Security.Principal.WindowsIdentity.GetCurrent().Name; // "AzureAD\JohnDoe"

var name2 = UserPrincipal.Current.DisplayName; 
// System.Exception: 
//     Unable to cast object of type 'System.DirectoryServices.AccountManagement.GroupPrincipal' 
//     to type 'System.DirectoryServices.AccountManagement.UserPrincipal'.

Моя лучшая идея сейчас, хотя я и застрял, — использовать GroupPrincipal, если UserPrincipal не работает, но я открыт для других решений, если это неправильно или противоречит передовой практике.

Является ли ваш пользователь/компьютер активным участником AD/AAD или это локальный пользователь?

gunr2171 19.07.2024 16:00

Вы пробовали UserPrincipal.FindByIdentity передать SID от WindowsIdentity.GetCurrent().USer?

Charlieface 19.07.2024 16:20
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
68
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Этот ответ очень помог мне в решении.

С точки зрения функции мое решение идентично данному ответу. Мои изменения заключаются в следующем:

  • Инвертирован оператор «if», чтобы уменьшить отступ.
  • Используется GeneratedRegexAttribute для создания регулярных выражений во время компиляции.
  • Добавлена ​​попытка/перехват для возврата "" в случае исключения NullReferenceException при назначении userInfo.

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

Требуются пакеты NuGet System.DirectoryServices и System.DirectoryServices.AccountManagement.

 [DllImport("secur32.dll", CharSet = CharSet.Auto)]
 private static extern int GetUserNameEx(int nameFormat, StringBuilder userName, ref uint userNameSize);

 [DllImport("netapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
 private static extern int NetUserGetInfo([MarshalAs(UnmanagedType.LPWStr)] string serverName,
                                           [MarshalAs(UnmanagedType.LPWStr)] string userName,
                                           int level, out IntPtr bufPtr);

 [DllImport("netapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
 private static extern long NetApiBufferFree(out IntPtr bufPtr);

 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
 public struct USER_INFO_10
 {
     [MarshalAs(UnmanagedType.LPWStr)] public string usri10_name;
     [MarshalAs(UnmanagedType.LPWStr)] public string usri10_comment;
     [MarshalAs(UnmanagedType.LPWStr)] public string usri10_usr_comment;
     [MarshalAs(UnmanagedType.LPWStr)] public string usri10_full_name;
 }

 [GeneratedRegex(@"(\S+), (\S+)", options: RegexOptions.Compiled)]
 private static partial Regex LastnameFirstnameToFirstnameLastnameRegex();

 [GeneratedRegex(@"(.+)\\.+", options: RegexOptions.Compiled)]
 private static partial Regex DomainExtractorRegex();

 [GeneratedRegex(@".+\\(.+)", options: RegexOptions.Compiled)]
 private static partial Regex NameExtractorRegex();

 private static string GetUserFullName()
 {
     var username = new StringBuilder(1024);
     uint userNameSize = (uint)username.Capacity;

     // try to get display name and convert from "Last, First" to "First Last" if necessary
     if (0 != GetUserNameEx(3, username, ref userNameSize))
         return LastnameFirstnameToFirstnameLastnameRegex().Replace(username.ToString(), "$2 $1");

     // get SAM compatible name <server/machine>\\<username>
     if (0 == GetUserNameEx(2, username, ref userNameSize)) return "";
     IntPtr bufPtr;

     try
     {
         string domain = DomainExtractorRegex().Replace(username.ToString(), @"$1");
         DirectoryContext context = new DirectoryContext(DirectoryContextType.Domain, domain);
         DomainController dc = DomainController.FindOne(context);

         if (0 == NetUserGetInfo(dc.IPAddress,
                 NameExtractorRegex().Replace(username.ToString(), "$1"),
                 10, out bufPtr))
         {
             try
             {
                 var userInfo = (USER_INFO_10)Marshal.PtrToStructure(bufPtr, typeof(USER_INFO_10));
                 return LastnameFirstnameToFirstnameLastnameRegex().Replace(userInfo.usri10_full_name, "$2 $1");
             }
             catch (NullReferenceException)
             {
                 return "";
             }
         }
     }
     finally
     {
         NetApiBufferFree(out bufPtr);
     }

     return "";
 }

Good luck with "Martin Luther King, Jr.", "Ludwig van Beethoven", and "大谷 翔平".

Raymond Chen 24.07.2024 16:28

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