3

ローカルの WinNT グループのメンバーを取得すると、なぜかすべてのメンバーが返されません。私は追加します:

  • Active Directory ユーザー
  • Active Directory グループ

どちらも成功しましたが (写真を参照)、後で表示されるのはユーザーのみです。

ここに画像の説明を入力

質問は:

  • 追加されたグループはどうなりますか?
  • コード サンプル 'GetMembers()' の最後のメソッドを参照してください。
  • これは既知の問題ですか?
  • 利用可能な回避策はありますか?

どうもありがとう!!

string _domainName = @"MYDOMAIN";
string _basePath = @"WinNT://MYDOMAIN/myserver";
string _userName = @"MYDOMAIN\SvcAccount";
string _password = @"********";

void Main()
{
   CreateGroup("lg_TestGroup");
   AddMember("lg_TestGroup", @"m.y.username");
   AddMember("lg_TestGroup", @"Test_DomainGroup");

   GetMembers("lg_TestGroup");
}

// Method added for reference.
void CreateGroup(string accountName)
{
   using (DirectoryEntry rootEntry = new DirectoryEntry(_basePath, _userName, _password))
   {
      DirectoryEntry newEntry = rootEntry.Children.Add(accountName, "group");
        newEntry.CommitChanges();
   }
}

// Add Active Directory member to the local group.
void AddMember(string groupAccountName, string userName)
{
    string path = string.Format(@"{0}/{1}", _basePath, groupAccountName);
    using (DirectoryEntry entry = new DirectoryEntry(path, _userName, _password))
    {
        userName = string.Format("WinNT://{0}/{1}", _domainName, userName);
      entry.Invoke("Add", new object[] { userName });
        entry.CommitChanges();
    }
}

// Get all members of the local group.
void GetMembers(string groupAccountName)
{
    string path = string.Format(@"{0}/{1}", _basePath, groupAccountName);
   using (DirectoryEntry entry = new DirectoryEntry(path, _userName, _password))
   {
      foreach (object member in (IEnumerable) entry.Invoke("Members"))
      {
         using (DirectoryEntry memberEntry = new DirectoryEntry(member))
         {
            string accountName = memberEntry.Path.Replace(string.Format("WinNT://{0}/", _domainName), string.Format(@"{0}\", _domainName));
            Console.WriteLine("- " + accountName); // No groups displayed...
         }
      }
   }
}

更新 #1 グループ メンバーの順序が重要なようです。GetMembers()の列挙子が Active Directory グループに遭遇するとすぐに、残りの項目も表示されません。したがって、この例で「Test_DomainGroup」が最初にリストされている場合、GetMembers()は何も表示しません。

4

1 に答える 1

3

私はそれが古い質問であることを知っており、必要な答えを見つけた可能性がありますが、他の誰かがこれに出くわした場合に備えて...

DirectoryEntry で使用している WinNT ADSI プロバイダー [ie. WinNT://MYDOMAIN/myserver] は、古い Windows 2000/NT 機能レベル ( https://support.microsoft.com/en-us/kb/322692 ) にとらわれていない Windows ドメインを操作する機能がかなり制限されています。

この場合の問題は、WinNT プロバイダーがグローバルまたはユニバーサル セキュリティ グループ (Windows NT には存在せず、ドメイン レベルを Windows 2000 混合モードより上に上げるとすぐにアクティブになる) の処理方法を認識していないことです。したがって、これらのタイプのグループがローカル グループの下にネストされている場合、通常、説明したような問題が発生します。

私が見つけた唯一の解決策/回避策は、列挙しているグループがドメインからのものかどうかを判断し、そうであれば、「メンバー」を呼び出すときにすべてのメンバーを適切に表示する LDAP プロバイダーに切り替えることです。

残念ながら、既に WinNT プロバイダーにバインドされている DirectoryEntry を使用して、WinNT プロバイダーの使用から LDAP プロバイダーの使用に切り替える「簡単な」方法を私は知りません。そのため、私が取り組んできたプロジェクトでは、通常、現在の WinNT オブジェクトの SID を取得してから、LDAP を使用して同じ SID を持つドメイン オブジェクトを検索することを好みます。

Windows 2003 以降のドメインでは、SID バイト配列を通常の SDDL 形式 (S-1-5-21...) に変換し、次のような方法で一致する SID を持つオブジェクトにバインドできます。

Byte[] SIDBytes = (Byte[])memberEntry.Properties["objectSID"].Value;
System.Security.Principal.SecurityIdentifier SID = new System.Security.Principal.SecurityIdentifier(SIDBytes, 0);

memberEntry.Dispose();
memberEntry = new DirectoryEntry("LDAP://" + _domainName + "/<SID=" + SID.ToString() + ">");

Windows 2000 ドメインの場合、SID によってオブジェクトに直接バインドすることはできません。そのため、SID バイト配列を "\" プレフィックス (\01\06\05\16\EF\A2 ..) を持つ 16 進値の配列に変換してから、DirectorySearcher を使用して、一致する SID。これを行う方法は次のようになります。

public DirectoryEntry FindMatchingSID(Byte[] SIDBytes, String Win2KDNSDomainName)
{
    using (DirectorySearcher Searcher = new DirectorySearcher("LDAP://" + Win2KDNSDomainName))
    {
        System.Text.StringBuilder SIDByteString = new System.Text.StringBuilder(SIDBytes.Length * 3);

        for (Int32 sidByteIndex = 0; sidByteIndex < SIDBytes.Length; sidByteIndex++)
            SIDByteString.AppendFormat("\\{0:x2}", SIDBytes[sidByteIndex]);

        Searcher.Filter = "(objectSid=" + SIDByteString.ToString() + ")";
        SearchResult result = Searcher.FindOne();

        if (result == null)
            throw new Exception("Unable to find an object using \"" + Searcher.Filter + "\".");
        else
            return result.GetDirectoryEntry();
    }
}
于 2015-05-15T19:23:31.900 に答える