Querying Account Lockout Policy settings

To prevent brute-force attacks on your Windows accounts, you should configure an appropriate Account Lockout Policy, which is supported in both Windows 10 and Windows 11. Changing these settings in the Group Policy Editor (gpedit.msc) is straightforward:

If you want to query these settings programmatically, you can use one of these methods:

Method 1: net.exe

C:\>%windir%\System32\net.exe Accounts
…
Lockout threshold:                                    5
Lockout duration (minutes):                           10
Lockout observation window (minutes):                 10
…
The command completed successfully.

This method does not print the Allow Administrator account lockout setting, however.

Method 2: PowerShell

The settings are stored in the [HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account] registry key, which is not easily readable. Furthermore, Windows uses a single REG_BINARY value that needs to be decoded. The Get-AccountLockoutSettings cmdlet uses reg.exe to read the contents of that key and then decodes the binary data:

function Get-AccountLockoutSettings {
    [CmdletBinding()]
    param();
    
    function Assert-ExitCode {
        [CmdletBinding()]
        param(
            [Parameter( Mandatory )]
            [scriptblock]
            $Command
        );

        & $Command | Write-Verbose;
        if( $LASTEXITCODE -ne 0 ) {
            throw "Command $Command returned exit code $LASTEXITCODE.";
        }
    }
    
    $random = [guid]::NewGuid().ToString('N');
    
    Assert-ExitCode -Command {
        & "$env:windir\System32\reg.exe" SAVE "HKLM\SAM\SAM\Domains\Account" "$env:TEMP\$random.hiv";
    };
    Assert-ExitCode -Command {
        & "$env:windir\System32\reg.exe" LOAD "HKLM\$random" "$env:TEMP\$random.hiv";
    };
    "HKEY_LOCAL_MACHINE\$random [1]" | Out-File -FilePath "$env:TEMP\$random.txt";
    Assert-ExitCode -Command {
        & "$env:windir\System32\regini.exe" "$env:TEMP\$random.txt";
    };
 
    [byte[]] $bytes = Get-ItemPropertyValue -LiteralPath "HKLM:\$random" -Name 'F';
    
    function ConvertTo-Minutes {
        [CmdletBinding()]
        param(
            [byte[]]
            $Bytes
        );
        
        $ticks = [System.BitConverter]::ToInt64( $Bytes, 0 );
        [timespan]::FromTicks( -$ticks ).TotalMinutes;
    }
    
    @{
        "Account lockout duration" = ConvertTo-Minutes -Bytes $bytes[0x30..0x37];
        "Reset account lockout counter after" = ConvertTo-Minutes -Bytes $bytes[0x38..0x3F];
        "Account lockout threshold" = [System.BitConverter]::ToUInt16( $bytes[0x54..0x55], 0 );
        "Allow Administrator account lockout" = $(
            switch( $bytes[0x4C] ) {
                0 { "Disabled"; }
                8 { "Enabled"; }
                default { throw "Unexpected value '0x{0:X2}'." -f $_; }
            }
        );
    };

    Assert-ExitCode -Command {
        & "$env:windir\System32\reg.exe" UNLOAD "HKLM\$random";
    };
    Remove-Item -LiteralPath "$env:TEMP\$random.hiv", "$env:TEMP\$random.txt" -ErrorAction 'SilentlyContinue';
}
Get-AccountLockoutSettings.ps1

You need administrative rights to run this function. The output should look like this:

PS C:\> Get-AccountLockoutSettings | Format-Table -AutoSize

Name                                Value
----                                -----
Account lockout duration            10
Allow Administrator account lockout Enabled
Reset account lockout counter after 10
Account lockout threshold           5