Scripting. Stuff. (By Froosh)

January 6, 2009

Byte Array and SID manipulation class and component

Filed under: VBScript — Froosh @ 11:41 am

In a move that is a little like Marge re-using the 1 stylish dress she found, I’ve wrapped my old Byte() and SID manipulation code into a VBScript Class and a Windows Script Component.

The class code can be directly used within your VBScript VBS/WSF file, or included in a WSF package with the <script src=…> tag.

The Windows Script Component needs to be installed on each machine it will be used with and registered with “regsvr32 scrobj.dll /n /i:<path to wsc file>”.

Alternatively, it may be possible to use the WSC without registering it as in the following snippet:

Set objComponent = GetObject(“script:c:\COM\MyComponent.wsc”)

This loads the first (or only) <component> section and is usable the same way as calling CreateObject(“MyComponent”). One upside of this is that normally component registration requires administrator rights, but using a WSC this way does not.


October 21, 2005

Hex SID to Decimal SID Translation

Filed under: VBScript — Froosh @ 11:46 am

Update: I’ve rolled this into a VBScript class and a Windows Script Component.

If you’ve ever played with SIDs in VBScript, you will have needed to convert a binary SID to the usual slightly-human-readable decimal format (e.g. S-1-5-21-xxxxxxxx-etc). Since I couldn’t find any examples of VBScript to do this, I’ve had to create it myself – and I post it here to use, poke fun at, or ignore at your leisure 😀

The two main references I needed to make this possible are from two of the very best programming blogs I read: The Old New Thing: How do I convert a SID between binary and string forms? and Fabulous Adventures In Coding: Integer Arithmetic in VBScript, Part Two. Also useful are the MSDN article on Well Known SIDs and my previous posting here VBScript vs. Byte().

The guts of the script is based on this excerpt from The Old New Thing:

If your SID is S-1-5-21-2127521184-1604012920-1887927527-72713, then your raw hex SID is 010500000000000515000000A065CF7E784B9B5FE77C8770091C0100

This breaks down as follows:
01 S-1
05 (seven dashes, seven minus two = 5)
000000000005 (5 = 0x000000000005, big-endian)
15000000 (21 = 0x00000015, little-endian)
A065CF7E (2127521184 = 0x7ECF65A0, little-endian)
784B9B5F (1604012920 = 0x5F9B4B78, little-endian)
E77C8770 (1887927527 = 0X70877CE7, little-endian)
091C0100 (72713 = 0x00011c09, little-endian)

And without further ado, here is the code to convert a hex string representation of a SID to the decimal format (and back again). Also included is the little helper function to swap between big- and little-endian representations. Note: Lines may be wrapped – it’s not worth my effort right now to format it nicely. Leave a comment if you want me to e-mail it to you.

Function ConvertHexStringToSidString(strHex)
  Const intSidVersionLength = 2
  Const intSubAuthorityCountLength = 2
  Const intAuthorityIdentifierLength = 12
  Const intSubAuthorityLength = 8

  Dim intStringPosition, bytSidVersion, lngAuthorityIdentifier, bytSubAuthorityCount, lngTempSubAuthority

  intStringPosition = 1

  bytSidVersion = CByte("&h" & Mid(strHex, intStringPosition, intSidVersionLength))
  intStringPosition = intStringPosition + intSidVersionLength

  bytSubAuthorityCount = CByte("&h" & Mid(strHex, intStringPosition, intSubAuthorityCountLength))
  intStringPosition = intStringPosition + intSubAuthorityCountLength

  lngAuthorityIdentifier = CLng("&h" & Mid(strHex, intStringPosition, intAuthorityIdentifierLength))
  intStringPosition = intStringPosition + intAuthorityIdentifierLength

  ConvertHexStringToSidString = "S-" & bytSidVersion & "-" & lngAuthorityIdentifier

  Do Until bytSubAuthorityCount = 0
    lngTempSubAuthority = CLng("&h" & EndianReverse(Mid(strHex, intStringPosition, intSubAuthorityLength)))
    intStringPosition = intStringPosition + intSubAuthorityLength

    If lngTempSubAuthority < 0 Then lngTempSubAuthority = lngTempSubAuthority + 2^32

    ConvertHexStringToSidString = ConvertHexStringToSidString & "-" & lngTempSubAuthority

    bytSubAuthorityCount = bytSubAuthorityCount - 1
End Function

Function ConvertSidStringToHexString(strSID)
  Const intSidVersionLength = 2
  Const intSubAuthorityCountLength = 2
  Const intAuthorityIdentifierLength = 12
  Const intSubAuthorityLength = 8

  Dim intCounter, arrSplitSid, bytSidVersion, lngAuthorityIdentifier, bytSubAuthorityCount, dblTempSubAuthority

  arrSplitSid = Split(strSID, "-")

  bytSidVersion = CByte(arrSplitSid(LBound(arrSplitSid) + 1))
  bytSubAuthorityCount = CByte(UBound(arrSplitSid) - LBound(arrSplitSid) - 2)
  lngAuthorityIdentifier = CLng(arrSplitSid(LBound(arrSplitSid) + 2))

  ConvertSidStringToHexString = Right(String(intSidVersionLength, "0") & Hex(bytSidVersion), intSidVersionLength)
  ConvertSidStringToHexString = ConvertSidStringToHexString & Right(String(intSubAuthorityCountLength, "0") & Hex(bytSubAuthorityCount), intSubAuthorityCountLength)
  ConvertSidStringToHexString = ConvertSidStringToHexString & Right(String(intAuthorityIdentifierLength, "0") & Hex(lngAuthorityIdentifier), intAuthorityIdentifierLength)

  For intCounter = (LBound(arrSplitSid) + 3) to UBound(arrSplitSid)
    dblTempSubAuthority = CDbl(arrSplitSid(intCounter))
    If dblTempSubAuthority > 2^31 - 1 Then dblTempSubAuthority = dblTempSubAuthority - 2^32
    ConvertSidStringToHexString = ConvertSidStringToHexString & EndianReverse(Right(String(intSubAuthorityLength, "0") & Hex(dblTempSubAuthority), intSubAuthorityLength))
End Function

Function EndianReverse(strHex)
  Dim intCounter

  For intCounter = Len(strHex) to 1 Step - 2
    EndianReverse = EndianReverse & Mid(strHex, intCounter - 1, 2)
End Function

Enjoy! (I may comment these in the future for clarity, but don’t count on it.)

Update 4-Sep-2007: Wow, I must have had a bad day when I posted this – it was completely borkened. Updated with (I hope) actual working script and the mirror function to convert them back to strings. Oh, and using the new built-in syntax highlighter. Look out for the &amp; &lt; and &gt; in the code above as they need to be replaced with actual & < and > symbols. It seems the editor is munging the code when the syntax highlighter instructions tell us not to worry about the HTML entities.

Update 8-May-2008: Looks like the syntax highlighter was updated some time in the past to handle the HTML elements and the ‘copy to clipboard’ option also works perfectly.

Update 12-Aug-2008: Sigh.  It seems the the code keeps getting messed up.  I’m still happy to e-mail out the scriptlet, though sometimes I’m a bit laggy.

September 22, 2005

VBScript vs. Byte()

Filed under: VBScript — Froosh @ 9:43 am

In a recent fight with VBScript I was attempting to read SID’s from the logged in users Access Token and translate them to group names. In the process, objUser.Get(“tokenGroups”) returns a Variant() array of Byte() arrays.

Easy you say, just do something like for each bytPart in Byte() … except that VBScript doesn’t actually know how to work with a Byte(). It knows Byte and Array(), just not how they work together.

After much head-scratching and googling, the secret was revelead in a snippet of code attributed to Richard Mueller, a MS MVP in Scripting and ADSI (found on Michael Harris’ blog). And the secret is: Byte() arrays are really just byte strings (as opposed to unicode/char strings).

Knowing that, the next minor secret is how to work with byte strings. Unsurprisingly, the answer is in the documentation. Read any of the string functions (Len, InStr, Mid, etc) and pay attention to any Note: sections that mention a *B variant of the function. e.g. LenB, InStrB, MidB

ConvertByteArrayToHexString = ""
For intCounter = 1 to LenB(arrBytes)
  ConvertByteArrayToHexString = ConvertByteArrayToHexString & Right("0" & Hex(AscB(MidB(arrBytes, intCounter, 1))), 2)

So now you know. Happy Byte()-ing!

Blog at