[ADSI プログラミング] VBScript で SID(SDDL) を使用するには

ご無沙汰しております。 ILM 一家のパパ(お父さん)でございます。
暦上での秋は過ぎておりますが、猛暑の続く中、いかがお過ごしでしょうか。
とりあえず、ファミリーレストランでは秋メニューも始まっており、秋野菜の天ぷらなど食べては見たものの、なんか味気ないですね。本当の食欲の秋が、楽しみでなりません。

 

さて、久しぶりの投稿となりますが、今回は VBScript で ActiveDirectory の SID を扱う方法について、ご案内します。

Active Directory上では、user/group などのオブジェクトを SID(Security Identifier:セキュリティ識別子)で管理しています。SID は ドメイン内でユニークな値であり、user/group オブジェクトなどでは ObjectSID 属性として情報を保持していますが、格納値はバイナリ値であるため VBScript では直接扱う事が出来ません。

過去には、ADsSecurity.dll で機能提供されていた ADsSID オブジェクトにより、SID を VBScript を扱う事が可能でしたが、Active Directory サービス インターフェイス (ADSI) 2. 5 リソース キットの一部であった ADsSecurity.dll の提供も既に終了しており、この部分は VBScript のみで実装する必要がある状況となっています。

バイナリ値を扱う事が出来ない VBScript でどうするかというと、数値演算でバイナリ値を分割抽出し Hex関数で文字列化するという、少々強引な手段を用います。以下が関数例となります。

 

  <SID(バイナリ) を数値演算で文字列(SDDL)に変換するスクリプト関数>

  Function OctetString2String(byVal OctetStr)
      dim result
      dim j, loByte, hiByte
      result = ""
      for j = lbound(OctetStr) to ubound(OctetStr)
          hiByte = ascb(midb(OctetStr,j+1,1))
          loByte = hiByte mod 16
          hiByte = hiByte \ 16
          result = result & hex(hiByte) & hex(loByte)
      next
      OctetString2String = result
  End Function

 

これを使ってどのような事ができるか、もう少し、具体的な例をご紹介しましょう。

信頼関係をもつ複数のドメイン間で、グループメンバーに信頼関係先ドメインのアカウントを追加したり、逆に信頼関係ドメインのアカウントを含むグループオブジェクトのメンバーを参照する場合、SID の直接操作が避けられません。これは、信頼関係先ドメインのアカウント(User/Group)については、SID の解決が行えないため対象アカウントの AdsPath 形式の情報のみでは
オブジェクトを識別する事ができないためです。

グループメンバーに信頼関係先ドメインのアカウントを追加するような操作では、以下のよう対象ユーザアカウントの SID を SDDL形式とすることで、直接 信頼関係ドメインのグループメンバーに追加する事が可能です。

  グループ : jpdsilm1.extest.microsoft.com の testgroup1
  ユーザー : jpdsilm2.extest.microsoft.com の testuser1

  <スクリプト サンプル:グループメンバー追加>
  Set objGroup = GetObject(LDAP://CN=testgroup1,OU=MyGroup,DC=jpdsilm1,DC=microsoft,DC=com)
  Set objUser = GetObject(LDAP://CN=testuser1,CN=Users,DC=jpdsilm2,DC=extest,DC=microsoft,DC=com)
  valSID = objUser.Get("objectSid")
  strSID = OctetString2String(valSID)
  Wscript.Echo "<Sid=" & strSID & ">"
  objGroup.PutEx 3, "member", Array("<Sid=" & strSID & ">")
  objGroup.SetInfo

  Function OctetString2String(byVal OctetStr)
      dim result
      dim j, loByte, hiByte
      result = ""
      for j = lbound(OctetStr) to ubound(OctetStr)
          hiByte = ascb(midb(OctetStr,j+1,1))
          loByte = hiByte mod 16
          hiByte = hiByte \ 16
          result = result & hex(hiByte) & hex(loByte)
      next
      OctetString2String = result
  End Function

 

<スクリプト サンプル:グループメンバー参照>
  Set objADs = GetObject(LDAP://CN=testgroup1,OU=MyGroup,DC=jpdsilm1,DC=microsoft,DC=com)
  For Each objMem In objADs.Members 
      If ( objMem.class = "foreignSecurityPrincipal" ) then
          '該当オブジェクトドメインの SID 部分を取得
          objVal = objMem.ObjectSid
          strSID = OctetString2String(valSID)
          Wscript.Echo "<Sid=" & strSID & ">"
          Set objUser = GetObject("LDAP://jpdsilm2/<SID=" & strSID & ">")
          Wscript.ECho objUser. sAMAccountName
      End if
  Next

  Function OctetString2String(byVal OctetStr)
      dim result
      dim j, loByte, hiByte
      result = ""
      for j = lbound(OctetStr) to ubound(OctetStr)
          hiByte = ascb(midb(OctetStr,j+1,1))
          loByte = hiByte mod 16
          hiByte = hiByte \ 16
          result = result & hex(hiByte) & hex(loByte)
      next
      OctetString2String = result
  End Function

いかがでしたでしょうか。
実はこの手法、以前に一家のお母さん(ういこさん)が投稿した、PrimaryGroup を参照する手法でも使っています。 他にも、ACL/ACE の操作でも流用できるかもしれませんね。
ご参考になれば、幸いです。

 

実娘が夏休みの宿題におわれている
~お父さん より~