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 = 0×000000000005, big-endian)
15000000 (21 = 0×00000015, little-endian)
A065CF7E (2127521184 = 0×7ECF65A0, little-endian)
784B9B5F (1604012920 = 0×5F9B4B78, little-endian)
E77C8770 (1887927527 = 0X70877CE7, little-endian)
091C0100 (72713 = 0×00011c09, 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
Loop
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))
Next
End Function
Function EndianReverse(strHex)
Dim intCounter
For intCounter = Len(strHex) to 1 Step - 2
EndianReverse = EndianReverse & Mid(strHex, intCounter - 1, 2)
Next
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 & < and > 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.