スクリプトセンターに挑戦!(ADSI でも論理演算って重要なんです!)

最近、私たちチーム一同、体調不良となってしまいました。忘年会等、皆様も体調管理が難しい季節でもあるかと思いますので、お気を付けください。今回の記事は、ひろと が書かせていただきます。

今回のお題ですが、シロアリは、厳密にいうとアリではなく、ゴキブリ・・・・。ではなくて、ADSI は、論理演算が必要なケースもあるということを記事にさせていただきたいと思います。

皆様ご存じのとおり、ADSI は、システム管理を行う上で非常に有益なインタフェースです。本ブログをご覧になっている皆様は、C# や VB.NET や、VBScript 等、ADSI を用いたユーザーの変更・追加・削除や、グループの追加、一覧作成といった管理を行っているかと思います。実際に作成してみると、"ここをこうしたいんだけど、やり方が・・・"という悩みがあるかと思います。特に、"userAccountControl" 属性とかいかがでしょう。

本属性は、ビットの On/Off により属性を決定します。根っからのプログラマ(アセンブラ大好きな方とか) の場合、ビットの論理演算とか生活の一部になっている方もいらっしゃるかもわかりません。しかしながら、システム管理
という観点でみれば、システムを安定稼働させる等のデベロッパーとは違う難しさがあると思っています。そこで、本ブログにて ADSI で有効な論理演算例を踏まえて、一緒に考えてみたいと
思います。

Hey, Scripting Guy ! にある記事を元に考えてみましょう。

パスワードが期限切れになることがないように Active Directory アカウントを構成する方法はありますか
https://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/oct06/hey1031.mspx

本記事にあるコードにて、次のようになっています。

If Not objUser.userAccountControl AND ADS_UF_DONT_EXPIRE_PASSWD Then ' ==== (1) 
    objUser.Put "userAccountControl", _
        objUser.userAccountControl XOR ADS_UF_DONT_EXPIRE_PASSWD  ' ==== (2)
    objUser.SetInfo
End If

太字にしたところが、論理演算が行われているところとなります。実際の処理はどうなっているのでしょうか。Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000 と定義されておりますので、userAccountControl の値にて、16 進数にて"10000" という箇所のフラグが立っているかを判断しています。

AND をとっておりますので、論理積ですね。論理積にてパターンを見た場合次のパターンで解がでます。

0 and 0 = 0
1 and 0 = 0
0 and 1 = 0
1 and 1 = 1 

つまり、True( 1 を返す) 場合は、userAccountControl にて、当該フラグが ON の場合のみとなります。

(2) については、どうでしょう。ここでは、XOR が使用されています。これは、排他的論理和ですね。パターンを見てみましょう。

0 xor 0 = 0
1 xor 0 = 1
0 xor 1 = 1
1 xor 1 = 0

ということは、userAccountControl にて、1 が設定されている場合 OFF が設定されることとなります。このときの注意は、userAccountControl にて、1 が設定されていない場合になります。当該フラグが ON が設定されてしまいます。つまり、排他的論理和にてフラグを OFF にする場合は、前もってフラグの状態がわかっていなければできないということになります。

無条件に、フラグを OFF にしたい場合はどうすればよいでしょうか。

私なら、C# の場合次のように記載します。

int val = (int) user.Properties["userAccountControl"].Value;
user.Properties["userAccountControl"].Value = val & ~(int) ADS_UF_DONT_EXPIRE_PASSWD;

~ 演算子ですが、日頃見慣れない演算子かと思います。この演算子は、1の補数を取る演算子です(ビット反転に使えます)。この場合、~(int) ADS_UF_DONT_EXPIRE_PASSWD = &hFFFEFFFF となります。これと AND を取るわけです。ビットが逆転しているため、ADS_UF_DONT_EXPIRE_PASSWD は、OFF それ以外は、ON です。ここで、UserAccountControl 内の ADS_UF_DONT_EXPIRE_PASSWD  が ON の場合は、(左側の値をUserAccountControl 内の値とします)

1 and 0 = 0
0 and 0 = 0

となりますので、必ず 0 になりますね。他のフラグに与える影響はどうでしょうか。

1 and 1 = 1
0 and 1 = 0

結果的には、左側の値が変化することはありません。逆に、ON にしたい場合は、私であれば
次のように書きます。

int val = (int) user.Properties["userAccountControl"].Value;
user.Properties["userAccountControl"].Value = val | (int) ADS_UF_DONT_EXPIRE_PASSWD;

| 演算子は、OR (論理和) をとります。論理和は、次のパターンとなります。

0 or 0 = 0
1 or 0 = 1
0 or 1 = 1
1 or 1 = 1

そうです、ともに0 以外は1 にします。これにより、無条件にパスワードの無期限化を行いたい場合は、OR を取ることでできるわけです。

このパターンを身につけてしまえば、UserAccountControl が大好物になると信じています。

余談 : UserAccountControl は、LDAP プロバイダのときに使える属性ですが、WinNT システムプロバイダのときは、UserFlags となります。ご注意ください。