「ほっ」と。キャンペーン
<   2010年 03月 ( 10 )   > この月の画像一覧
(.Net,ADSI)Active Directory LastLogonTimestampを現在の時刻に変換

ActiveDirectoryからADSIを使って LastLogon , LastLogonTimestamp を取るときの注意点ですが、これらの値は 1601/01/01 00:00:00からのミリ秒を64ビットの値として持っているようです。
(WindowsAPIのFILETIME 構造体がこのような仕様みたいです。ちなみにUnix時間は1970/01/01 00:00:00から32bitでカウントしてましたね。)

その FLETIME 構造体形式の値を .Net の DateTime に変換するのは下記のように書けばいいようです。(C#)


//.Net 3.5以降
//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);


参考:
Active Directory lastLogonTimestampを現在の時刻に変換
[PR]
by jehoshaphat | 2010-03-21 09:34 | .Net開発 | Trackback | Comments(0)
(.Net)SIDを文字列に変換
ActiveDirectoryから取得したオブジェクトの SID はバイト型配列になっています。
これを文字列(S-1-5-21-xxx-xxx...)に変換する方法です。

WindowsAPIにMSDN:ConvertSidToStringSidという関数があるようなので、これを使うと簡単に文字列形式にできるようですね。

サンプルはこんな感じです。(C#)
/// <summary>
/// ActiveDirectoryから取得したbyte配列をSID文字列形式に変換
/// </summary>
/// <param name="psid">変換する SID へのポインタを指定します</param>
/// <param name="stringSid">NULL で終わる SID 文字列へのポインタを受け取る変数へのポインタを指定します。返されたバッファを解放するには、LocalFree 関数を使います。</param>
/// <returns>関数が成功すると、0 以外の値が返ります。関数が失敗すると、0 が返ります。拡張エラー情報を取得するには、GetLastError 関数を使います。</returns>
[DllImport("advapi32.dll")]
private static extern int ConvertSidToStringSid(byte[] psid, ref IntPtr stringSid);
 
public static string SidToString(SearchResult res)
{
ResultPropertyValueCollection pvc = res.Properties["objectSid"];
byte[] sids = (byte[])pvc[0];
//ポインタ定義
IntPtr pStringSid = IntPtr.Zero;
//APIを使って変換 第二引数ポインタに結果が入ってる
int ret = ConvertSidToStringSid(sids, ref pStringSid);
//結果となる文字列変数定義
string strSid = string.Empty;
if (ret != 0)
{
//ポインタの先にある文字列をマネージStringに変換。
strSid = Marshal.PtrToStringAnsi(pStringSid);
//メモリ解放
Marshal.FreeCoTaskMem(pStringSid);
}
return strSid;
}


参考:
@IT:C#からActive Directoryのユーザ、グループのSIDを取得したい
[PR]
by jehoshaphat | 2010-03-21 09:32 | .Net開発 | Trackback | Comments(0)
(.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)
[PR]
by jehoshaphat | 2010-03-20 06:22 | .Net開発 | Trackback | Comments(0)
(.Net,ADSI)Active Directroyの情報を参照サンプルソースのユーザクラス
(.Net)Active Directroyの情報を参照でのサンプルソースの補足です。
ユーザーアカウント情報を持つ User クラスです。(C#)
public class User{
/// <summary>
/// objectGUID キー値
/// </summary>
public Guid dmObjectGUID{get;set;}
/// <summary>
/// objectSID
/// </summary>
public string dmObjectSID { get; set; }
/// <summary>
/// sAMAccountName ログインアカウント名
/// </summary>
public string dmSamAccountName { get; set; }
/// <summary>
/// userPrincipalName ログインアカウント名(AD環境 xx@aa.jp)
/// </summary>
public string dmUserPrincipalName { get; set; }
/// <summary>
/// createTimeStamp アカウント作成日時(なぜか空)
/// </summary>
public DateTime dmCreateTimeStamp { get; set; }
/// <summary>
/// modifyTimeStamp アカウント変更日時(なぜか空)
/// </summary>
public DateTime dmModifyTimeStamp { get; set; }
/// <summary>
/// WhenCreated アカウント作成日時
/// </summary>
public DateTime dmWhenCreated{ get; set; }
/// <summary>
/// WhenChanged アカウント変更日時
/// </summary>
public DateTime dmWhenChanged { get; set; }
/// <summary>
/// displayName 表示名
/// </summary>
public string dmDisplayName { get; set; }
/// <summary>
/// logonCount ログイン回数(ドメイン間複製無し)
/// </summary>
public long dmLogonCount { get; set; }
/// <summary>
/// lastLogon 最終ログイン日時(ドメイン間複製無)
/// </summary>
public DateTime dmLastLogon { get; set; }
/// <summary>
/// lastLoginTimeStamp 最終ログイン日時(14日毎ドメイン間複製あり)
/// </summary>
public DateTime dmLastLogonTimeStamp { get; set; }
/// <summary>
/// userAccountControl ユーザのアカウントに関する情報(無効情報もここにあり)
/// </summary>
public int dmUserAccountControl { get; set; }
/// <summary>
/// distinguishedName 識別名。DN表記
/// </summary>
public string dmDistinguishedName { get; set; }
 
private List<string> mDmMemberOf = new List<string>();
/// <summary>
/// memberOf ユーザが属しているグループ。DN表記
/// </summary>
public List<string> dmMemberOf { get { return mDmMemberOf; } set { mDmMemberOf=value; } }
/// <summary>
/// sn 姓
/// </summary>
public string dmSn { get; set; }
/// <summary>
/// givenName 名
/// </summary>
public string dmGivenName { get; set; }
/// <summary>
/// cn CN名
/// </summary>
public string dmCn { get; set; }
/// <summary>
/// description 説明
/// </summary>
public string dmDescription { get; set; }
/// <summary>
/// accountExpirationDate アカウント有効期限
/// </summary>
public DateTime dmAccountExpirationDate { get; set; }
/// <summary>
/// objectcategory オブジェクトのカテゴリ
/// </summary>
public string dmObjectCategory { get; set; }
/// <summary>
/// adspath オブジェクトへのパス
/// </summary>
public string dmAdsPath { get; set; }
/// <summary>
/// アカウント無効か
/// </summary>
public bool Disable { get; set; }
/// <summary>
/// ログオンスクリプト実行
/// </summary>
public bool Script{ get; set; }
/// <summary>
/// ホームフォルダが必要
/// </summary>
public bool HomeDirReauired { get; set; }
/// <summary>
/// ロックアウトしてる
/// </summary>
public bool LockOut { get; set; }
/// <summary>
/// パスワードが必要ない
/// </summary>
public bool PasswdNotReqd { get; set; }
/// <summary>
/// パスワードが変更できない
/// </summary>
public bool PasswdCantChange { get; set; }
/// <summary>
/// 暗号化されたパスワードを送信できる
/// </summary>
public bool EncPasswdAllowed { get; set; }
/// <summary>
/// 別のドメインにプライマリ アカウントを持つユーザーが使用するアカウントです。このアカウントが存在することにより、ユーザーはこのドメインにアクセスできますが、このドメインを 信頼するドメインへのアクセスはできません。これはローカル ユーザー アカウントとして参照される場合があります。
/// </summary>
public bool TempDuplicateAccount { get; set; }
/// <summary>
/// 通常のユーザー
/// </summary>
public bool NormalAccount { get; set; }
/// <summary>
/// 別のドメインを信頼しているシステム ドメインのアカウントを信頼することを許可します。
/// </summary>
public bool InterdomainTrustAccount { get; set; }
/// <summary>
/// Microsoft Windows NT 4.0 Workstation、Microsoft Windows NT 4.0 Server、Microsoft Windows 2000 Professional、または Windows 2000 Server を実行している動作するコンピュータのコンピュータ アカウントであり、このドメインのメンバです。
/// </summary>
public bool WorkstTrustAccount { get; set; }
/// <summary>
/// このドメインのメンバであるドメイン コントローラのコンピュータ アカウントです。
/// </summary>
public bool ServerTrustAccount { get; set; }
/// <summary>
/// パスワード無期限
/// </summary>
public bool DontExpirePasswd { get; set; }
/// <summary>
/// MNSログインアカウント
/// </summary>
public bool MnsLogon { get; set; }
/// <summary>
/// スマートカードログイン
/// </summary>
public bool SmartCardRequired { get; set; }
/// <summary>
/// このフラグを設定すると、サービスを実行するサービス アカウント (ユーザー アカウントまたはコンピュータ アカウント) が Kerberos の委任に対して信頼されます。このようなサービスでは、サービスを要求するクライアントを偽装することができます。サービスで Kerberos の委任を有効にするには、このフラグをサービス アカウントの userAccountControl プロパティに設定する必要があります。
/// </summary>
public bool TrustedForDelegation { get; set; }
/// <summary>
/// このフラグを設定すると、サービス アカウントが Kerberos の委任に対して信頼されると設定されていても、ユーザーのセキュリティ コンテキストはサービスに委任されません。
/// </summary>
public bool NotDelegated { get; set; }
/// <summary>
/// このプリンシパルを、DES (Data Encryption Standard) 暗号化のみをキーに使用できるように制限します
/// </summary>
public bool UseDesKeyOnly { get; set; }
/// <summary>
/// このアカウントは、ログオン時に Kerberos 事前認証を必要としません。
/// </summary>
public bool DontReqPreauth { get; set; }
/// <summary>
/// ユーザーのパスワードの有効期限が切れています。
/// </summary>
public bool PasswdExpired { get; set; }
/// <summary>
/// このアカウントは委任に対して有効です。これはセキュリティに代わる設定です。このオプションが設定されたアカウントは厳密に管理する必要があります。こ の設定を行うと、アカウントで実行されているサービスはクライアントとして識別され、ネットワーク上の他のリモート サーバーへそのユーザーとして認証されます
/// </summary>
public bool TrustedToAuthForDelegation { get; set; }
/// <summary>
/// PrimaryグループSID(プライマリグループはMemberOfで取れないため)
/// </summary>
public string PrimaryGroupSID { get; set; }
}

[PR]
by jehoshaphat | 2010-03-20 06:05 | .Net開発 | Trackback | Comments(0)
(ADSI)ActiveDirectoryのオブジェクトの属性をのぞきたい
ActiveDirectory上のユーザーアカウントやグループオブジェクト等のオブジェクトには非常に多くの属性があります。
それらオブジェクトの生を情報をのぞく方法というかツールがあるようです。

それはMicrosoftが提供している ADSI Edit というツールです。
英語のツールですが、特に難しい使い方はありません。
オブジェクトを選んでコンテキストメニューからプロパティで設定されている属性が覗けます。
(スクリーンショット撮るの忘れたんですが、画像検索でググればハードコピーいっぱい出てきます。)

このツールは元からは入ってないようですが、MSダウンロード:XP SP2サポートツールの中に含まれているようなので、インストールしてみました。

インストーラの「Select An Installation Type」で「Complete」を選ばないと入らないようです。
デフォルトだと、%Program Files%¥Support Tools にインストールされます。

ADSI Edit本体へのパスはデフォルトだと下記になります。
%Program Files%¥Support Tools¥adsiedit.msc
ショーカット等も作成されないので、作成しとくと便利かもしれません。
また、動かす時はドメイン管理者権限でないとみれないオブジェクトも多々あります。

取りあえずわかりづらく必要そうな属性を調べて見ました。

┌───────────┬────────────────────────────────────────────────────────┐
│属性名 │説明 │
├───────────┼────────────────────────────────────────────────────────┤
│Userオブジェクト │ │
├───────────┼────────────────────────────────────────────────────────┤
│objectGUID │オブジェクトのGUID(ActiveDirectory内で一意のはず) │
├───────────┼────────────────────────────────────────────────────────┤
│objectSID │セキュリティ識別子。S-1-5-21-……-513の形式 │
├───────────┼────────────────────────────────────────────────────────┤
│sAMAccountName │ユーザー・ログオン名(Windows 2000以前の互換ログオン名)。 │
├───────────┼────────────────────────────────────────────────────────┤
│createTimeStamp │作成日? │
├───────────┼────────────────────────────────────────────────────────┤
│modifyTimeStamp │最終変更日? │
├───────────┼────────────────────────────────────────────────────────┤
│WhenCreated │作成日 │
├───────────┼────────────────────────────────────────────────────────┤
│WhenChanged │最終変更日 │
├───────────┼────────────────────────────────────────────────────────┤
│userPrincipalName │ユーザー・ログオン名(Active Directory環境で利用されるユーザー名)。例:Tyamada@domain.local │
├───────────┼────────────────────────────────────────────────────────┤
│displayName │表示名。例:山田 太郎 │
├───────────┼────────────────────────────────────────────────────────┤
│logonCount │ログイン回数。ドメインコントローラが複数ある場合は別個に管理してる。DC間での複製はされない。 │
├───────────┼────────────────────────────────────────────────────────┤
│lastLogon │最終ログイン日時。ドメイン間では複製できない。 │
├───────────┼────────────────────────────────────────────────────────┤
│lastLogonTimestamp │最終ログイン日時。ドメイン間で複製される。ただし、複製期間は14日間隔。 │
├───────────┼────────────────────────────────────────────────────────┤
│userAccountControl │ユーザー アカウントのプロパティを開いて、[アカウント] タブの各オプションのbitフラグ。無効か有効かもここで判断。 │
├───────────┼────────────────────────────────────────────────────────┤
│distinguishedName │識別名。DN表記(CN=hoge,OU=eigyou,DC=domain,DC=jp) │
├───────────┼────────────────────────────────────────────────────────┤
│memberOf │ユーザが所属しているグループ。配列でDN表記識別名として帰る。 │
├───────────┼────────────────────────────────────────────────────────┤
│sn │姓 │
├───────────┼────────────────────────────────────────────────────────┤
│givenName │名 │
├───────────┼────────────────────────────────────────────────────────┤
│cn │CN名 │
├───────────┼────────────────────────────────────────────────────────┤
│description │説明 │
├───────────┼────────────────────────────────────────────────────────┤
│accountExpirationDate │アカウントの期限。日付形式帰る。 │
├───────────┼────────────────────────────────────────────────────────┤
│accountExpires │アカウントの期限。1601 年 1 月 1 日を基準にナノ秒単位で時間を記録する長整数型の値 │
├───────────┼────────────────────────────────────────────────────────┤
│usncreated │AD内部用? │
├───────────┼────────────────────────────────────────────────────────┤
│usnchanged │AD内部用? │
├───────────┼────────────────────────────────────────────────────────┤
│objectcategory │オブジェクトのカテゴリ │
├───────────┼────────────────────────────────────────────────────────┤
│pwdlastset │ユーザーが最後にパスワードを設定した日時 0なら次回パスワード変更必要あり。 │
├───────────┼────────────────────────────────────────────────────────┤
│adsPath │オブジェクトのパス LDAP://xxxx/CN= │
├───────────┼────────────────────────────────────────────────────────┤
│グループオブジェクト │ │
├───────────┼────────────────────────────────────────────────────────┤
│canonicalName │hogehoge.jp/Users/... オブジェクトのパス? │
├───────────┼────────────────────────────────────────────────────────┤
│cn │グループ名 │
├───────────┼────────────────────────────────────────────────────────┤
│createTimeStamp │作成日? │
├───────────┼────────────────────────────────────────────────────────┤
│description │説明 │
├───────────┼────────────────────────────────────────────────────────┤
│distinguishedName │識別名。DN表記(CN=hoge,OU=eigyou,DC=domain,DC=jp) │
├───────────┼────────────────────────────────────────────────────────┤
│member │グループのメンバ。配列でDN表記識別名。 │
├───────────┼────────────────────────────────────────────────────────┤
│modifyTimeStamp │最終変更日? │
├───────────┼────────────────────────────────────────────────────────┤
│name │グループ名 │
├───────────┼────────────────────────────────────────────────────────┤
│objectGUID │オブジェクトのGUID(ActiveDirectory内で一意のはず) │
├───────────┼────────────────────────────────────────────────────────┤
│objectSID │セキュリティ識別子。S-1-5-21-……-513の形式 │
├───────────┼────────────────────────────────────────────────────────┤
│sAMAccountName │グループ名 │
├───────────┼────────────────────────────────────────────────────────┤
│usncreated │AD内部用? │
├───────────┼────────────────────────────────────────────────────────┤
│usnchanged │AD内部用? │
├───────────┼────────────────────────────────────────────────────────┤
│objectcategory │オブジェクトのカテゴリ │
├───────────┼────────────────────────────────────────────────────────┤
│adsPath │オブジェクトのパス LDAP://xxxx/CN= │
├───────────┼────────────────────────────────────────────────────────┤
│WhenCreated │作成日 │
├───────────┼────────────────────────────────────────────────────────┤
│WhenChanged │最終変更日 │
├───────────┼────────────────────────────────────────────────────────┤
│groupType │グループの種類。グルーバルトか、ドメインローカルとか。。。 │
└───────────┴────────────────────────────────────────────────────────┘



また、属性についてはMSサポート:Windows 2000 スキーマ内での既定 Active ディレクトリの属性で一部説明されています。

(ちなみに余談ですが Active Directory スキーマだと、どういうクラスや型があるかわかるようですが、いまいちまだ不明です。
%systemroot%¥system32¥schmmgmt.msc でスキーマ見れるようですね。)
[PR]
by jehoshaphat | 2010-03-20 06:00 | サーバがらみ | Trackback | Comments(0)
(.Net)デザイナでテーブルアダプタでGroupBy指定
DataSetのデザイナを使って、テーブルアダプタを書いたんですが、その時にGroupByのクエリをしたいときの方法です。

方法といっても、クエリの追加ウィザードから「単一の値を返すSELECT」を実行すればいいだけです。
そうすると、SELECT で指定したフィールドの型が返り値となったメソッドが生成できます。

この返り値の型ですが、フィールドの型が int 等基本型の場合は注意が必要で、Nullable 型で返ってきます。

VB.Netだと Nullable(Of Integer) 見たいな感じで定義しないといけませんが、C# だと int? 見たいな感じで省略して定義できるようです。(C#でも正式には Nullable<int> となるようですが。。)

余談ですが、Nullableには ?? 演算子というものがあるようです。
Nullable型変数 ?? 値 という使い方をし、Nullable型変数がnullなら 値 を入れるということができるようです。
詳細は、Nullable 型 (C# によるプログラミング入門)参照。


(最近スパムコメントが多いんで、コメント承認制にしました。スパム側のIP,ホスト名は無数だし、キーワード設定にも引っかからないような巧妙なコメント多いんで困りますね...)
[PR]
by jehoshaphat | 2010-03-20 05:45 | .Net開発 | Trackback | Comments(0)
xcopyでフォルダコピー時に「ファイル名ですか、またはディレクトリ名ですか」と聞いてくる
下記のようなバッチファイルで、xcopy でフォルダコピーを書いてました。(相対パス指定でのコピーです。a,b,cはフォルダを表してます。)

xcopy "a" "b\c" /e /c /q /y
pause


なお、この時のフォルダ構成は下記のような感じです。

├─a
│ └─a
│ test.txt

└─b


コピー先が b¥c なのですが、c フォルダが無いパターンです。

この場合、バッチを実行すると下記のようなメッセージが表示され、入力を要求されます。

D:\mydoc\豆知識>xcopy "a" "b\c" /e /c /q /y
b\c は受け側のファイル名ですか、
またはディレクトリ名ですか
(F= ファイル、D= ディレクトリ)?


"D"を選択すると、ちゃんとコピーされますが、"F"を選択すると、c というファイルができてしまいます。
XCOPY - 拡張COPY [FPCU]DOS/V&Windowsコマンド・プロンプト・リファレンスによると、「複写先が既存のディレクトリを含まず、かつ、名前が円記号(¥)で終わっていない場合」に表示されるようです。


回避策としては、/i オプションを付けるか、受け側の指定を¥で終端するといいようです。

xcopy "a" "b\c\" /e /c /q /y
もしくは
xcopy "a" "b\c" /e /c /q /y i


余談ですが、ファイルのコピーで xcopy 使うときも同様の現象が出るようなので、下記のように強制的にファイルに指定してやるといいようです。

echo F | xcopy test.txt test2.txt /R /Y


参考:
単一ファイルコピー時に xcopyが「またはディレクトリ名ですか」ときいてくる罠の回避。 - 片っ端から忘れていけばいいじゃない。
[PR]
by jehoshaphat | 2010-03-10 18:30 | 豆知識 | Trackback | Comments(2)
リームバブルディスクの自動実行の禁止

最近、Windowsのオートラン機能を使ったUSBドライブ等でのウイルス感染が多いので、とりあえず自動実行を無効化しとくことにしました。

レジストリでもできるようですが、グループポリシーを使った方法です。

グループポリシーで、「コンピュータの構成」→「管理用テンプレート」→「システム」→「自動再生機能をオフにする」を有効にし、対象を「すべてのドライブ」にしとけばOKです。
[PR]
by jehoshaphat | 2010-03-10 18:24 | 豆知識 | Trackback | Comments(1)
(WindowsServer)グループポリシーを強制適用する
グループポリシーですが、クライアントに適用されるにはPCの起動,ログイン時か後はバックグラウンドで90分+アルファでのタイミングとなります。

グループポリシーのテストをする時にすぐにクライアントに反映させたいことがありますが、コマンドを使うことで強制的に適用することができるようです。

コマンドは、クライアントPCで下記のように指定するといいようです。

>gpupdate
↑変更があった部分のみ
>gpupdate /force
↑全てのオプションを再適用


参考:
@IT:Windows TIPS -- Tips:gpupdateでグループ・ポリシーの適用を強制する gpupdate の使い方です。
マイコミジャーナル:にわか管理者のためのActive Directory入門 (64) GPOの即時適用と初期状態の復元 Windows2000はgpupdateが使えないみたいです。
@IT:グループ・ポリシーの適用 グループポリシーの適用タイミングがかかれてます。
MSサポート:グループ ポリシー エディタで変更がすぐに適用されない レジストリ変更して、更新間隔を変更する方法が出ていました。


また、ドメインコントローラが複数ある場合はドメインコントローラ間での同期は通常15分置きに複製してるようです。
ですのでグループポリシーのテストをすぐに実行するときは、この複製も強制しなければなりません。

その方法として、"Active Directoryサイトとサービス" から Sites → ドメイン名 → Servers → ドメインコントローラ名 → NTDS Settings → 右ペインのサーバを右クリック → 今すぐレプリケート で可能です。

また、repadmin コマンドを使う方法もあるようです。

@IT:Active Directoryのデータベースを強制的に複製する
ITpro:repadminコマンドでドメイン・コントローラを手動で同期させる repadminコマンドの使い方です。
[PR]
by jehoshaphat | 2010-03-02 02:16 | サーバがらみ | Trackback | Comments(0)
(WindowsServer)グループポリシーでとあるURLを信頼済みするとさらにハマった件
グループポリシーでグループウェアを置いてあるサーバーを信頼済みにしました。
このグループウェアはトップページにフレームを使い、フレーム内のコンテンツは別サーバを利用しています。
つまり下記のような感じとなってます。
グルプウェアサーバ:https://www.example.com/
フレーム内処理サーバ:https://www.example_frame.com/

で、グループポリシーでIEのゾーンの設定を下記のように指定しました。

*.www.example.com 信頼済み
https://www.example_frame.com/ 信頼済み


すると社内のあちこちから電話爆撃発生です。

どうやらグループウェアトップページにアクセスすると警告のダイアログが出て消えないらしいのです。
現象が起きてるのIE7(IE8はまだ導入してない)の端末のみでした。
e0091163_2113388.jpg


とりあえずググったら下記の設定をするとよいとありました。

"ユーザーの構成" → "管理用テンプレート" → "Windowsコンポーネント" → "Internet Explorer" → "インターネットコントロールパネル" → "セキュリティページ" → "信頼済みサイトゾーン" の「より権限の少ないWebコンテンツゾーンのWebサイトがこのゾーンに移動できる」 を有効にする。

これを調べてみるとInternet Explorerをセキュリティのため適切に設定しましょうの"Internet Explorerをセキュリティのため適切に設定しましょう"に詳細が載ってました。
下位のゾーンから上位のゾーンにアクセスルときに警告がでるらしいですが、それを非表示できるようです。

確かに、これを有効にすると警告出なくなりました。

最初はヤフー等インターネットゾーンのページを開いてからグループウェアに行くから出るのかとおもってましたがどうやら違うようです。
しかし、グループウェア内の(信頼済み)ページからトップページ戻っても表示される。

で、ステータスバー見るとゾーンの表示が「不明なゾーン(混在)」となっています。

もしかして、、思ってゾーンのURL設定を

www.example.com 信頼済み

とすると治りました。

IE7ではゾーンのURL設定で *.www.example.com というように、ワイルドカードを先頭につけると www.example.com は適用範囲に入らないみたいですね。
まぁ確かによく考えるとその通りです。

しかし、IE6だと *.www.example.com としても、www.example.com は適用範囲に入るようです。

いい加減なもんです。。。。
[PR]
by jehoshaphat | 2010-03-02 02:12 | サーバがらみ | Trackback | Comments(0)