-
Notifications
You must be signed in to change notification settings - Fork 202
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This function discovers all user accounts configured with a ServicePrincipalName in the Active Directory domain or forest and returns this data in a custom object including the following: * Domain * UserID * Description * SPNServers * SPNTypes * ServicePrincipalNames
- Loading branch information
Showing
1 changed file
with
197 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,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/03/2015 | ||
Version: 1.0 | ||
|
||
.DESCRIPTION | ||
This function discovers all user accounts configured with a ServicePrincipalName in the Active Directory domain or forest and returns this data in a custom object including the following: | ||
* Domain - the service account's domain | ||
* UserID - the SAM Account name for the service account | ||
* Description - service account's description property data | ||
* SPNServers - all servers configured with SPNs for the service account (server FQDNs stored in an array) | ||
* SPNTypes - all SPN types (classes) configured for the service account (SPN types stored in an array) | ||
* ServicePrincipalNames - all SPNs with a server FQDN configured for the service account (SPNs stored in an array) | ||
|
||
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 FQDNs. | ||
|
||
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. | ||
|
||
.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,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 } | ||
|
||
} |