Invoke TrimarcADChecks
Invoke TrimarcADChecks
SCRIPTNAME: Invoke-TrimarcADChecks.ps1
AUTHOR: Sean Metcalf
#>
Param
(
$Domain,
$ReportDir = 'c:\temp\Trimarc-ADReports',
[int]$UserLogonAge = '180',
[int]$UserPasswordAge = '180'
## FUNCTION
function Get-NameForGUID{
# From http://blog.wobl.it/2016/04/active-directory-guid-to-friendly-name-using-
just-powershell/
[CmdletBinding()]
Param(
[guid]$guid,
[string]$ForestDNSName
)
Begin{
IF (!$ForestDNSName)
{ $ForestDNSName = (Get-ADForest $ForestDNSName).Name }
$ExtendedRightGUIDs = "LDAP://cn=Extended-Rights,cn=configuration,
$ForestDNSNameDN"
$PropertyGUIDs = "LDAP://cn=schema,cn=configuration,
$ForestDNSNameDN"
}
Process{
If($guid -eq "00000000-0000-0000-0000-000000000000"){
Return "All"
}Else{
$rightsGuid = $guid
$property = "cn"
$SearchAdsi = ([ADSISEARCHER]"(rightsGuid=$rightsGuid)")
$SearchAdsi.SearchRoot = $ExtendedRightGUIDs
$SearchAdsi.SearchScope = "OneLevel"
$SearchAdsiRes = $SearchAdsi.FindOne()
If($SearchAdsiRes){
Return $SearchAdsiRes.Properties[$property]
}Else{
$SchemaGuid = $guid
$SchemaByteString = "\" + ((([guid]
$SchemaGuid).ToByteArray() | %{$_.ToString("x2")}) -Join "\")
$property = "ldapDisplayName"
$SearchAdsi =
([ADSISEARCHER]"(schemaIDGUID=$SchemaByteString)")
$SearchAdsi.SearchRoot = $PropertyGUIDs
$SearchAdsi.SearchScope = "OneLevel"
$SearchAdsiRes = $SearchAdsi.FindOne()
If($SearchAdsiRes){
Return $SearchAdsiRes.Properties[$property]
}Else{
Write-Host -f Yellow $guid
Return $guid.ToString()
}
}
}
}
}
Function Get-ListFromArray
{
Param
(
$Array
)
$ArrayList = $NULL
ForEach ($ArrayItem in $Array)
{ [string]$ArrayList += "$ArrayItem; " }
IF ($ArrayList)
{ $ArrayList = $ArrayList.Substring(0,$ArrayList.Length-2) }
Return $ArrayList
}
$ScriptTimer = [System.Diagnostics.Stopwatch]::StartNew()
IF (!$Domain)
{ $Domain = (Get-ADDomain).DNSRoot }
Import-Module ActiveDirectory
Import-Module GroupPolicy
Write-Host ""
IF (($ADForestInfo.Domains).count -gt 1)
{ Write-Host "There are $(($ADForestInfo.Domains).count) domains in the AD Forest.
Only the currently selected domain ($ADDomainName) is being analyzed. `n" -Fore
Cyan }
ELSE
{ Write-Host "The AD Forest is a single domain forest and is now being analyzed...
`n" -Fore Cyan }
Write-Host ""
## Identify AD FFL/DFL
## Get AD Forest & Domain Info
$ADForestFunctionalLevel = (Get-ADForest).ForestMode
$ADDomainFunctionalLevel = (Get-ADDomain $Domain).DomainMode
Write-Host "The AD Forest Functional Level is $ADForestFunctionalLevel `n" -Fore
Cyan
Write-Host "The AD Domain Functional Level ($Domain) is $ADDomainFunctionalLevel
`n" -Fore Cyan
Write-Host ""
## Get Domain Controllers
$DomainDCs = Get-ADDomainController -filter * -Server $DomainDC
Write-Host "$ADDomainName AD Forest Domain Controllers and OS Version: `n" -Fore
Cyan
$DomainDCs | Select HostName,OperatingSystem | Format-Table -AutoSize
$DomainDCArray = @()
ForEach ($DomainDCItem in $DomainDCs)
{
$DomainDCItem | Add-Member -MemberType NoteProperty -Name FSMORolesList -Value
(Get-ListFromArray $DomainDCItem.OperationMasterRoles) -Force
$DomainDCItem | Add-Member -MemberType NoteProperty -Name PartitionsList -Value
(Get-ListFromArray $DomainDCItem.Partitions) -Force
[array]$DomainDCArray += $DomainDCItem
}
## AD Backups
# From https://devblogs.microsoft.com/scripting/use-a-powershell-script-to-show-
active-directory-backup-status-info/
[string[]]$Partitions = (Get-ADRootDSE -Server $DomainDC).namingContexts
$contextType =
[System.DirectoryServices.ActiveDirectory.DirectoryContextType]::Domain
$context = new-object
System.DirectoryServices.ActiveDirectory.DirectoryContext($contextType,
$ADDomainName)
$domainController =
[System.DirectoryServices.ActiveDirectory.DomainController]::findOne($context)
Write-Host "Determining last supported backup of AD partitions... `n" -
ForegroundColor Cyan
ForEach($partition in $partitions)
{
$domainControllerMetadata = $domainController.GetReplicationMetadata($partition)
$dsaSignature = $domainControllerMetadata.Item(“dsaSignature”)
Write-Host “$partition was backed up $
($dsaSignature.LastOriginatingChangeTime.DateTime)"
}
Write-Host " `n"
## Trusts
$ADTrusts = Get-ADTrust -Filter * -Server $DomainDC
$ADTrustFile = $ReportDir + "\TrimarcADChecks-DomainTrustReport-$Domain-
$TimeVal.csv"
$ADTrusts | Export-CSV $ADTrustFile -NoTypeInformation
Write-Host "$Domain Active Directory Trusts: `n" -Fore Cyan
$ADTrusts | Select
Source,Target,Direction,IntraForest,SelectiveAuth,SIDFilteringForestAware,SIDFilter
ingQuarantined | Format-Table -AutoSize
Write-Host "Active Directory Trusts ($Domain) saved to the file $ADTrustFile `n"
Write-Output " "
"@
$DomainUserReport
## Identify AD Admins
$ADAdminArray = @()
$ADAdminMembers = Get-ADGroupMember Administrators -Recursive -Server $DomainDC
ForEach ($ADAdminMemberItem in $ADAdminMembers)
{
TRY
{
Switch ($ADAdminMemberItem.objectClass)
{
'User' { [array]$ADAdminArray += Get-ADUser $ADAdminMemberItem -Properties
LastLogonDate,PasswordLastSet,ServicePrincipalName -Server $DomainDC }
'Computer' { [array]$ADAdminArray += Get-ADComputer $ADAdminMemberItem -
Properties LastLogonDate,PasswordLastSet -Server $DomainDC }
'msDS-GroupManagedServiceAccount' { [array]$ADAdminArray += Get-
ADServiceAccount $ADAdminMemberItem -Properties LastLogonDate,PasswordLastSet -
Server $DomainDC}
}
}
CATCH
{ Write-Warning "The security principal member ($ADAdminMemberItem) may be in
another domain or is unreachable" ; $ADAdminArray += $ADAdminMemberItem }
}
Write-Host " "
Write-Host "$ADDomainName AD Admins: " -Fore Cyan
$ADAdminArray | sort PasswordLastSet | select
name,DistinguishedName,PasswordLastSet,LastLogonDate,ObjectClass | Format-Table -
AutoSize
Write-Host ""
}
TRY
{
[array]$ADPrivGroupArray = Get-ADGroup -filter {Name -like "*VMWare*"} -Server
$DomainDC
ForEach ($ADPrivGroupItem in $ADPrivGroupArray)
{
$ADPrivGroupItemGroupMembership = Get-ADGroupMember
$ADPrivGroupItem.SamAccountName -Server $DomainDC
IF ($ADPrivGroupItemGroupMembership.count -ge 1)
{
Write-Host "$ADDomainName Domain $ADPrivGroupItem Group:" -Fore Cyan
$ADPrivGroupItemGroupMembership | Select
name,DistinguishedName,objectClass | Format-Table
IF ($KerberosDelegationObjectItem.'msDS-AllowedToActOnBehalfOfOtherIdentity')
{ $KerberosType = 'Resource-Based Constrained Delegation' }
[array]$KerberosDelegationArray += $KerberosDelegationObjectItem
}
Write-Host ""
Write-Host "$Domain Domain Accounts with Kerberos Delegation:" -Fore Cyan
$KerberosDelegationArray | Sort DelegationType | Select
DistinguishedName,DelegationType,Name,ServicePrincipalName | Format-Table -AutoSize
Write-Host ""
$KerberosDelegationReportFile = $ReportDir + "\TrimarcADChecks-
KerberosDelegationReport-$Domain-$TimeVal.csv"
$KerberosDelegationArray | Sort DelegationType | Export-CSV
$KerberosDelegationReportFile -NoTypeInformation
[array]$ForestDomainObjectPermissions += $ForestDomainObjectSecurityDataItem
}
$ForestDomainObjectPermissionFile = $ReportDir + "\TrimarcADChecks-
DomainRootPermissionReport-$Domain-$TimeVal.csv"
$ForestDomainObjectPermissions | Sort IdentityReference | Select
IdentityReference,ActiveDirectoryRights,InheritedObjectTypeName,ObjectTypeName,`
InheritanceType,ObjectFlags,AccessControlType,IsInherited,InheritanceFlags,Propagat
ionFlags,ObjectType,InheritedObjectType | `
Export-CSV $ForestDomainObjectPermissionFile -NoTypeInformation
## Duplicate SPNs
Write-Host "AD Forest Duplicate SPN Report:" -Fore Cyan
$SetSPN = SetSPN -X -F | where {$_ -notlike "Processing entry*"}
$SetSPN
$ADForestDuplicateSPNsFile = $ReportDir + "\TrimarcADChecks-
ADForestDuplicateSPNReport-$Domain-$TimeVal.txt"
$SetSPN | Out-File $ADForestDuplicateSPNsFile
#####
$EndMessageText =
@"
###################################################################################
###################################################################################
######
#
#
# Contact Trimarc to perform a full Active Directory Security Assessment which
covers these security items (& many more) and provides detailed actionable
recommendations #
#
#
#
----------------------------------------------------------
#
# | TrimarcSecurity.com |
[email protected] |
#
#
----------------------------------------------------------
#
#
#
###################################################################################
###################################################################################
######
"@
$EndMessageText
Stop-Transcript