functions/Get-AhsPrivilegedPrincipal.ps1
function Get-AhsPrivilegedPrincipal { <# .SYNOPSIS Retrieves all privileged accounts in a domain. .DESCRIPTION Retrieves all privileged accounts in a domain. Includes nested group memberships and non-user principals. Note: This scan is ONLY scanning for membership in privileged groups. If you want to ensure no other escalation path exists, use a tool such as the Active Directory Management Framework (admf.one) to scan for unexpected delegations. List of privileged groups taken from the Protected Accounts and Groups: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory .PARAMETER Name Name filter applied to the returned principals. Defaults to: * .PARAMETER Group Name of privileged group to consider for the result. Defaults to: * .PARAMETER ExcludeBuiltIn By default, the krbtgt and Administrator account are returned, irrespective of any other filtering. This disables that behavior. .PARAMETER IncludeGroups Include groups in the list of members of privileged groups. By default, groups that are members of a privileged groups are not returned, just its non-group members (recursively). .PARAMETER Server The server / domain to contact. .PARAMETER Credential The credentials to use with the request .EXAMPLE PS C:\> Get-AhsPrivilegedPrincipal Retrieves all privileged accounts in the current domain. .LINK https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory #> [CmdletBinding()] param ( [string] $Name = '*', [string] $Group = '*', [switch] $ExcludeBuiltIn, [switch] $IncludeGroups, [string] $Server, [PSCredential] $Credential ) begin { $privilegedGroupRids = @( '498' # Enterprise Read-only Domain Controllers '512' # Domain Admins '516' # Domain Controllers '518' # Schema Admins '519' # Enterprise Admins '521' # Read-only DOmain Controllers ) $privilegedBuiltinGroups = @( 'S-1-5-32-544' # Administrators 'S-1-5-32-548' # Account Operators 'S-1-5-32-549' # Server Operators 'S-1-5-32-550' # Print Operators 'S-1-5-32-551' # Backup Operators 'S-1-5-32-552' # Replicator ) $privilegedAccountRids = @( '500' # Administrator '502' # krbtgt ) $adParam = @{} if ($Server) { $adParam.Server = $Server } if ($Credential) { $adParam.Credential = $Credential } } process { $domain = Get-LdapObject @adParam -LdapFilter '(objectCategory=domainDNS)' #region Builtin Privileged Accounts if (-not $ExcludeBuiltIn) { foreach ($rid in $privilegedAccountRids) { $user = Get-LdapObject @adParam -LdapFilter "(objectSID=$($domain.ObjectSID)-$rid)" -Property SamAccountName, ObjectClass, ObjectSID, DistinguishedName if ($user.Name -notlike $Name) { continue } [PSCustomObject]@{ PSTypeName = 'ADObjectHealthScan.Privileged.GroupMember' GroupName = 'n/a' GroupDN = $null GroupSID = $null MemberName = $user.SamAccountName MemberType = $user.ObjectClass MemberSID = $user.ObjectSID MemberDN = $user.DistinguishedName } } } #endregion Builtin Privileged Accounts #region Resolve Groups to check $groupsDefault = foreach ($rid in $privilegedGroupRids) { Get-LdapObject @adParam -LdapFilter "(objectSID=$($domain.ObjectSID)-$rid)" -Property SamAccountName, DistinguishedName, ObjectSID -ErrorAction Stop } $groupsBuiltin = foreach ($sid in $privilegedBuiltinGroups) { Get-LdapObject @adParam -LdapFilter "(objectSID=$sid)" -Property SamAccountName, DistinguishedName, ObjectSID -ErrorAction Stop } $relevantGroups = @($groupsDefault) + @($groupsBuiltin) | Write-Output | Where-Object { $_ -and $_.SamAccountName -like $Group } #endregion Resolve Groups to check #region Resolve privileged entities foreach ($relevantGroup in $relevantGroups) { $members = Get-LdapObject @adParam -LDAPFilter "(&(objectSID=*)(memberof:1.2.840.113556.1.4.1941:=$($relevantGroup.DistinguishedName)))" -Properties ObjectSID, SamAccountName, ObjectClass, DistinguishedName foreach ($member in $members) { if ($member.SamAccountName -notlike $Name) { continue } if ($member.ObjectClass -eq 'Group' -and -not $IncludeGroups) { continue } [PSCustomObject]@{ PSTypeName = 'ADObjectHealthScan.Privileged.GroupMember' GroupName = $relevantGroup.SamAccountName GroupDN = $relevantGroup.DistinguishedName GroupSID = $relevantGroup.ObjectSID MemberName = $member.SamAccountName MemberType = $member.ObjectClass MemberSID = $member.ObjectSID MemberDN = $member.DistinguishedName } } } #endregion Resolve privileged entitie } } |