-
Notifications
You must be signed in to change notification settings - Fork 72
/
Find-PSServiceAccounts.ps1
197 lines (159 loc) · 9.46 KB
/
Find-PSServiceAccounts.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
function Find-PSServiceAccounts
{
<#
.SYNOPSIS
This function discovers all user accounts configured with a ServicePrincipalName in the Active Directory domain or forest.
Find-PSServiceAccounts
Author: Sean Metcalf, Twitter: @PyroTek3
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None
Last Updated: 1/16/2015
Version: 1.1
.DESCRIPTION
This function discovers all user accounts configured with a ServicePrincipalName in the Active Directory domain or forest.
Currently, the script performs the following actions:
* Forest Mode: Queries a Global Catalog in the Active Directory root domain for all user accounts configured with a ServicePrincipalName in the forest by querying the Global Catalog for SPN info.
* Domain Mode: Queries a DC in the current Active Directory domain for all user accounts configured with a ServicePrincipalName in the forest by querying the DCfor SPN info.
* Identifies the ServicePrincipalNames associated with the account and reports on the SPN types and server names.
* Provides password last set date & last logon date for service accounts
REQUIRES: Active Directory user authentication. Standard user access is fine - admin access is not necessary.
.EXAMPLE
Find-PSServiceAccounts
Perform current AD domain user account SPN discovery via AD and returns the results in a custom PowerShell object.
.EXAMPLE
Find-PSServiceAccounts -Forest
Perform current AD forest user account SPN discovery via AD and returns the results in a custom PowerShell object.
.EXAMPLE
Find-PSServiceAccounts -Domain "ad.domain.com"
Perform user account SPN discovery for the Active Directory domain "ad.domain.com" via AD and returns the results in a custom PowerShell object.
.EXAMPLE
Find-PSServiceAccounts -Domain "ad.domain.com" -DumpSPNs
Perform user account SPN discovery for the Active Directory domain "ad.domain.com" via AD and returns the list of discovered SPN FQDNs (de-duplicated).
.NOTES
This function discovers all user accounts configured with a ServicePrincipalName in the Active Directory domain or forest.
.LINK
Blog: http://www.ADSecurity.org
Github repo: https://github.com/PyroTek3/PowerShell-AD-Recon
#>
Param
(
[ValidateSet("Domain", "Forest")]
[string]$Scope = "Domain",
[string]$DomainName,
[switch]$DumpSPNs,
[switch]$GetTGS
)
Write-Verbose "Get current Active Directory domain... "
IF ($Scope -eq "Domain")
{
IF (!($DomainName))
{
$ADDomainInfo = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$ADDomainName = $ADDomainInfo.Name
}
$ADDomainDN = "DC=" + $ADDomainName -Replace("\.",',DC=')
$ADDomainLDAPDN = 'LDAP://' + $ADDomainDN
Write-Output "Discovering service account SPNs in the AD Domain $ADDomainName "
}
IF ( ($Scope -eq "Forest") -AND (!($DomainName)) )
{
$ADForestInfo = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest()
$ADForestInfoRootDomain = $ADForestInfo.RootDomain
$ADForestInfoRootDomainDN = "DC=" + $ADForestInfoRootDomain -Replace("\.",',DC=')
$ADDomainLDAPDN = 'GC://' + $ADForestInfoRootDomainDN
Write-Output "Discovering service account SPNs in the AD Forest $ADForestInfoRootDomain "
}
$root = [ADSI]$ADDomainLDAPDN
$ADSearcher = new-Object System.DirectoryServices.DirectorySearcher($root,"(&(objectcategory=user)(serviceprincipalname=*))")
$ADSearcher.PageSize = 5000
$AllServiceAccounts = $ADSearcher.FindAll()
# $AllServiceAccountsCount = $AllServiceAccounts.Count
# Write-Output "Processing $AllServiceAccountsCount service accounts (user accounts) with SPNs discovered in AD ($ADDomainLDAPDN) `r "
$AllServiceAccountsReport = $Null
$AllServiceAccountsSPNs = @()
ForEach ($AllServiceAccountsItem in $AllServiceAccounts)
{
$AllServiceAccountsItemSPNTypes = @()
$AllServiceAccountsItemSPNServerNames = @()
$AllServiceAccountsItemSPNs = @()
ForEach ($AllServiceAccountsItemSPN in $AllServiceAccountsItem.properties.serviceprincipalname)
{
$AllServiceAccountsItemDomainName = $NULL
[array]$AllServiceAccountsItemmDNArray = $AllServiceAccountsItem.Path -Split(",DC=")
[int]$DomainNameFECount = 0
ForEach ($AllServiceAccountsItemmDNArrayItem in $AllServiceAccountsItemmDNArray)
{
IF ($DomainNameFECount -gt 0)
{ [string]$AllServiceAccountsItemDomainName += $AllServiceAccountsItemmDNArrayItem + "." }
$DomainNameFECount++
}
$AllServiceAccountsItemDomainName = $AllServiceAccountsItemDomainName.Substring(0,$AllServiceAccountsItemDomainName.Length-1)
$AllServiceAccountsItemSPNArray1 = $AllServiceAccountsItemSPN -Split("/")
$AllServiceAccountsItemSPNArray2 = $AllServiceAccountsItemSPNArray1 -Split(":")
[string]$AllServiceAccountsItemSPNType = $AllServiceAccountsItemSPNArray1[0]
[string]$AllServiceAccountsItemSPNServer = $AllServiceAccountsItemSPNArray2[1]
IF ($AllServiceAccountsItemSPNServer -notlike "*$AllServiceAccountsItemDomainName*" )
{
$AllServiceAccountsItemSPNServerName = $AllServiceAccountsItemSPNServer
$AllServiceAccountsItemSPNServerFQDN = $NULL
}
ELSE
{
$AllServiceAccountsItemSPNServerName = $AllServiceAccountsItemSPNServer -Replace(("."+ $AllServiceAccountsItemDomainName),"")
$AllServiceAccountsItemSPNServerFQDN = $AllServiceAccountsItemSPNServer
[array]$AllServiceAccountsSPNs += $AllServiceAccountsItemSPN
}
#[string]$AllMSSQLSPNsItemServerInstancePort = $ADSISQLServersItemSPNArray2[2]
[array]$AllServiceAccountsItemSPNTypes += $AllServiceAccountsItemSPNType
[array]$AllServiceAccountsItemSPNServerNames += $AllServiceAccountsItemSPNServerFQDN
[array]$AllServiceAccountsItemSPNs += $AllServiceAccountsItemSPN
}
[array]$AllServiceAccountsItemSPNTypes = $AllServiceAccountsItemSPNTypes | sort-object | get-unique
[array]$AllServiceAccountsItemSPNServerNames = $AllServiceAccountsItemSPNServerNames | sort-object | get-unique
[array]$AllServiceAccountsItemSPNs = $AllServiceAccountsItemSPNs | sort-object | get-unique
$AllServiceAccountsItemDN = $Null
[array]$AllServiceAccountsItemDNArray = ($AllServiceAccountsItem.Properties.distinguishedname) -Split(",DC=")
[int]$DomainNameFECount = 0
ForEach ($AllServiceAccountsItemDNArrayItem in $AllServiceAccountsItemDNArray)
{
IF ($DomainNameFECount -gt 0)
{ [string]$AllServiceAccountsItemDN += $AllServiceAccountsItemDNArrayItem + "." }
$DomainNameFECount++
}
$AllServiceAccountsItemDN = $AllServiceAccountsItemDN.Substring(0,$AllServiceAccountsItemDN.Length-1)
[string]$ServiceAccountsItemSAMAccountName = $AllServiceAccountsItem.properties.samaccountname
[string]$ServiceAccountsItemdescription = $AllServiceAccountsItem.properties.description
[string]$ServiceAccountsItempwdlastset = $AllServiceAccountsItem.properties.pwdlastset
[string]$ServiceAccountsItemPasswordLastSetDate = [datetime]::FromFileTimeUTC($ServiceAccountsItempwdlastset)
[string]$ServiceAccountsItemlastlogon = $AllServiceAccountsItem.properties.lastlogon
[string]$ServiceAccountsItemLastLogonDate = [datetime]::FromFileTimeUTC($ServiceAccountsItemlastlogon)
$ServiceAccountsReport = New-Object PSObject -Property @{
Domain = $AllServiceAccountsItemDomainName
UserID = $ServiceAccountsItemSAMAccountName
Description = $ServiceAccountsItemdescription
PasswordLastSet = $ServiceAccountsItemPasswordLastSetDate
LastLogon = $ServiceAccountsItemLastLogonDate
SPNServers = $AllServiceAccountsItemSPNServerNames
SPNTypes = $AllServiceAccountsItemSPNTypes
ServicePrincipalNames = $AllServiceAccountsItemSPNs
}
[array]$AllServiceAccountsReport += $ServiceAccountsReport
}
$AllServiceAccountsReport = $AllServiceAccountsReport | Select-Object Domain,UserID,PasswordLastSet,LastLogon,Description,SPNServers,SPNTypes,ServicePrincipalNames
If ($DumpSPNs -eq $True)
{
[array]$AllServiceAccountsSPNs = $AllServiceAccountsSPNs | sort-object | Get-Unique
return $AllServiceAccountsSPNs
IF ($GetTGS)
{
ForEach ($AllServiceAccountsSPNsItem in $AllServiceAccountsSPNs)
{
Add-Type -AssemblyName System.IdentityModel
New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList "$AllServiceAccountsSPNsItem"
}
}
}
ELSE
{ return $AllServiceAccountsReport }
}