forked from maxbakhub/winposh
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCheckMaxTokenSize.ps1
408 lines (378 loc) · 23.1 KB
/
CheckMaxTokenSize.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
## Active Directory: PowerShell Script To Query DCs in a Domain to Report on Users SIDs and SIDHistory to Estimate their Token Size ##
<#
Overview:
This script will query for the items which make up the token and then calculate the token size based on that dynamic result using the formula in KB327825. It will also give you a total of how many SIDs are in the SIDHistory for the user, how many of each group scope the user has, and whether the account is trusted for delegation or not (if it is the token size may be much larger).
The script has had a major rewrite and now can be ran against a single user or a collection of users to gauge their estimate token size and provide information about where the "bloat" or size is coming from-specific groups, types of groups, group SIDHistory SIDs, user SIDHistory SIDs or Windows Kerberos claims (for Windows 8/Server 2012 or later computers).
Requires: ActiveDirectory PowerShell Module
Usage Example:
.\CheckMaxTokenSize.ps1 -Principals @('[email protected]', '[email protected]') $OSEmulation $false -Details $true
Resources:
https://gallery.technet.microsoft.com/scriptcenter/Check-for-MaxTokenSize-520e51e5#content
http://support.microsoft.com/kb/327825
#>
PARAM ([array]$Principals = ($env:USERNAME), $OSEmulation = $false, $Details = $false)
cls
Import-Module ActiveDirectory
Trap [Exception]
{
$Script:ExceptionMessage = $_
$Error.Clear()
continue
}
$ExportFile = $pwd.Path + "\" + $env:username + "_TokenSizeDetails.txt"
$global:FormatEnumerationLimit = -1
"Token Details for all Users" | Out-File -FilePath $ExportFile
"********************" | Out-File -FilePath $ExportFile -Append
"`n" | Out-File $ExportFile -Append
#If OS is not specified to hypothesize token size let's find the local OS and computer role
if ($OSEmulation -eq $false)
{
$OS = Get-WmiObject -Class Win32_OperatingSystem
$cs = gwmi -Namespace "root\cimv2" -class win32_computersystem
$DomainRole = $cs.domainrole
switch -regex ($DomainRole) {
[0-1]{
#Workstation.
$RoleString = "client"
if ($OS.BuildNumber -eq 3790)
{
$OperatingSystem = "Windows XP"
$OSBuild = $OS.BuildNumber
}
elseif (($OS.BuildNumber -eq 6001) -or ($OS.BuildNumber -eq 6002))
{
$OperatingSystem = "Windows Vista"
$OSBuild = $OS.BuildNumber
}
elseif (($OS.BuildNumber -eq 7600) -or ($OS.BuildNumber -eq 7601))
{
$OperatingSystem = "Windows 7"
$OSBuild = $OS.BuildNumber
}
elseif ($OS.BuildNumber -eq 9200)
{
$OperatingSystem = "Windows 8"
$OSBuild = $OS.BuildNumber
}
elseif ($OS.BuildNumber -eq 9600)
{
$OperatingSystem = "Windows 8.1"
$OSBuild = $OS.BuildNumber
}
elseif ($OS.BuildNumber -eq 10586)
{
$OperatingSystem = "Windows 10"
$OSBuild = $OS.BuildNumber
}
}
[2-3]{
#Member server.
$RoleString = "member server"
if ($OS.BuildNumber -eq 3790)
{
$OperatingSystem = "Windows Server 2003"
$OSBuild = $OS.BuildNumber
}
elseif (($OS.BuildNumber -eq 6001) -or ($OS.BuildNumber -eq 6002))
{
$OperatingSystem = "Windows Server 2008 RTM"
$OSBuild = $OS.BuildNumber
}
elseif (($OS.BuildNumber -eq 7600) -or ($OS.BuildNumber -eq 7601))
{
$OperatingSystem = "Windows Server 2008 R2"
$OSBuild = $OS.BuildNumber
}
elseif ($OS.BuildNumber -eq 9200)
{
$OperatingSystem = "Windows Server 2012"
$OSBuild = $OS.BuildNumber
}
elseif ($OS.BuildNumber -eq 9600)
{
$OperatingSystem = "Windows Server 2012 R2"
$OSBuild = $OS.BuildNumber
}
}
[4-5]{
#Domain Controller
$RoleString = "domain controller"
if ($OS.BuildNumber -eq 3790)
{
$OperatingSystem = "Windows Server 2003"
$OSBuild = $OS.BuildNumber
}
elseif (($OS.BuildNumber -eq 6001) -or ($OS.BuildNumber -eq 6002))
{
$OperatingSystem = "Windows Server 2008"
$OSBuild = $OS.BuildNumber
}
elseif (($OS.BuildNumber -eq 7600) -or ($OS.BuildNumber -eq 7601))
{
$OperatingSystem = "Windows Server 2008 R2"
$OSBuild = $OS.BuildNumber
}
elseif ($OS.BuildNumber -eq 9200)
{
$OperatingSystem = "Windows Server 2012"
$OSBuild = $OS.BuildNumber}
elseif ($OS.BuildNumber -eq 9600)
{
$OperatingSystem = "Windows Server 2012 R2"
$OSBuild = $OS.BuildNumber
}
}
}
}
if ($OSEmulation -eq $true)
{
#Prompt user to choose which OS since they chose to emulate.
$PromptTitle= "Operating System"
$Message = "Select which operating system to emulate for token sizing (size tolerance is and configuration OS dependant)."
$12K = New-Object System.Management.Automation.Host.ChoiceDescription "Gauge Kerberos token size using the Windows 7/Windows Server 2008 R2 and earlier default token size of &12K."
$48K = New-Object System.Management.Automation.Host.ChoiceDescription "Gauge Kerberos token size using the Windows 8/Windows Server 2012 default token size of &48K. Note: The &48K setting is optionally configurable for many earlier Windows versions."
$65K = New-Object System.Management.Automation.Host.ChoiceDescription "Gauge Kerberos token size using the Windows 10 and later default token size of &65K. Note: The &65K setting is optionally configurable for many earlier Windows versions."
$OSOptions = [System.Management.Automation.Host.ChoiceDescription[]]($12K,$48K,$65K)
$Result = $Host.UI.PromptForChoice($PromptTitle,$Message,$OSOptions,0)
switch ($Result)
{
0 {
$OSBuild = "7600"
"Gauging Kerberos token size using the Windows 7/Windows Server 2008 R2 and earlier default token size of 12K." | Out-File $ExportFile -Append
Write-host "Gauging Kerberos token size using the Windows 7/Windows Server 2008 R2 and earlier default token size of 12K."
}
1 {
$OSBuild = "9200"
"Gauging Kerberos token size using the Windows 8/Windows Server 2012 and later default token size of 48K. Note: The 48K setting is optionally configurable for many earlier Windows versions." | Out-File $ExportFile -Append
Write-host "Gauging Kerberos token size using the Windows 8/Windows Server 2012 and later default token size of 48K. Note: The 48K setting is optionally configurable for many earlier Windows versions."
}
2 {
$OSBuild = "10586"
"Gauging Kerberos token size using the Windows 10 default token size of 65K. Note: The 65K setting is optionally configurable for many earlier Windows versions." | Out-File $ExportFile -Append
Write-host "Gauging Kerberos token size using the Windows 8/Windows Server 2012 and later default token size of 65K. Note: The 65K setting is optionally configurable for many earlier Windows versions."
}
}
}
else
{
Write-Host "The computer is $OperatingSystem and is a $RoleString."
"The computer is $OperatingSystem and is a $RoleString." | Out-File $ExportFile -Append
}
function GetSIDHistorySIDs
{ param ([string]$objectname)
Trap [Exception]
{$Script:ExceptionMessage = $_
$Error.Clear()
continue}
$DomainInfo = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$RootString = "LDAP://" + $DomainInfo.Name
$Root = New-Object System.DirectoryServices.DirectoryEntry($RootString)
$searcher = New-Object DirectoryServices.DirectorySearcher($Root)
$searcher.Filter="(|(userprincipalname=$objectname)(name=$objectname))"
$results=$searcher.findone()
if ($results -ne $null)
{
$SIDHistoryResults = $results.properties.sidhistory
}
#Clean up the SIDs so they are formatted correctly
$SIDHistorySids = @()
foreach ($SIDHistorySid in $SIDHistoryResults)
{
$SIDString = (New-Object System.Security.Principal.SecurityIdentifier($SIDHistorySid,0)).Value
$SIDHistorySids += $SIDString
}
return $SIDHistorySids
}
foreach ($Principal in $Principals)
{
#Obtain domain SID for group SID comparisons.
$UserIdentity = New-Object System.Security.Principal.WindowsIdentity($Principal)
$Groups = $UserIdentity.get_Groups()
$DomainSID = $UserIdentity.User.AccountDomainSid
$GroupCount = $Groups.Count
if ($Details -eq $true)
{
$GroupDetails = New-Object PSObject
Write-Progress -Activity "Getting SIDHistory, and group details for review." -Status "Detailed results requested. This may take awhile." -ErrorAction SilentlyContinue
}
$AllGroupSIDHistories = @()
$SecurityGlobalScope = 0
$SecurityDomainLocalScope = 0
$SecurityUniversalInternalScope = 0
$SecurityUniversalExternalScope = 0
foreach ($GroupSid in $Groups)
{
$Group = [adsi]"LDAP://<SID=$GroupSid>"
$GroupType = $Group.groupType
if ($Group.name -ne $null)
{
$SIDHistorySids = GetSIDHistorySIDs $Group.name
If (($SIDHistorySids | Measure-Object).Count -gt 0)
{$AllGroupSIDHistories += $SIDHistorySids}
$GroupName = $Group.name.ToString()
#Resolve SIDHistories if possible to give more detail.
if (($Details -eq $true) -and ($SIDHistorySids -ne $null))
{
$GroupSIDHistoryDetails = New-Object PSObject
foreach ($GroupSIDHistory in $AllGroupSIDHistories)
{
$SIDHistGroup = New-Object System.Security.Principal.SecurityIdentifier($GroupSIDHistory)
$SIDHistGroupName = $SIDHistGroup.Translate([System.Security.Principal.NTAccount])
$GroupSIDHISTString = $GroupName + "--> " + $SIDHistGroupName
add-Member -InputObject $GroupSIDHistoryDetails -MemberType NoteProperty -Name $GroupSIDHistory -Value $GroupSIDHISTString -force
}
}
}
#Count number of security groups in different scopes.
switch -exact ($GroupType)
{"-2147483646" {
#Domain Global scope
$SecurityGlobalScope++
if ($Details -eq $true)
{
#Domain Global scope
$GroupNameString = $GroupName + " (" + ($GroupSID.ToString()) + ")"
add-Member -InputObject $GroupDetails -MemberType NoteProperty -Name $GroupNameString -Value "Domain Global Group"
$GroupNameString = $null
}
}
"-2147483644" {
#Domain Local scope
$SecurityDomainLocalScope++
if ($Details -eq $true)
{
$GroupNameString = $GroupName + " (" + ($GroupSID.ToString()) + ")"
Add-Member -InputObject $GroupDetails -MemberType NoteProperty -Name $GroupNameString -Value "Domain Local Group"
$GroupNameString = $null
}
}
"-2147483640" {
#Universal scope; must separate local
#domain universal groups from others.
if ($GroupSid -match $DomainSID)
{
$SecurityUniversalInternalScope++
if ($Details -eq $true)
{
$GroupNameString = $GroupName + " (" + ($GroupSID.ToString()) + ")"
Add-Member -InputObject $GroupDetails -MemberType NoteProperty -Name $GroupNameString -Value "Local Universal Group"
$GroupNameString = $null
}
}
else
{
$SecurityUniversalExternalScope++
if ($Details -eq $true)
{
$GroupNameString = $GroupName + " (" + ($GroupSID.ToString()) + ")"
Add-Member -InputObject $GroupDetails -MemberType NoteProperty -Name $GroupNameString -Value "External Universal Group"
$GroupNameString = $null
}
}
}
}
}
#Get user object SIDHistories
$SIDHistoryResults = GetSIDHistorySIDs $Principal
$SIDCounter = $SIDHistoryResults.count
#Resolve SIDHistories if possible to give more detail.
if (($Details -eq $true) -and ($SIDHistoryResults -ne $null))
{
$UserSIDHistoryDetails = New-Object PSObject
foreach ($SIDHistory in $SIDHistoryResults)
{
$SIDHist = New-Object System.Security.Principal.SecurityIdentifier($SIDHistory)
$SIDHistName = $SIDHist.Translate([System.Security.Principal.NTAccount])
add-Member -InputObject $UserSIDHistoryDetails -MemberType NoteProperty -Name $SIDHistName -Value $SIDHistory -force
}
}
$GroupSidHistoryCounter = $AllGroupSIDHistories.Count
$AllSIDHistories = $SIDCounter + $GroupSidHistoryCounter
#Calculate the current token size.
$TokenSize = 0 #Set to zero in case the script is *gasp* ran twice in the same PS.
$TokenSize = 1200 + (40 * ($SecurityDomainLocalScope + $SecurityUniversalExternalScope + $GroupSidHistoryCounter)) + (8 * ($SecurityGlobalScope + $SecurityUniversalInternalScope))
$DelegatedTokenSize = 2 * (1200 + (40 * ($SecurityDomainLocalScope + $SecurityUniversalExternalScope + $GroupSidHistoryCounter)) + (8 * ($SecurityGlobalScope + $SecurityUniversalInternalScope)))
#Begin output of details regarding the user into prompt and outfile.
"`n" | Out-File $ExportFile -Append
Write-Host " "
Write-host "Token Details for user $Principal"
"Token Details for user $Principal" | Out-File $ExportFile -Append
Write-host "**********************************"
"**********************************" | Out-File $ExportFile -Append
$Username = $UserIdentity.name
$PrincipalsDomain = $Username.Split('\')[0]
Write-Host "User's domain is $PrincipalsDomain."
"User's domain is $PrincipalsDomain." | Out-File $ExportFile -Append
Write-Host "Total estimated token size is $Tokensize."
"Total estimated token size is $Tokensize." | Out-File $ExportFile -Append
Write-Host "For access to DCs and delegatable resources the total estimated token delegation size is $DelegatedTokenSize."
"For access to DCs and delegatable resources the total estimated token delegation size is $DelegatedTokenSize." | Out-File $ExportFile -Append
$KerbKey = get-item -Path Registry::HKLM\SYSTEM\CurrentControlSet\Control\LSA\Kerberos\Parameters
$MaxTokenSizeValue = $KerbKey.GetValue('MaxTokenSize')
if ($MaxTokenSizeValue -eq $null)
{
if ($OSBuild -lt 9200)
{$MaxTokenSizeValue = 12000}
if ($OSBuild -ge 9200)
{$MaxTokenSizeValue = 48000}
}
Write-Host "Effective MaxTokenSize value is: $Maxtokensizevalue"
"Effective MaxTokenSize value is: $Maxtokensizevalue" | Out-File $ExportFile -Append
#Assess OS so we can alert based on default for proper OS version. Windows 8 and Server 2012 allow for a larger token size safely.
$ProblemDetected = $false
if (($OSBuild -lt 9200) -and (($Tokensize -ge 12000) -or ((($Tokensize -gt $MaxTokenSizeValue) -or ($DelegatedTokenSize -gt $MaxTokenSizeValue)) -and ($MaxTokenSizeValue -ne $null))))
{
Write-Host "Problem detected. The token was too large for consistent authorization. Alter the maximum size per KB http://support.microsoft.com/kb/327825 and consider reducing direct and transitive group memberships." -ForegroundColor "red"
}
elseif ((($OSBuild -eq 9200) -or ($OSBuild -eq 9600)) -and (($Tokensize -ge 48000) -or ((($Tokensize -gt $MaxTokenSizeValue) -or ($DelegatedTokenSize -gt $MaxTokenSizeValue)) -and ($MaxTokenSizeValue -ne $null))))
{
Write-Host "Problem detected. The token was too large for consistent authorization. Alter the maximum size per KB http://support.microsoft.com/kb/327825 and consider reducing direct and transitive group memberships." -ForegroundColor "red"
}
elseif (($OSBuild -eq 10586) -and (($Tokensize -ge 65535) -or ((($Tokensize -gt $MaxTokenSizeValue) -or ($DelegatedTokenSize -gt $MaxTokenSizeValue)) -and ($MaxTokenSizeValue -ne $null))))
{
Write-Host "WARNING: The token was large enough that it may have problems when being used for Kerberos delegation or for access to Active Directory domain controller services. Alter the maximum size per KB http://support.microsoft.com/kb/327825 and consider reducing direct and transitive group memberships." -ForegroundColor "yellow"
}
else
{
Write-Host "Problem not detected." -backgroundcolor "green"
}
if ($Details -eq $true)
{
"`n" | Out-File $ExportFile -Append
Write-Host " "
Write-Host "*Token Details for $principal*"
"*Token Details*" | Out-File $ExportFile -Append
Write-Host "There are $GroupCount groups in the token."
"There are $GroupCount groups in the token." | Out-File $ExportFile -Append
Write-host "There are $SIDCounter SIDs in the users SIDHistory."
"There are $SIDCounter SIDs in the users SIDHistory." | Out-File $ExportFile -Append
Write-host "There are $GroupSidHistoryCounter SIDs in the users groups SIDHistory attributes."
"There are $GroupSidHistoryCounter SIDs in the users groups SIDHistory attributes." | Out-File $ExportFile -Append
Write-host "There are $AllSIDHistories total SIDHistories for user and groups user is a member of."
"There are $AllSIDHistories total SIDHistories for user and groups user is a member of." | Out-File $ExportFile -Append
Write-Host "$SecurityGlobalScope are domain global scope security groups."
"$SecurityDomainLocalScope are domain local security groups." | Out-File $ExportFile -Append
Write-Host "$SecurityDomainLocalScope are domain local security groups."
"$SecurityUniversalInternalScope are universal security groups inside of the users domain." | Out-File $ExportFile -Append
Write-Host "$SecurityUniversalInternalScope are universal security groups inside of the users domain."
"$SecurityUniversalExternalScope are universal security groups outside of the users domain." | Out-File $ExportFile -Append
Write-Host "$SecurityUniversalExternalScope are universal security groups outside of the users domain."
Write-Host "Summary and all other token content details can be found in the output file at $ExportFile"
"`n" | Out-File $ExportFile -Append
"Group Details" | Out-File $ExportFile -Append
$GroupDetails | FL * | Out-File -FilePath $ExportFile -width 500 -Append
"`n" | Out-File $ExportFile -Append
"Group SIDHistory Details" | Out-File $ExportFile -Append
if ($GroupSIDHistoryDetails -eq $null)
{"[NONE FOUND]" | Out-File $ExportFile -Append}
else
{$GroupSIDHistoryDetails | FL * | Out-File -FilePath $ExportFile -width 500 -Append}
"`n" | Out-File $ExportFile -Append
"User SIDHistory Details" | Out-File $ExportFile -Append
if ($UserSIDHistoryDetails -eq $null)
{"[NONE FOUND]" | Out-File $ExportFile -Append}
else
{$UserSIDHistoryDetails | FL * | Out-File -FilePath $ExportFile -width 500 -Append}
"`n" | Out-File $ExportFile -Append
}
}