Wednesday, August 8, 2012

Token Size report for users

I was posed a question as to how can we tell what is the Token Size for each users in the environment.
Microsoft provides a tool for use to calculate 1 user (http://www.microsoft.com/en-us/download/details.aspx?id=1448). But this tool from what I know only allows calculation of the token size for the current logon user and if computation of token size for another user is needed, the user's credentials will have to be provided (Which is a challenging task).
With that I set out to create a vbs for this and the below is the output that I would like to share.
The computation formula is based on 


Following formula to determine whether it is necessary to modify the MaxTokenSize value or not
TokenSize = [12 X number of user rights] + [token overhead] + [40 X number of group memberships] + 8s
This formula uses the following values:
·         d:  The number of domain logical groups a user is a member of plus the number of universal groups outside the user’s account domain plus the number of groups represented in SID history.
·         s:  The number of security global groups that a user is a member of plus the number of universal groups in a user’s account domain.
·         User rights include rights such as “Log on locally” or “Access this Computer from the network”. The only user rights that are added to an access token are those user rights that are configured on the server that hosts a secured resource.  Most of the users are likely to have only two or three user rights on the Exchange server. Administrators may have dozens of user rights. Each user right requires 12 bytes to store it in the token.
·         Token overhead includes multiple fields such as the token source, expiration time, and impersonation information. For example, a typical domain user has no special access or restrictions; token overhead is likely to be between 400 and 500 bytes.
·         Estimated value for ticket overhead can vary depending on factors such as DNS domain name length, client name and other factors.
·         Each group membership adds the group SID to the token together with an additional 16 bytes for associated attributes and information. The maximum possible size for SID is 68 bytes.  Therefore, each security group to which a user belongs typically adds 44 bytes to the user’s token size.

*** Assumes that [12 X number of user rights] + [token overhead] = 1200

The script is as below. To user copy and save the file as vbs

'Start of VBS

Const ForReading = 1

Const ADS_SCOPE_SUBTREE = 2

TotalGroups=0
UniversalGroup=0
LocalGroup=0
GlobalGroup = 0
I = 2

' Clean up.
Set objGroupList = Nothing
Set objUser = Nothing

'_________________________________________________________________________________

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile(INPUT_FILE_NAME, FOR_READING)
strSite = objFile.ReadAll
objFile.Close

' Create Excel Spreadsheet
Set app = CreateObject("Excel.Application")
Set wb = app.Workbooks.Add
wb.Activate
Set ws = wb.Sheets.Add

On Error Resume Next
app.Visible = True

ws.Cells(1,1).Value = "Display Name"
ws.Columns(1).ColumnWidth = 30
ws.cells(1,2).value = "SAMACCountName"
ws.columns(1,2).columnwidth = 30
'ws.Cells(1,3).Value = "Total Groups"
'ws.Columns(3).ColumnWidth = 10
ws.Cells(1,4).Value = "Local group"
ws.Columns(4).ColumnWidth = 10
ws.Cells(1,5).Value = "Universal group"
ws.Columns(5).ColumnWidth = 10
ws.Cells(1,6).Value = "Global group"
ws.Columns(6).ColumnWidth = 10

ws.Cells(1,6).Value = "Token Size"
ws.Columns(6).ColumnWidth = 10


'Replace the domain with your domain in your environment
Strdomain = "DC=contoso,DC=msft"

Set objConnection = CreateObject("ADODB.Connection")
Set objCommand =   CreateObject("ADODB.Command")
objConnection.Provider = "ADsDSOObject"
objConnection.Open "Active Directory Provider"

Set objCOmmand.ActiveConnection = objConnection
objCommand.CommandText = _
    "Select SAMAccountname,distinguishedname,displayname from 'LDAP://" & strDomain & "' " _
        & "Where objectcategory='user' AND SAMAccountname = '*'"
objCommand.Properties("Page Size") = 1000
objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE
Set objRecordSet = objCommand.Execute
objRecordSet.MoveFirst


Do Until objRecordSet.EOF

ws.cells(I,1).Value = objRecordSet.Fields("displayname").Value
ws.cells(I,2).value = objRecordSet.Fields("SAMAccountname").Value
  On Error Resume Next
wscript.echo objRecordSet.Fields("distinguishedname").Value

' Bind to the user object in Active Directory with the LDAP provider.
Set objUser = GetObject("LDAP://" & objRecordSet.Fields("distinguishedname").Value)

' Bind to dictionary object.
Set objGroupList = CreateObject("Scripting.Dictionary")

' Enumerate group memberships.
Call EnumGroups(objUser)
' ws.cells(I,3).value = TotalGroups
ws.cells(I,4).value = LocalGroup
ws.cells(I,5).value = UniversalGroup
ws.cells(I,6).value = GlobalGroup
'Token Size Computation based on http://support.microsoft.com/kb/327825
Tokensize = 1200 + localgroup*40 + 8*(UniversalGroup + GlobalGroup)
ws.cells(I,7).value = Tokensize

'To reset the numbers after each user
TotalGroups=0
UniversalGroup=0
LocalGroup=0
GlobalGroup = 0

objRecordSet.MoveNext
I = I + 1

Loop

'You may wish to change this to any path as needed.
ws.SaveAs "D:\Scripts\CalculateTokenSize\" & "usertoken.xlsx"
app.quit

'_____________________________________________________________


Sub EnumGroups(objADObject)
' Recursive subroutine to enumerate user group memberships.
' Includes nested group memberships.
Dim colstrGroups, objGroup, j
objGroupList.CompareMode = vbTextCompare
colstrGroups = objADObject.memberOf

If IsEmpty(colstrGroups) Then
Exit Sub
End If


If TypeName(colstrGroups) = "String" Then
Set objGroup = GetObject("LDAP://" & colstrGroups)
If Not objGroupList.Exists(objGroup.sAMAccountName) Then
objGroupList(objGroup.sAMAccountName) = True
Select Case objGroup.GroupType
    Case 2
        GlobalGroup = GlobalGroup +1
    Case 4
localgroup = Localgroup +1
    Case 8
UniversalGroup=UniversalGroup +1
    Case -2147483646
GlobalGroup = GlobalGroup +1
    Case -2147483644
        localgroup = Localgroup +1
    Case -2147483640
UniversalGroup=UniversalGroup +1
End Select


Call EnumGroups(objGroup)
End If
Set objGroup = Nothing
Exit Sub
End If

For j = 0 To UBound(colstrGroups)
Set objGroup = GetObject("LDAP://" & colstrGroups(j))
If Not objGroupList.Exists(objGroup.sAMAccountName) Then
objGroupList(objGroup.sAMAccountName) = True

Select Case objGroup.GroupType
    Case 2
        GlobalGroup = GlobalGroup +1
    Case 4
localgroup = Localgroup +1
    Case 8
UniversalGroup=UniversalGroup +1
    Case -2147483646
GlobalGroup = GlobalGroup +1
    Case -2147483644
        localgroup = Localgroup +1
    Case -2147483640
UniversalGroup=UniversalGroup +1
End Select

Call EnumGroups(objGroup)

End If

TotalGroups=TotalGroups+1


Next
Set objGroup = Nothing
End Sub

'End of VBS

2 comments:

  1. Thanks for this great script Vincent,
    thus the script was missing a few comments and you left some disorder in the columns...anyway here's the "updated" script. Thanks again !!!

    http://pastebin.com/9F49HFvz

    ReplyDelete
  2. I guess this would require excel to be installed on the target system. I tried this and got 'Invalid procedure call or argument' on line 20.

    ReplyDelete