Emergency server help: get in touch

Kerberos RC4 Audit Script: Find RC4 Accounts and Tickets

Free PowerShell script that finds AD accounts allowing or requiring Kerberos RC4 and counts RC4 tickets issued by your DCs (events 4769/4768).

Version
1.0.0
Last updated
October 6, 2026
Language
PowerShell
Tested on
Run on 6 Oct 2026 on a Windows Server 2025 DC (build 26100.33438, Windows PowerShell 5.1) in our lab domain with a Windows 11 Pro member; syntax-checked with PowerShell 7.4.6 and PSScriptAnalyzer 1.25.
License
MIT
Pricing
Free

Short answer: run .\Get-KerberosRC4Usage.ps1 to list service accounts, computers, managed service accounts and trusts whose msDS-SupportedEncryptionTypes allows RC4, allows only RC4, or is not set. Add -Events to read events 4769 (and with -IncludeTgt 4768) on every DC and count the tickets that were actually issued with RC4 (TicketEncryptionType 0x17 or 0x18), grouped by client, service and source IP. Fix the “RC4Only” accounts and the services in the usage list before you turn RC4 off.

We ran this script on 6 October 2026 on a Windows Server 2025 Standard domain controller (build 26100.33438, September 2026 update, Windows PowerShell 5.1) and a Windows 11 Pro member PC in our lab domain contoso.com. The example output below is from that run; the lab domain is small and new, so your numbers will be bigger. It was also syntax-checked with PowerShell 7.4.6 and PSScriptAnalyzer 1.25.

What it does

Microsoft is moving Kerberos away from RC4 and has said it will change the default encryption types that domain controllers assume for accounts with no explicit setting. Before RC4 is gone from your domain you need two lists: which accounts are configured so that they still need RC4, and which clients and services are really getting RC4 tickets today. This read-only script builds both.

Part 1: account configuration

The script reads msDS-SupportedEncryptionTypes on the objects that receive Kerberos service tickets: user accounts with a servicePrincipalName (service accounts), all computer accounts, group and standalone managed service accounts, and trust objects. -AllUsers adds every user account. Each one gets a classification:

ClassificationMeaningAction
NotSetAttribute empty or 0. The KDC applies the DC’s DefaultDomainSupportedEncTypes value insteadDepends on your DC settings; set an explicit value for important service accounts
RC4OnlyRC4 (0x4) set, no AES bit (0x8 or 0x10)Fix first: these break when RC4 is disabled
RC4AndAESRC4 and at least one AES typeRemove RC4 once nothing needs it
AESOnlyAES allowed, RC4 notHidden unless you use -IncludeAesOnly
DESOnlyOnly DES bits (0x1, 0x2)Legacy; DES is disabled by default since Windows 7 and Server 2008 R2

The bit values come from Microsoft’s Kerberos protocol specification (MS-KILE): 0x1 DES-CBC-CRC, 0x2 DES-CBC-MD5, 0x4 RC4-HMAC, 0x8 AES128-CTS-HMAC-SHA1-96, 0x10 AES256-CTS-HMAC-SHA1-96. Other bits are shown as “other bits 0x…” without guessing a name. Separate columns flag any DES bit and the userAccountControl flag USE_DES_KEY_ONLY (0x200000). PasswordLastSet is included because an account whose password was last set before the domain had Windows Server 2008 or later DCs may have no AES keys at all: changing the password creates them.

Part 2: RC4 tickets actually issued

With -Events the script reads the Security log of each DC for event 4769 (“A Kerberos service ticket was requested”) where the TicketEncryptionType field is 0x17 (RC4-HMAC) or 0x18 (RC4-HMAC-EXP). -IncludeTgt adds event 4768 (TGT requests). Rows are grouped by event ID, client (TargetUserName), service (ServiceName), source IP and encryption type, with a count, first and last time seen, and the DCs that issued them. On DCs with the January 2025 or later security update the events also carry AccountAvailableKeys, ServiceAvailableKeys and ClientAdvertizedEncryptionTypes; the script copies them into the report, which tells you whether the problem is a missing AES key or a client that only offers RC4.

Requirements

  • Windows PowerShell 5.1 or PowerShell 7 on Windows, with the ActiveDirectory module (RSAT).
  • Read access to AD for Part 1 (default for domain users).
  • For -Events: “Audit Kerberos Service Ticket Operations” (and for 4768 “Audit Kerberos Authentication Service”) success auditing on the DCs; see Active Directory audit policy. Rights to read each DC’s Security log (Domain Admins or Event Log Readers) and the Remote Event Log Management firewall rules.
  • Busy DCs log a lot of 4769 events. The XPath filter is evaluated on the DC, so only RC4 events travel over the network, but keep -Hours modest on large domains.

Download and first run

  1. Copy the script from the box on this page (or use the download button) and save it as C:\Scripts\Get-KerberosRC4Usage.ps1.
  2. If you downloaded the file, remove the “downloaded from the internet” mark so the execution policy lets it run: Unblock-File C:\Scripts\Get-KerberosRC4Usage.ps1.
  3. Run it on a domain-joined machine that has the ActiveDirectory module: a domain controller, a management server, or a Windows 11 PC with RSAT (see Install RSAT on Windows 11).
  4. Read the built-in help once, then run it with no options to see the result on screen before you export anything.
cd C:\Scripts
Get-Help .\Get-KerberosRC4Usage.ps1 -Full
.\Get-KerberosRC4Usage.ps1
.\Get-KerberosRC4Usage.ps1 -Events -Hours 24

Options

ParameterWhat it doesDefault
-ServerDomain to checkCurrent domain
-SearchBaseLimit the account scan to one OUWhole domain
-AllUsersInclude every user, not only those with an SPNOff
-IncludeAesOnlyAlso output AES-only accountsOff
-EventsRead RC4 ticket events from the DCsOff
-IncludeTgtWith -Events, also read 4768Off
-HoursWith -Events, look-back window (1 to 720)24
-MaxEventsWith -Events, maximum events per DC; a warning shows if reached5000
-DomainControllerWith -Events, only these DCsAll DCs
-ExportCsvAccount CSV; with -Events a second file “<name>-events.csv”Not written
-PassThruReturn the objects (accounts, then usage rows)Off

Usage examples

# Configuration only
.\Get-KerberosRC4Usage.ps1

# Configuration plus three days of RC4 tickets, both to CSV
.\Get-KerberosRC4Usage.ps1 -Events -Hours 72 -ExportCsv C:\Reports\rc4.csv
#   -> C:\Reports\rc4.csv and C:\Reports\rc4-events.csv

# Count every account by classification, including AES-only and all users
.\Get-KerberosRC4Usage.ps1 -AllUsers -IncludeAesOnly -PassThru | Group-Object Classification

# Service accounts that will break without RC4
.\Get-KerberosRC4Usage.ps1 -PassThru | Where-Object { $_.Classification -eq 'RC4Only' }

CSV columns

The example output further down is from our lab run.

FileColumns
AccountsName, SamAccountName, Kind (User, Computer, ManagedSvcAccount, Trust), Classification, SupportedEncTypes (hex), EncTypesDecoded, DESAllowed, UseDesKeyOnly, Enabled, PasswordLastSet, SPNCount, OperatingSystem, DistinguishedName
Usage (-events)EventId, Client, Service, SourceIP, TicketEncryptionType, Count, FirstSeen, LastSeen, DomainControllers, AccountAvailableKeys, ServiceAvailableKeys, ClientAdvertizedEncryptionTypes

Fixing what it finds

  • RC4Only service account: set AES only, either with the two “This account supports Kerberos AES 128/256 bit encryption” boxes on the Account tab in Active Directory Users and Computers or with Set-ADUser svc-web -Replace @{'msDS-SupportedEncryptionTypes'=24} (24 = 0x18 = AES128 + AES256), then reset the account password so AES keys exist, then test the service. The application side may need a new keytab if it is not Windows.
  • NotSet service accounts with an old PasswordLastSet: reset the password first, then set explicit AES types.
  • Usage rows with an empty AES key list: the account or service lacks AES keys; a password reset normally fixes it.
  • Clients that advertise only RC4: old operating systems, appliances and some Java or Linux Kerberos configurations. Update or reconfigure them.

Test before you change service accounts. Changing encryption types or resetting the password of a service account can stop the service until every server using it has the new password. Do one account at a time, in a maintenance window, and note the old value from the CSV.

Example output

We gave the test service account svc-legacyapp RC4 only (msDS-SupportedEncryptionTypes = 0x4), requested a ticket for its SPN from the member PC, then ran the script with and without -Events:

Classification Count
-------------- -----
NotSet             3
RC4AndAES          2
RC4Only            1

Name       Kind     Classification SupportedEncTypes EncTypesDecoded          PasswordLastSet
----       ----     -------------- ----------------- ---------------          ---------------
Legacy App User     RC4Only        0x4               RC4-HMAC                 10/6/2026 2:17:13 PM
WINCLIENT  Computer RC4AndAES      0x1C              RC4-HMAC, AES128, AES256 10/6/2026 2:17:06 PM
WINSRV     Computer RC4AndAES      0x1C              RC4-HMAC, AES128, AES256 10/6/2026 2:09:52 PM

Count EventId Client                 Service       SourceIP     LastSeen
----- ------- ------                 -------       --------     --------
    1    4769 WINCLIENT$@CONTOSO.COM svc-legacyapp 192.168.0.14 10/6/2026 2:31:55 PM

On this September 2026 build the DC still issued an RC4 ticket because the account explicitly allows only RC4 (klist on the PC showed RSADSI RC4-HMAC(NT)). Accounts with the attribute not set did not get RC4 tickets.

Schedule it

During an RC4 clean-up, run it daily: the usage list should shrink as you fix accounts, and anything new shows up quickly. The task account needs to read the DCs’ Security logs, so add the gMSA to Event Log Readers (see our gMSA guide).

$action = New-ScheduledTaskAction -Execute 'powershell.exe' `
    -Argument '-NoProfile -ExecutionPolicy Bypass -File C:\Scripts\Get-KerberosRC4Usage.ps1 -Events -Hours 24 -ExportCsv C:\Reports\rc4.csv'
$trigger = New-ScheduledTaskTrigger -Daily -At 6am
$principal = New-ScheduledTaskPrincipal -UserId 'CONTOSO\gmsa-adreport$' -LogonType Password
Register-ScheduledTask -TaskName 'Kerberos RC4 audit' -Action $action -Trigger $trigger -Principal $principal

The file is overwritten on every run. If you need history, point the task at a small wrapper script that adds the date to the file name, or copy the file away after each run.

How it works

  1. Four LDAP queries with Get-ADObject collect user accounts with an SPN (or all users), computers, managed service accounts and trustedDomain objects, with msDS-SupportedEncryptionTypes, userAccountControl and pwdLastSet.
  2. The value is classified with bitwise tests and decoded into names.
  3. With -Events, Get-ADDomainController -Filter * lists the DCs and Get-WinEvent -FilterXPath asks each one only for 4769/4768 events in the window whose TicketEncryptionType is 0x17 or 0x18.
  4. Each event is read as XML by field name and aggregated by client, service, IP and type.

Limitations

  • The NotSet classification cannot tell you whether RC4 will be used: that depends on DefaultDomainSupportedEncTypes and the update level of your DCs. Check the usage report for the real answer.
  • Only service-ticket and TGT encryption types are checked; session key types are not used for the classification.
  • Events exist only while the Security log keeps them; on busy DCs that may be hours. Forward events to a collector for longer windows.
  • Microsoft also publishes Kerberos audit scripts (Get-KerbEncryptionUsage.ps1 and List-AccountKeys.ps1) in its Kerberos-Crypto GitHub repository, referenced from the RC4 guidance linked below; they are worth running alongside this report.
  • Not yet run against a live domain (see the note at the top).

Official documentation: Detect and remediate RC4 usage in Kerberos · Event 4769: a Kerberos service ticket was requested · MS-KILE 2.2.7: supported encryption types bit flags · Event 4768: a Kerberos TGT was requested

Related: Disable NTLM Active Directory-Wide: 5 Safe Audit and Block Steps · Active Directory Audit Policy: DC Settings and 35 Key Event IDs · Group Managed Service Accounts (gMSA): Complete Windows Server 2025 Guide · Raise AD Functional Level Safely: Forest and Domain

See also: Reset krbtgt Password Safely: Two Resets, Replication and RODCs · Kerberos RC4 Removal: Find and Fix RC4 Accounts (2026) · BadSuccessor dMSA on Server 2025: Audit OU Rights and Patch

The script

Get-KerberosRC4Usage.ps1Download
# Kerberos RC4 Audit Script: Find RC4 Accounts and Tickets (v1.0.0) - from srvScripts.com
# Source, docs and updates: https://srvscripts.com/scripts/kerberos-rc4-audit/
# Copyright (c) 2026 srvScripts.com. MIT licence: if you copy, share or adapt this script, keep this notice and credit srvScripts.com.
<#
.SYNOPSIS
    Find AD accounts that still allow (or only allow) Kerberos RC4, and optionally the RC4 tickets your DCs
    actually issued (events 4768/4769 with encryption type 0x17).

.DESCRIPTION
    Read-only.
    Part 1 - configuration. Reads msDS-SupportedEncryptionTypes on the accounts that matter for Kerberos
    service tickets: user and managed service accounts with a servicePrincipalName, computer accounts, and
    trust objects (trustedDomain). Use -AllUsers to include every user account. Each account is classified:
      NotSet     attribute empty or 0: the KDC uses the DefaultDomainSupportedEncTypes value of the DC,
                 so the result depends on your DCs' configuration and update level
      RC4Only    RC4 (0x4) allowed and no AES bit (0x8, 0x10)
      RC4AndAES  RC4 and at least one AES type allowed
      AESOnly    AES allowed, RC4 not allowed
      DESOnly    only DES bits (0x1, 0x2) set
    A separate DESAllowed column is True whenever a DES bit is set (DES is disabled by default since
    Windows 7 / Server 2008 R2), for example the common value 0x1F (DES, RC4, AES128, AES256).
    It also flags userAccountControl USE_DES_KEY_ONLY (0x200000) and shows when the password was last set:
    an account whose password has not changed since the domain first ran Windows Server 2008 domain
    controllers may have no AES keys at all.

    Part 2 - usage (-Events). Reads the Security log of each DC for 4769 (service ticket) and, with
    -IncludeTgt, 4768 (TGT) events whose TicketEncryptionType is 0x17 (RC4-HMAC) or 0x18 (RC4-HMAC-EXP),
    and groups them by client, service and source IP. On DCs with the January 2025 or later security update
    the events also carry AccountAvailableKeys / ServiceAvailableKeys, which the report includes.
    Requires "Audit Kerberos Service Ticket Operations" (and for 4768 "Audit Kerberos Authentication
    Service") success auditing on the DCs.

.PARAMETER Server
    Domain to check (default: current domain).

.PARAMETER SearchBase
    Limit the account scan to this OU (DN).

.PARAMETER AllUsers
    Include all user accounts, not only those with a servicePrincipalName.

.PARAMETER IncludeAesOnly
    Also output accounts classified AESOnly (default: only accounts that need attention).

.PARAMETER Events
    Also read RC4 ticket events from the domain controllers.

.PARAMETER IncludeTgt
    With -Events, also read 4768 (TGT) events, not only 4769.

.PARAMETER Hours
    With -Events, how far back to read (default 24, maximum 720).

.PARAMETER MaxEvents
    With -Events, maximum events read per DC (default 5000).

.PARAMETER DomainController
    With -Events, read only these DCs.

.PARAMETER ExportCsv
    Write the account report to this CSV file. With -Events the usage report is written next to it with
    "-events" added to the file name.

.PARAMETER PassThru
    Output objects (accounts, then usage rows) to the pipeline.

.EXAMPLE
    .\Get-KerberosRC4Usage.ps1

.EXAMPLE
    .\Get-KerberosRC4Usage.ps1 -Events -Hours 72 -ExportCsv C:\Reports\rc4.csv

.EXAMPLE
    .\Get-KerberosRC4Usage.ps1 -AllUsers -IncludeAesOnly -PassThru | Group-Object Classification

.NOTES
    Name:     Get-KerberosRC4Usage.ps1
    Version:  1.0.0
    Source:   https://srvscripts.com/scripts/kerberos-rc4-audit/
    License:  MIT
    Requires: Windows PowerShell 5.1 or PowerShell 7 on Windows, ActiveDirectory module (RSAT); for -Events,
              rights to read the DC Security logs (Domain Admins or Event Log Readers) and the Remote Event Log
              Management firewall rules on the DCs.
    Microsoft also publishes Kerberos audit scripts (Get-KerbEncryptionUsage.ps1, List-AccountKeys.ps1) in
    its Kerberos-Crypto GitHub repository; see https://learn.microsoft.com/windows-server/security/kerberos/detect-remediate-rc4-kerberos
#>
[CmdletBinding()]
param(
    [ValidateNotNullOrEmpty()]
    [string]$Server,

    [ValidateNotNullOrEmpty()]
    [string]$SearchBase,

    [switch]$AllUsers,

    [switch]$IncludeAesOnly,

    [switch]$Events,

    [switch]$IncludeTgt,

    [ValidateRange(1, 720)]
    [int]$Hours = 24,

    [ValidateRange(1, 1000000)]
    [int]$MaxEvents = 5000,

    [ValidateNotNullOrEmpty()]
    [string[]]$DomainController,

    [ValidateNotNullOrEmpty()]
    [string]$ExportCsv,

    [switch]$PassThru
)

Set-StrictMode -Version 2
$ErrorActionPreference = 'Stop'

if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) {
    throw "The ActiveDirectory module is not installed. Install RSAT: Active Directory Domain Services tools, then run again."
}
Import-Module ActiveDirectory -Verbose:$false

function ConvertFrom-FileTimeValue {
    param($Value)
    if ($null -eq $Value) { return $null }
    $v = [int64]$Value
    if ($v -le 0 -or $v -eq [int64]::MaxValue) { return $null }
    [DateTime]::FromFileTime($v)
}

function Get-AttributeValue {
    param($Entity, [string]$Name)
    if ($Entity.PropertyNames -contains $Name) { return $Entity[$Name].Value }
    $null
}

function Get-EncTypeName {
    param([int64]$Value)
    $n = @()
    if ($Value -band 0x1)  { $n += 'DES-CBC-CRC' }
    if ($Value -band 0x2)  { $n += 'DES-CBC-MD5' }
    if ($Value -band 0x4)  { $n += 'RC4-HMAC' }
    if ($Value -band 0x8)  { $n += 'AES128' }
    if ($Value -band 0x10) { $n += 'AES256' }
    if ($Value -band -bnot 0x1F) { $n += ('other bits 0x{0:X}' -f ($Value -band -bnot 0x1F)) }
    $n -join ', '
}

function Get-EncClassification {
    param($Value)
    if ($null -eq $Value -or [int64]$Value -eq 0) { return 'NotSet' }
    $v = [int64]$Value
    $rc4 = [bool]($v -band 0x4)
    $aes = [bool]($v -band 0x18)
    $des = [bool]($v -band 0x3)
    if ($rc4 -and -not $aes) { return 'RC4Only' }
    if ($rc4 -and $aes) { return 'RC4AndAES' }
    if ($aes) { return 'AESOnly' }
    if ($des) { return 'DESOnly' }
    'NoKerberosEtype'
}

$domArgs = @{}
if ($Server) { $domArgs.Server = $Server }
$domain = Get-ADDomain @domArgs
$srv = $domain.DNSRoot

# ---- Part 1: account configuration ----------------------------------------------------------------------
$attrs = 'msDS-SupportedEncryptionTypes', 'userAccountControl', 'pwdLastSet', 'servicePrincipalName', 'sAMAccountName', 'objectClass', 'name', 'operatingSystem'
$userFilter = if ($AllUsers) { '(&(objectCategory=person)(objectClass=user))' } else { '(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))' }
$filters = [ordered]@{
    'User'              = $userFilter
    'Computer'          = '(objectCategory=computer)'
    'ManagedSvcAccount' = '(|(objectClass=msDS-GroupManagedServiceAccount)(objectClass=msDS-ManagedServiceAccount))'
    'Trust'             = '(objectClass=trustedDomain)'
}
$q = @{ Server = $srv; Properties = $attrs; ResultPageSize = 500 }
if ($SearchBase) { $q.SearchBase = $SearchBase }

$accounts = [System.Collections.Generic.List[object]]::new()
$seen = @{}
foreach ($kind in $filters.Keys) {
    Write-Verbose "Scanning $kind objects"
    $objs = @(Get-ADObject -LDAPFilter $filters[$kind] @q)
    foreach ($o in $objs) {
        if ($seen.ContainsKey($o.DistinguishedName)) { continue }
        $seen[$o.DistinguishedName] = $true
        $et = Get-AttributeValue $o 'msDS-SupportedEncryptionTypes'
        $uac = Get-AttributeValue $o 'userAccountControl'
        $cls = Get-EncClassification $et
        $desOnly = ($null -ne $uac -and ([int]$uac -band 0x200000))
        $desAllowed = ($null -ne $et -and ([int64]$et -band 0x3))
        if ($cls -eq 'AESOnly' -and -not $desOnly -and -not $desAllowed -and -not $IncludeAesOnly) { continue }
        $spn = @(Get-AttributeValue $o 'servicePrincipalName' | Where-Object { $_ })
        $etText = 'Not set'
        $etHex = ''
        if ($null -ne $et -and [int64]$et -ne 0) { $etText = Get-EncTypeName ([int64]$et); $etHex = '0x{0:X}' -f [int64]$et }
        $accounts.Add([pscustomobject]@{
            Name                 = [string](Get-AttributeValue $o 'name')
            SamAccountName       = [string](Get-AttributeValue $o 'sAMAccountName')
            Kind                 = $kind
            Classification       = $cls
            SupportedEncTypes    = $etHex
            EncTypesDecoded      = $etText
            DESAllowed           = [bool]$desAllowed
            UseDesKeyOnly        = [bool]$desOnly
            Enabled              = if ($null -ne $uac) { -not ([int]$uac -band 2) } else { $null }
            PasswordLastSet      = ConvertFrom-FileTimeValue (Get-AttributeValue $o 'pwdLastSet')
            SPNCount             = $spn.Count
            OperatingSystem      = [string](Get-AttributeValue $o 'operatingSystem')
            DistinguishedName    = $o.DistinguishedName
        })
    }
}
$accountRows = @($accounts | Sort-Object @{ Expression = { switch ($_.Classification) { 'RC4Only' { 0 } 'DESOnly' { 1 } 'RC4AndAES' { 2 } 'NotSet' { 3 } default { 4 } } } }, Kind, Name)

# ---- Part 2: RC4 tickets issued -------------------------------------------------------------------------
$usageRows = @()
if ($Events) {
    $dcs = @(Get-ADDomainController -Filter * -Server $srv | ForEach-Object { $_.HostName })
    if ($DomainController) { $dcs = @($dcs | Where-Object { $DomainController -contains $_ }) }
    $ms = [int64]$Hours * 3600 * 1000
    $ids = if ($IncludeTgt) { '(EventID=4769 or EventID=4768)' } else { 'EventID=4769' }
    $xpath = "*[System[$ids and TimeCreated[timediff(@SystemTime) <= $ms]]] and " +
             "*[EventData[Data[@Name='TicketEncryptionType']='0x17' or Data[@Name='TicketEncryptionType']='0x18']]"
    $agg = @{}
    foreach ($dc in $dcs) {
        Write-Verbose "Reading RC4 ticket events on $dc"
        $evs = @()
        try {
            $evs = @(Get-WinEvent -ComputerName $dc -LogName Security -FilterXPath $xpath -MaxEvents $MaxEvents)
        } catch {
            if ($_.FullyQualifiedErrorId -match 'NoMatchingEventsFound' -or $_.Exception.Message -match 'No events were found') { continue }
            Write-Warning "Cannot read the Security log on ${dc}: $($_.Exception.Message)"
            continue
        }
        if ($evs.Count -ge $MaxEvents) { Write-Warning "$dc returned $MaxEvents events (the -MaxEvents limit); counts for this DC are incomplete." }
        foreach ($e in $evs) {
            $d = @{}
            foreach ($n in ([xml]$e.ToXml()).Event.EventData.Data) { $d[$n.Name] = [string]$n.InnerText }
            $ip = ([string]$d['IpAddress']) -replace '^::ffff:', ''
            $key = '{0}|{1}|{2}|{3}|{4}' -f $e.Id, $d['TargetUserName'], $d['ServiceName'], $ip, $d['TicketEncryptionType']
            if (-not $agg.ContainsKey($key)) {
                $agg[$key] = [pscustomobject]@{
                    EventId              = $e.Id
                    Client               = [string]$d['TargetUserName']
                    Service              = [string]$d['ServiceName']
                    SourceIP             = $ip
                    TicketEncryptionType = [string]$d['TicketEncryptionType']
                    Count                = 0
                    FirstSeen            = $e.TimeCreated
                    LastSeen             = $e.TimeCreated
                    DomainControllers    = ''
                    AccountAvailableKeys = [string]$d['AccountAvailableKeys']
                    ServiceAvailableKeys = [string]$d['ServiceAvailableKeys']
                    ClientAdvertizedEncryptionTypes = [string]$d['ClientAdvertizedEncryptionTypes']
                }
            }
            $a = $agg[$key]
            $a.Count++
            if ($e.TimeCreated -lt $a.FirstSeen) { $a.FirstSeen = $e.TimeCreated }
            if ($e.TimeCreated -gt $a.LastSeen) { $a.LastSeen = $e.TimeCreated }
            if (($a.DomainControllers -split '; ') -notcontains $dc) { $a.DomainControllers = (@($a.DomainControllers -split '; ' | Where-Object { $_ }) + $dc) -join '; ' }
        }
    }
    $usageRows = @($agg.Values | Sort-Object Count -Descending)
}

# ---- Output ---------------------------------------------------------------------------------------------
if ($ExportCsv) {
    $accountRows | Export-Csv -LiteralPath $ExportCsv -NoTypeInformation -Encoding UTF8
    Write-Information ("{0} account(s) written to {1}" -f $accountRows.Count, $ExportCsv) -InformationAction Continue
    if ($Events) {
        $evFile = [System.IO.Path]::ChangeExtension($ExportCsv, $null).TrimEnd('.') + '-events.csv'
        $usageRows | Export-Csv -LiteralPath $evFile -NoTypeInformation -Encoding UTF8
        Write-Information ("{0} RC4 usage row(s) written to {1}" -f $usageRows.Count, $evFile) -InformationAction Continue
    }
}
if ($PassThru) { $accountRows; $usageRows; return }

$accountRows | Group-Object Classification | Sort-Object Name | Format-Table @{ n = 'Classification'; e = { $_.Name } }, Count -AutoSize
$accountRows | Where-Object { $_.Classification -in 'RC4Only', 'DESOnly', 'RC4AndAES' -or $_.DESAllowed -or $_.UseDesKeyOnly } |
    Format-Table Name, Kind, Classification, SupportedEncTypes, EncTypesDecoded, PasswordLastSet -AutoSize
if ($Events) {
    if ($usageRows.Count) {
        $usageRows | Select-Object -First 50 | Format-Table Count, EventId, Client, Service, SourceIP, LastSeen -AutoSize
    } else {
        Write-Information "No RC4 (0x17/0x18) ticket events found in the last $Hours hour(s) on: $($dcs -join ', ')" -InformationAction Continue
    }
}
Version 1.0.0 · SHA-256 81b45767c36dfb6e12f73c18143b025b460fd7609cff2c2f682f1ea873017e83
Download and verify on Linux or macOS
curl -fsSL -o Get-KerberosRC4Usage.ps1 https://scr.srvscripts.com/kerberos-rc4-audit/Get-KerberosRC4Usage.ps1 && curl -fsSL https://scr.srvscripts.com/kerberos-rc4-audit/Get-KerberosRC4Usage.ps1.sha256 | sha256sum -c
Download and verify in Windows PowerShell
Invoke-WebRequest -Uri 'https://scr.srvscripts.com/kerberos-rc4-audit/Get-KerberosRC4Usage.ps1' -OutFile 'Get-KerberosRC4Usage.ps1'; if ((Get-FileHash 'Get-KerberosRC4Usage.ps1' -Algorithm SHA256).Hash -eq '81B45767C36DFB6E12F73C18143B025B460FD7609CFF2C2F682F1EA873017E83') { 'OK: the file is intact' } else { 'MISMATCH: do not run this file' }
Copy the whole line. In Windows PowerShell, curl and sha256sum are not the Linux tools, so use the PowerShell line there.
Also on GitHub: github.com/srvscripts/scripts

Frequently asked questions

How do I find accounts that use RC4 for Kerberos?

Check msDS-SupportedEncryptionTypes on service accounts, computers and trusts (value 0x4 alone means RC4 only), and look for events 4769 with TicketEncryptionType 0x17 on your DCs. This script does both.

What does TicketEncryptionType 0x17 mean?

RC4-HMAC. 0x11 and 0x12 are AES128 and AES256, and 0x18 is RC4-HMAC-EXP.

What happens if msDS-SupportedEncryptionTypes is not set?

The KDC uses the DefaultDomainSupportedEncTypes value configured on the domain controller instead, so the result depends on your DC settings and updates.

Why does an account have no AES keys?

AES keys are created when the password is set on a domain controller that supports AES. An account whose password has not changed since before Windows Server 2008 DCs may only have RC4 keys. Reset the password.

How do I set a service account to AES only?

Tick the two Kerberos AES boxes on the Account tab in Active Directory Users and Computers, or set msDS-SupportedEncryptionTypes to 24 (AES128 plus AES256) with Set-ADUser -Replace. Then reset the password and test the service in a maintenance window.

Does the script change encryption settings?

No. It only reads AD and the Security logs.

Changelog

  • 1.0.0 — First release.

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.