3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。(jehupc.exblog.jpから移転中)

(.Net,ADSI)Active Directroyの情報を参照。

Windows標準のActiveDirectoryオブジェクト管理ツールはちょいと使いにくいので .Net でツールを作ることにしました。

.Net 標準のクラスライブラリで Active Directory の操作はできるようです。

DirectoryEntryクラスを使うと Active Directory に接続して任意のオブジェクトを取得できるようです。

とりあえずユーザ情報を取得するサンプルです。(C#)(文字数制限にひっかかったんでハイライト無しで..)

※System.DirectoryServices.dllの参照を追加する必要があります。

using System.DirectoryServices;

///

/// ActiveDirectoryから情報を取得し、Userオブジェクトリストを作成

///

///

public List GetUserAllList()

{

//既定接続の接続するLDAP名 (ドメイン名が hogehoge.jp の場合)

private const string cPath = @"LDAP://domaincontroller/DC=hogehoge,DC=jp";

//既定接続のユーザ名

private const string cUser = @"cn=administrator,DC=hogehoge,DC=jp";

//パスワード

private const string cPasswd = @"password";

//ActiveDirectoryに接続

DirectoryEntry mDrctEntry = new DirectoryEntry(cPath, cUser, cPasswd);

//ログインできた確認

try{

Object obj = mDrctEntry.NativeObject;

} catch (Exception ex){

//ログイン失敗

Utility.DispMessageBox(Utility.StrType.LoginErr);

Console.WriteLine(ex.Message);

return;

}

// LDAP検索オブジェクトを作成

DirectorySearcher drSearch = new DirectorySearcher(mDrctEntry);

// アカウントフィルターを設定 Userオブジェクトだけ取得するように

drSearch.Filter = "(ObjectCategory=user)";

//↓アカウントが hoge のユーザを取得する場合はこのように

//drSearch.Filter = "(SAMAccountName=hoge)";

//↓複数条件の場合(serオブジェクトかつhogeという名前のオブジェクト)

//string loginName = "hoge";

//drSearch.Filter = "(&(ObjectCategory=user)(SAMAccountName=hoge))";

//既定では PropertiesToLoad を指定しないとすべての属性を取得する

//個別に取得する属性を取るには下記のように指定。

// Common Name(cn)プロパティを取得する

//drSearch.PropertiesToLoad.Add("cn");

//sAMAccountName

//drSearch.PropertiesToLoad.Add("sAMAccountName");

//説明

//drSearch.PropertiesToLoad.Add("description");

//所属グループ

//drSearch.PropertiesToLoad.Add("memberOf");

// 指定した条件で検索する

SearchResultCollection scn = drSearch.FindAll();

if (scn == null) return null;

List lstUser = new List();

//Userオブジェクト新規生成

foreach (SearchResult sResult in scn) {

//Userオブジェクト生成

lstUser.Add(SetUserBySearchResult(sResult));

}

return lstUser;

}

//検索結果 SearchResultからオブジェクトの属性取得

private User SetUserBySearchResult(SearchResult sResult)

{

User usr = new User();

if (sResult.Properties["objectGUID"].Count > 0) {

byte[] byt = (byte[])sResult.Properties["objectGUID"][0];

usr.dmObjectGUID = new Guid(byt);

}

if (sResult.Properties["sAMAccountName"].Count > 0) {

usr.dmSamAccountName = (string)sResult.Properties["sAMAccountName"][0];

}

if (sResult.Properties["userPrincipalName"].Count > 0) {

usr.dmUserPrincipalName = (string)sResult.Properties["userPrincipalName"][0];

}

if (sResult.Properties["WhenCreated"].Count > 0) {

//UTCなのでローカル時間に変換。

DateTime dtm = (DateTime)sResult.Properties["WhenCreated"][0];

usr.dmWhenCreated = dtm.ToLocalTime();

}

if (sResult.Properties["WhenChanged"].Count > 0) {

//UTCなのでローカル時間に変換。

DateTime dtm = (DateTime)sResult.Properties["WhenChanged"][0];

usr.dmWhenChanged = dtm.ToLocalTime();

}

if (sResult.Properties["displayName"].Count > 0) {

usr.dmDisplayName = (string)sResult.Properties["displayName"][0];

}

if (sResult.Properties["lastLogon"].Count > 0) {

//1601/01/01からミリ秒をDateTimeに変換

Int64 lastLogonTimestamp = (Int64)sResult.Properties["lastLogon"][0];

DateTime baseDateTime = new DateTime(1601, 01, 01);

usr.dmLastLogon = TimeZoneInfo.ConvertTimeFromUtc(baseDateTime.AddTicks(lastLogonTimestamp), TimeZoneInfo.Local);

}

if (sResult.Properties["distinguishedName"].Count > 0) {

usr.dmDistinguishedName = (string)sResult.Properties["distinguishedName"][0];

}

if (sResult.Properties["memberOf"].Count > 0) {

foreach (object item in sResult.Properties["memberOf"])

{

if (usr.dmMemberOf == null) {

usr.dmMemberOf = new List();

}

usr.dmMemberOf.Add((string)item);

}

}

if (sResult.Properties["sn"].Count > 0) {

usr.dmSn = (string)sResult.Properties["sn"][0];

}

if (sResult.Properties["givenName"].Count > 0) {

usr.dmGivenName = (string)sResult.Properties["givenName"][0];

}

if (sResult.Properties["cn"].Count > 0) {

usr.dmCn = (string)sResult.Properties["cn"][0];

}

if (sResult.Properties["description"].Count > 0) {

usr.dmDescription = (string)sResult.Properties["description"][0];

}

return usr;

}

ActiveDirectoryから取得したユーザアカウント情報は User クラスに値を持たす用にしてます。

Userクラスのコードはこちらを参照。

今回は ActiveDirectory への接続文字列として、LDAPを用いてます。

LDAP://ドメインコントローラ名/DC=ドメイン名(セカンド),DC=ドメイン(トップレベル)

注意点としてLDAP識別名の先頭の"LDAP"は大文字にしとかないといけないようですね。

LDAP識別名のホスト名以降のルールは、マイコミジャーナル:LDAP識別名の記述ルールが参考になります。

指定した条件の ActiveDirectory を見つけるために、DirectorySearcher クラスというLDAP検索フィルタを使ってます。

この DirectorySearcher.Filter プロパティにフィルタを定義するんですが、これは書き方がLDAP書式になるようで複数条件の時がちょっと慣れないんですよね。

そのあたりの書式や使用例はMS:Windows PowerShell から Active Directory を検索する方法はありますか (2009/03) | Hey, Scripting Guy!が非常に参考なります。

後、気になったのが一部取得できない属性があったりするんですよね。

createTimeStamp とか modifyTimeStamp がその一例です。これらはドメインコントローラ間で複製されるようなんですが、(WhenCreated,WhenChanged等は複製されない)なぜか取得できませんでした。他にもいくつかこのような属性がありましたね。。。

参考:

寝ても覚めても.NET(?): ADのユーザ名から所属するグループの一覧を取得する

My Private Adversaria: Windowsのユーザ一覧を取得するには(.Net)