Permalink
Find file Copy path
157acb4 Jan 16, 2015
1 contributor

Users who have contributed to this file

198 lines (159 sloc) 9.27 KB
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 }
}