VBAでActive Directoryのサブドメインを含む全ドメインを列挙する方法


ややマニアックな話題だが、ExcelのVBA(Visual Basic For Applications)を使って、社内のActive Directoryに接続し、サブドメインも含む全ドメイン名を列挙し、各ドメイン内のOUやグループを列挙する方法が分かったので、備忘のために記事にしておく。
Const ADS_SCOPE_SUBTREE = 2
Dim oConn As Variant
Dim oCommand As Variant
‘ ActiveDirectory接続用ADODBオブジェクト生成
Set oConn = CreateObject(“ADODB.Connection”)
Set oCommand = CreateObject(“ADODB.Command”)
oConn.Provider = “ADsDSOObject”
oConn.Open
Set oCommand.ActiveConnection = oConn
‘ Active Directoryのグローバルカタログに全ドメイン名を問い合わせ
oCommand.CommandText = _
    “SELECT distinguishedName from ” & _
    “‘GC://DC=inabata,DC=com’ WHERE objectClass=’domain'”
oCommand.Properties(“Page Size”) = 1000
oCommand.Properties(“Timeout”) = 300
oCommand.Properties(“Searchscope”) = ADS_SCOPE_SUBTREE
oCommand.Properties(“Cache Results”) = False
Set oRes = oCommand.Execute
If oRes.BOF Then Exit Sub
Do Until oRes.EOF
    sDomain = oRes.Fields(“distinguishedName”).Value
    oRes.MoveNext
Loop
ここまでで自社のActive Directory管轄下にあるサブドメインも含む全てのドメイン名を取得できる。
distinguishedName形式で取得しているので「DC=japan,DC=hogehoge,DC=com」といった形式になる。
次に、各ドメイン内のOUやグループ、コンピュータを列挙するのだが、僕はてっきり、各ドメインのドメインコントローラを先ず調べて、そのドメインコントローラに対してLDAPクエリーを投げる必要があると思っていた。
例えば、ドメインコントローラーのサーバ名が「DCServer01」だとすると、その配下の全OUを列挙するには、次のように問い合わせる必要があると思っていた。
oCommand.CommandText = _
    “SELECT distinguishedName from ” & _
    “‘LDAP://DCServer01/DC=japan,DC=hogehoge,DC=com’ ” & _
    “WHERE objectClass=’organizationalUnit'”
CommandTextに渡す問い合わせ文字列の中身を抜き出せば次のようになる。
SELECT distinguishedName
FROM ‘LDAP://DCServer01/DC=japan,DC=hogehoge,DC=com’
WHERE objectClass=’organizationalUnit’
ところが、このサーバ名の代わりに、ドット表記のドメイン名が使えることが分かったのだ。つまり次のような感じである。
SELECT distinguishedName
FROM ‘LDAP://japan.hogehoge.com/DC=japan,DC=hogehoge,DC=com’
WHERE objectClass=’organizationalUnit’
ドット表記のドメイン名なら、最初に取得した「DC=japan,DC=hogehoge,DC=com」形式のドメイン名から簡単に変換できるので、例えば下記のような関数として定義しておけばよい。
Function ToDottedName(ByVal sBuf As String) As String
    sBuf = Replace(sBuf, “DC=”, “”)
    sBuf = Replace(sBuf, “,”, “.”)
    ToDottedName = sBuf
End Function
後は、sDomainという引数で”DC=japan,DC=hogehoge,DC=com”形式のドメイン名を渡すようなサブルーチンを書けば、当該ドメイン内の全OUを列挙するなら、
oCommand.CommandText = _
    “SELECT distinguishedName from ” & _
    “‘LDAP://” & ToDottedName(sDomain) & “/” & sDomain & “‘ ” & _
    “WHERE objectClass=’organizationalUnit'”
当該ドメイン内の全Groupを列挙するなら
oCommand.CommandText = _
    “SELECT distinguishedName from ” & _
    “‘LDAP://” & ToDottedName(sDomain) & “/” & sDomain & “‘ ” & _
    “WHERE objectClass=’Group'”
当該ドメインの特定OU内の全コンピュータを列挙するなら、
oCommand.CommandText = _
    “SELECT distinguishedName from ” & _
    “‘LDAP://” & ToDottedName(sDomain) & “/OU=特定のOU名称’ ” & _
    “WHERE objectClass=’computer'”
などとなる。