新しいActiveDirectory(以下AD)を構築する事になった。
そうなるとアカウント管理、ユーザの登録が必要となる。社内には、メールアドレスや内線電話番号など、全社員のアドレス帳として管理しているDBがすでにあり、このユーザ情報を新規AD構築に活用すると相当便利そうだ。
しかしデータは何千件もあり、これを手動でADに全部登録するのは大変。なので、WSH*1のひとつであるVBScript(以下VBS)を使って自動登録するスクリプトを作ることにした。DBをいったんCSVに落とし(理由は後述)、VBSでCSVをADに追加するといったもの。VBSでADSI*2を操作すると、わりと簡単にADのメンテナンスが出来る。
MicrosoftのTechNetサイトに、AD操作に関するたくさんのサンプルソース・Tipsが公開されているので、スクリプトも組みやすい。
- スクリプト一覧 Active Directory
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/default.mspx
- Hey, Scripting Guy! - アーカイブ
- http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/default.mspx
これらの資料を元に、今回は以下の要件を満たすVBSを作成することにした。
- アドレス帳DBの情報を取得して、AD上にユーザがいなければユーザを作成。
- ユーザ区分に応じて、グループに登録する。
- 今後、新規のユーザがアドレス帳DBに登録されたら、AD上にユーザを作成。
- 今後、既存ユーザの情報がアドレス帳DB上で更新されたら、AD上の情報も更新。
- 今後、アドレス帳DBからユーザが削除されたら、AD上のユーザを削除。
- ユーザの追加・削除情報、および追加時に自動設定したログオンパスワードをメールで送付。
そして見事プログラミング完了し、自動化達成。
以下、参考になったVBAスクリプトのサンプルや手法を、今回の要件実装に沿って紹介。同じような事をしようとしている人に参考となれば。
<前提>今回の要件ではOUやグループが新規に作成されることは無いので、あらかじめ用意してるものとする。また、キーはユーザIDとする。
ActiveDirectory操作
まず1と3と4の実装。
ユーザの検索
重複登録してエラーになるといけないので、既存のADにユーザIDがあるかどうかチェック。
- Active Directory 内のユーザー アカウントの検索
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/list/uslsvb18.mspx
strUserName = "kenmyer" dtStart = TimeValue(Now()) Set objConnection = CreateObject("ADODB.Connection") objConnection.Open "Provider=ADsDSOObject;" Set objCommand = CreateObject("ADODB.Command") objCommand.ActiveConnection = objConnection objCommand.CommandText = _ "<LDAP://dc=fabrikam,dc=com>;(&(objectCategory=User)" & _ "(samAccountName=" & strUserName & "));samAccountName;subtree" Set objRecordSet = objCommand.Execute If objRecordset.RecordCount = 0 Then WScript.Echo "sAMAccountName: " & strUserName & " does not exist." Else WScript.Echo strUserName & " exists." End If objConnection.Close
今回はこれをFunction化して、あるかどうかTrue/Falseで返せるようにした。
アカウントの追加
- ユーザー アカウントの作成
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/manage/usmgvb05.mspx
Set objOU = GetObject("LDAP://OU=management,dc=fabrikam,dc=com") Set objUser = objOU.Create("User", "cn=MyerKen") objUser.Put "sAMAccountName", "myerken" objUser.SetInfo
属性の設定・変更
氏名や事業所名なども一緒にセットしておく。全項目設定可能だが、とりあえず「全般」タブの設定サンプル。
- ユーザー アカウントの [全般] プロパティの変更
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/modify/usmdvb28.mspx
Set objUser = GetObject _ ("LDAP://cn=myerken,ou=management,dc=fabrikam,dc=com") objUser.Put "userPrincipalName", "MyerKen@fabrikam.com" objUser.Put "sAMAccountName", "MyerKen01" objUser.Put "userWorkstations", "wks1,wks2,wks3" objUser.SetInfo
変更の場合はこれでよいが、新規の場合は上記「アカウントの追加」のスクリプトにちょっと手を加えれば良い。具体的には、
objUser.Put "sAMAccountName", "myerken"
の下に、他の属性をPutしていけば良いので、わざわざSetInfoしてGetObjectで開きなおす必要は無い。
パスワードの設定
- ユーザー パスワードの設定
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/pwds/uspwvb01.mspx
Set objUser = GetObject _ ("LDAP://cn=MyerKen,ou=management,dc=fabrikam,dc=com") objUser.SetPassword "i5A2sj*!"
これも、新規の場合は上記と同様GetObjectを再度やる必要は無い。ただし、ユーザ追加・属性設定の後いったんSetInfoを行っておかないとエラーになる。
ちなみに、既存ユーザのパスワードを再設定したい場合は、以下のようにする。
objUser.ChangePassword "i5A2sj*!"
パスワードの無期限化
ログインドメインとして使わず、ファイルサーバやIISなどの認証のみでADを利用する場合、パスワードの期限切れ通知をする方法が無いので有効期限があると困る場合はこれを設定しておくといい(注:セキュリティを考慮すること)。
Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000 Set objUser = GetObject _ ("LDAP://cn=myerken,ou=management,dc=fabrikam,dc=com") intUAC = objUser.Get("userAccountControl") If ADS_UF_DONT_EXPIRE_PASSWD AND intUAC Then Wscript.echo "Already enabled" Else objUser.Put "userAccountControl", intUAC XOR _ ADS_UF_DONT_EXPIRE_PASSWD objUser.SetInfo WScript.Echo "Password never expires is now enabled" End If
アカウントの有効化
新規追加の場合、そのままだと使えないので、有効化する必要がある。
- ユーザー アカウントの有効化
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/status/usstvb02.mspx
Set objUser = GetObject _ ("LDAP://cn=myerken,ou=management,dc=fabrikam,dc=com") objUser.AccountDisabled = FALSE objUser.SetInfo
次に2の実装。
既存グループへのユーザ追加
ちょうどよいサンプルが見つからなかったので、以下を組み合わせてちょっと修正。
- ユーザー、グループ、および OU の作成
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/manage/usmgvb06.mspx
- ローカルの Administrators グループにドメイン ユーザーを追加する方法はありますか
- http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/oct04/hey1008.mspx
Set objUser = GetObject _ ("LDAP://cn=myerken,ou=management,dc=fabrikam,dc=com") Set objGroup = GetObject _ ("LDAP://cn=Group1,ou=management,dc=fabrikam,dc=com") objGroup.Add(objUser.ADsPath)
ただ、グループにユーザがすでに登録されている場合上記を行うとエラーになってしまうので、グループに指定ユーザがいるかどうかのチェック。
- お前ら、wsh使ってますか? Part2
- http://pc2.2ch.net/win/kako/1022/10222/1022248379.html
の974で書かれている「objGroup.IsMember」を利用して、Addするかどうか判定する。
If Not objGroup.IsMember(objUser.ADsPath) Then objGroup.Add(objUser.ADsPath) End If
もしグループがあるかどうか判定する必要がある場合は、「ユーザの検索」で使用したスクリプトを流用して、その一部↓
objCommand.CommandText = _ "<LDAP://dc=fabrikam,dc=com>;(&(objectCategory=User)" & _ "(samAccountName=" & strUserName & "));samAccountName;subtree"
にある「objectCategory=User」を「objectCategory=Group」と書き換えたものを作成すると良い。この場合「strUserName」に検索するグループ名を代入する。
5の実装。
ユーザの削除
- Active Directory からのユーザー アカウントの削除
- http://www.microsoft.com/japan/technet/scriptcenter/scripts/ad/users/manage/usmgvb07.mspx
Set objOU = GetObject("LDAP://ou=hr,dc=fabrikam,dc=com") objOU.Delete "user", "cn=MyerKen"
ユーザを削除すると、所属するグループからも自動的に削除されるので、グループからユーザを削除する処理は不要。
最後に6の実装。
メール送信
追加・削除したユーザの一覧は、これまでのサンプルに書かれた処理で追加・削除処理を実行したタイミングに記録すれば可能なので割愛。
メールでの送信は、BASP21を利用すれば簡単に送付できる。
- BASP21 DLL
- http://www.hi-ho.ne.jp/babaq/basp21.html
<2016/9追記>
この記事を書いた頃は知らなかったのだが、Windows標準機能を使用することで、ランタイム等無しで送信も可能な様子(一部OSに制約あり)。
- CDO を使用してメール送信
- https://gallery.technet.microsoft.com/scriptcenter/e7dfcfb7-1f64-48ca-8d16-107091be99cc
Set objEmail = CreateObject("CDO.Message") objEmail.From = "helpdesk@fabrikam.com" objEmail.To = "administrator@fabrikam.com" objEmail.Subject = "Server down" objEmail.Textbody = "Server1 is no longer accessible over the network." objEmail.Configuration.Fields.Item _ ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2 objEmail.Configuration.Fields.Item _ ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = _ "smtpmailer" objEmail.Configuration.Fields.Item _ ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25 objEmail.Configuration.Fields.Update objEmail.Send
パラメータの詳細やOSによる制約等は、下記サイトを参照。
www.atmarkit.co.jp
serialty.blog117.fc2.com
パスワードの自動生成
上記「パスワードの設定」で初期パスワードを設定する必要がある。これを全て同じものにするか、別ファイルから読み込ませるか、パスワードを生成するスクリプトを作成するか色々やり方はあるだろう。
今回は以下のソースを参考に「プログラムでのパスワード自動生成」を行った。
- ASPの公園 【パスワード】パスワード生成
- http://www.f-store.net/asp/parts.asp?MODE=ITIRAN&key=4823
genPassword = "" Randomize For i = 1 to 8 intNum = Int(10 * Rnd + 48) intUpper = Int(26 * Rnd + 65) intLower = Int(26 * Rnd + 97) intRand = Int(3 * Rnd + 1) Select Case intRand Case 1 strPartPass = Chr(intNum) Case 2 strPartPass = Chr(intUpper) Case 3 strPartPass = Chr(intLower) End Select genPassword = genPassword & strPartPass Next response.write(genPassword & "<br>")
ASP用のソースだが、「response.write」などを除けば基本的にはVBSでも利用可能。
もちろん、これだけではAD上のセキュリティポリシーを満たさないだろうし、長さも設定できなかったり、「0(ゼロ)」と「O(オー)」といった似たような文字を使用したりするんで、上記を参考に改良が必要。
(ちなみに、パスワード設定のスクリプトでポリシーに満たさないパスワードを設定しようとすると、Windowsのシステムからエラーダイアログが表示されてしまう。タスクで処理する場合は中断してしまうので注意。)
これらの組み合わせで出来た「hoge.vbs」を、Windowsのタスクに登録する事で毎日決まった時間に、自動で処理してくれるようになる。
手動で行ってたら莫大な時間がかかる上、今後のユーザメンテが非常に面倒になるので、受けれる恩恵は計り知れない。
参考までに
本来はDBから直接ADへ反映させるのが理想だが、DB直接接続の実装に時間がかかりそうだったため、今回はCSVからADへ反映させることにした。DB側でCSVを生成し、AD側からそれをFTPで取得するような仕組みにしている。
そこで得た、VBスクリプトによる「FTP接続」と「CSVをDBとして使用する」サンプルを紹介。特にCSVやEXCELのデータを使ってADを更新するパターンは多いと思うので、参考になれば。
FTP接続
FTPの操作は以下を参考にした。
- 教えて!goo VBSについて
- http://oshiete1.goo.ne.jp/qa3119812.html?ans_count_asc=20
Windows標準のFTPクライアントをShellで呼び出して実行する方法である。上記をデータ取得する内容へ修正。
「ftpCommandList.txt」にftpコマンドを記述。 ----- ユーザ名 パスワード cd ディレクトリ移動 get address.csv bye ----- hoge.vbsに下記のVBSを記述。 ----- set WshShell = WScript.CreateObject("WScript.Shell") WshShell.Run "ftp -s:c:\ftpCommandList.txt ホスト名",1,1 -----
「WsgShell.Run」の引数3番目は、「1」だとFTPの終了を待ち、「0」か「指定無し」だと終了を待たない。CSVがないと次の処理に進めないので「1」した。
CSVをDBとして使用する
CSVを単なるテキストファイルとして使うと不便なので、DBとして扱かえるようにし、データの取得・更新にSQL文が使えるようにする。
- 8.1 エクセルやCSVをDB感覚で! - VBScript & JScript(JavaScript) Tips for WSH
- http://www.happy2-island.com/vbs/cafe02/capter00801.shtml
- 8.3 データの読み込み - VBScript & JScript(JavaScript) Tips for WSH
- http://www.happy2-island.com/vbs/cafe02/capter00803.shtml
Dim objADO Dim objRS 'ADOオブジェクトを作成します Set objADO = CreateObject("ADODB.Connection") 'ADOを使いCSVファイルを扱う準備(オープン)を行います objADO.Open "Driver={Microsoft Text Driver (*.txt; *.csv)};" & _ "DBQ=c:\happy;" & _ "ReadOnly=1" 'SQLを実行し、店舗コードがT5144のデータを抽出します Set objRS = objADO.Execute("select * from ADO_EXCEL.csv where 店舗コード='T5144'") 'SQLの実行結果をデータが無くなるまで表示します Do Until objRS.Eof = True 'フィールド値の表示 WScript.echo "店舗コード:" & objRS("店舗コード") & " 価格:" & objRS("価格") 'カーソルを次の行へ objRS.MoveNext Loop 'レコードセットをクローズします objRS.Close 'ADOオブジェクトをクローズします objADO.Close 'オブジェクトの破棄 Set objRS = Nothing Set objADO = Nothing
テーブル名に、CSVのファイル名(フォルダパス無し・拡張子有り)を使用するのがポイント。
上記ページには、EXCELファイルを使った方法も掲載されている。
Windowsサーバー Hacks ―管理者必携のテクニック & WSHスクリプト 100選
- 作者: Mitch Tulloch,高橋基信,占部優希
- 出版社/メーカー: オライリージャパン
- 発売日: 2005/05/26
- メディア: 単行本(ソフトカバー)
- 購入: 2人 クリック: 35回
- この商品を含むブログ (23件) を見る
Windowsサーバークックブック ―ネットワーク管理者のためのレシピ集
- 作者: Robbie Allen,マイクロソフト株式会社ITプロエバンジェリストチーム,株式会社クイープ
- 出版社/メーカー: オライリージャパン
- 発売日: 2006/05/01
- メディア: 大型本
- 購入: 1人 クリック: 25回
- この商品を含むブログ (14件) を見る
ADSI ASPプログラミング―次世代標準ディレクトリサービスAPI ADSI入門 (Programmer’s SELECTION)
- 作者: スティーブンハン,河端善博,Steven Hahn,トップスタジオ
- 出版社/メーカー: 翔泳社
- 発売日: 1999/06
- メディア: 単行本
- クリック: 9回
- この商品を含むブログ (2件) を見る