Необъяснимое исключение InvalidOperationException с GroupPrincipal и SAM PrincipalContext

Я пытаюсь создать Принципал, как это:

PrincipalContext pc = new PrincipalContext(ContextType.Machine);
GroupPrincipal group = new GroupPrincipal(pc);

group.Name = "Some Group Name";
group.Description = "Some Group Name Description";

group.Save();

Тем не менее, когда код выполняется, я получаю следующее сообщение об исключении:

System.DirectoryServices.AccountManagement: Недопустимое свойство для этого типа магазина.

Если я не установлю Description Свойство, приведенный выше код прекрасно работает, просто нет описания для группы.

Я делаю что-то неправильно?

Заранее спасибо.

РЕДАКТИРОВАТЬ: я думаю, что я нашел обходной путь для этого (для тех, кто, возможно, заинтересован). Группу можно создать так же, как указано выше:

PrincipalContext pc = new PrincipalContext(ContextType.Machine);
GroupPrincipal group = new GroupPrincipal(pc);
group.Save();

Теперь вы создаете DirectoryEntry и свяжите это с недавно созданной Группой как это:

string path = "WinNT://" + machineName + "/" + group.SamAccountName;
DirectoryEntry dEntry = new DirectoryEntry(path);

Это позволяет получить доступ к свойствам этой группы, но меня интересует описание, поэтому:

dEntry.Properties["description"].Add("Some Decription");
dEntry.CommitChanges();

И это должно сделать это.

2 ответа

Решение

Ответ переписан

У меня есть ваш ответ, но он вам может не понравиться. Информации в интернете мало, но в коде это объяснимо:

  • Когда вы создаете свой GroupPrincipal, к нему добавляется контекст. Этот контекст внутренне имеет скрытый тип: SAMStoreCtx, который наследуется от абстрактного типа StoreCtx;
  • Каждое свойство в GroupPrincipal, которое вы вызываете, будет вызывать IsValidProperty, внутренний член SamStoreCtx;
  • Однако это не относится к свойству Name;
  • Внутри SAMStoreCtx есть фрагмент кода, который выглядит следующим образом (вывод Reflector):

    internal override bool IsValidProperty(Principal p, string propertyName)
    {
        ObjectMask none = ObjectMask.None;
        if (!ValidPropertyMap.TryGetValue(propertyName, out none))
        {
            return false;
        }
        if ((MaskMap[p.GetType()] & none) <= ObjectMask.None)
        {
            return false;
        }
        return true;
    }
    
  • Посмотрите внимательно на этот код (это заняло у меня мгновение), и вы заметите ошибку. Строка, сравнивающая битовый флаг с none использование оператора and всегда приводит к ObjectMask.None. Второе утверждение if для этого всегда верно.
  • Код вызова (свойство Settor of Description) генерирует исключение, когда этот метод возвращает false.

Я считаю, что это ошибка в библиотеке Microsoft. Это происходит только с SAMStoreCtx. Возможно, это нарочно, но поскольку код присутствует, но всегда возвращает false, я полагаю, что программисты намеревались использовать вместо этого оператор or. Проверка моих результатов с другими свойствами, такими как DisplayName, выдает то же исключение, что и ожидалось.

Вы можете связаться с Microsoft по этому поводу и показать им эту ветку. Я не проверял новые бета-версии.NET 4.0, которые могут отображаться по-другому. Вы можете проверить это сами, загрузив Reflector и загрузив соответствующую сборку.NET.

РЕДАКТИРОВАТЬ: я связался с Microsoft для вас и сообщил об ошибке через connect.microsoft.com здесь. Вы можете следить за вопросом там, если хотите.

Вы можете использовать GetUnderlyingObject, чтобы получить DirectoryEntry для группы вместо ее поиска.

var newGroup = new GroupPrincipal(context, groupName);

// You must save first           
newGroup.Save();

var entry = (DirectoryEntry) newGroup.GetUnderlyingObject();

entry.Properties["description"].Add(description);
entry.CommitChanges(); 
Другие вопросы по тегам