Skip to main content
COSMICBYTEZLABS
NewsSecurityHOWTOsToolsStudyTraining
ProjectsChecklistsAI RankingsNewsletterStatusTagsAbout
Subscribe

Press Enter to search or Esc to close

News
Security
HOWTOs
Tools
Study
Training
Projects
Checklists
AI Rankings
Newsletter
Status
Tags
About
RSS Feed
Reading List
Subscribe

Stay in the Loop

Get the latest security alerts, tutorials, and tech insights delivered to your inbox.

Subscribe NowFree forever. No spam.
COSMICBYTEZLABS

Your trusted source for IT intelligence, cybersecurity insights, and hands-on technical guides.

429+ Articles
114+ Guides

CONTENT

  • Latest News
  • Security Alerts
  • HOWTOs
  • Projects
  • Exam Prep

RESOURCES

  • Search
  • Browse Tags
  • Newsletter Archive
  • Reading List
  • RSS Feed

COMPANY

  • About Us
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CosmicBytez Labs. All rights reserved.

System Status: Operational
  1. Home
  2. HOWTOs
  3. Windows Security Baseline Audit: CIS Benchmark Compliance
Windows Security Baseline Audit: CIS Benchmark Compliance
HOWTOIntermediate

Windows Security Baseline Audit: CIS Benchmark Compliance

Automate Windows security baseline checks using PowerShell. Validate configurations against CIS benchmarks for password policies, audit settings, and...

Security Team

Security Engineering

January 25, 2026
9 min read

Prerequisites

  • Windows Server or Windows 10/11
  • Administrator privileges
  • PowerShell 5.1+

Overview

Validating Windows systems against security baselines like CIS Benchmarks ensures consistent security posture across your environment. This guide shows how to automate compliance checks using PowerShell.

Who Should Use This Guide

  • System administrators managing Windows infrastructure
  • Security engineers auditing compliance
  • IT teams implementing security baselines
  • Compliance officers validating configurations

Why Security Baselines

BenefitDescription
ComplianceMeet regulatory requirements (PCI-DSS, HIPAA, SOC 2)
ConsistencyEnsure all systems meet minimum security standards
Risk ReductionIdentify misconfigurations before attackers do
Audit TrailDocument security posture for stakeholders

Requirements

System Requirements

ComponentRequirement
Operating SystemWindows 10/11 or Windows Server 2016+
PowerShellVersion 5.1 or later
PrivilegesAdministrator/elevated access

CIS Benchmark Categories

CategoryExamples
Account PoliciesPassword length, complexity, lockout
Local PoliciesAudit settings, user rights assignments
Security OptionsUAC, network security, interactive logon
Windows FirewallProfile settings, rules
Advanced AuditDetailed audit policy configuration

Process

Step 1: Check Password Policy

Validate password requirements against CIS benchmarks.

PowerShell Script:

function Test-PasswordPolicy {
    Write-Host "`n=== Password Policy Compliance ===" -ForegroundColor Cyan
 
    $secpol = secedit /export /cfg "$env:TEMP\secpol.cfg" /quiet
    $content = Get-Content "$env:TEMP\secpol.cfg"
 
    $results = @()
 
    # Minimum password length (CIS: 14+ characters)
    $minLength = ($content | Select-String "MinimumPasswordLength").ToString().Split('=')[1].Trim()
    $results += [PSCustomObject]@{
        Check = "Minimum Password Length"
        Current = $minLength
        Required = "14"
        Status = if ([int]$minLength -ge 14) { "PASS" } else { "FAIL" }
    }
 
    # Password complexity
    $complexity = ($content | Select-String "PasswordComplexity").ToString().Split('=')[1].Trim()
    $results += [PSCustomObject]@{
        Check = "Password Complexity"
        Current = if ($complexity -eq "1") { "Enabled" } else { "Disabled" }
        Required = "Enabled"
        Status = if ($complexity -eq "1") { "PASS" } else { "FAIL" }
    }
 
    # Maximum password age (CIS: 365 days or less)
    $maxAge = ($content | Select-String "MaximumPasswordAge").ToString().Split('=')[1].Trim()
    $results += [PSCustomObject]@{
        Check = "Maximum Password Age"
        Current = "$maxAge days"
        Required = "365 days or less"
        Status = if ([int]$maxAge -le 365 -and [int]$maxAge -gt 0) { "PASS" } else { "FAIL" }
    }
 
    # Password history (CIS: 24 passwords)
    $history = ($content | Select-String "PasswordHistorySize").ToString().Split('=')[1].Trim()
    $results += [PSCustomObject]@{
        Check = "Password History"
        Current = "$history passwords"
        Required = "24 passwords"
        Status = if ([int]$history -ge 24) { "PASS" } else { "FAIL" }
    }
 
    Remove-Item "$env:TEMP\secpol.cfg" -Force
 
    $results | Format-Table -AutoSize
    return $results
}

Verification:

Test-PasswordPolicy

Expected Output: Table showing each check with PASS/FAIL status.


Step 2: Check Account Lockout Policy

Validate lockout settings prevent brute force attacks.

PowerShell Script:

function Test-LockoutPolicy {
    Write-Host "`n=== Account Lockout Policy ===" -ForegroundColor Cyan
 
    $lockoutInfo = net accounts
    $results = @()
 
    # Lockout threshold (CIS: 5 or fewer)
    $threshold = ($lockoutInfo | Select-String "Lockout threshold").ToString().Split(':')[1].Trim()
    $results += [PSCustomObject]@{
        Check = "Account Lockout Threshold"
        Current = $threshold
        Required = "5 or fewer attempts"
        Status = if ($threshold -ne "Never" -and [int]$threshold -le 5) { "PASS" } else { "FAIL" }
    }
 
    # Lockout duration (CIS: 15+ minutes)
    $duration = ($lockoutInfo | Select-String "Lockout duration").ToString().Split(':')[1].Trim()
    $results += [PSCustomObject]@{
        Check = "Lockout Duration"
        Current = $duration
        Required = "15+ minutes"
        Status = if ($duration -ne "Never" -and [int]($duration -replace '\D','') -ge 15) { "PASS" } else { "FAIL" }
    }
 
    $results | Format-Table -AutoSize
    return $results
}

Step 3: Check Audit Policy

Verify security auditing is properly configured.

PowerShell Script:

function Test-AuditPolicy {
    Write-Host "`n=== Audit Policy Compliance ===" -ForegroundColor Cyan
 
    $auditPolicy = auditpol /get /category:* | Out-String
    $results = @()
 
    # Required audit settings
    $requiredAudits = @{
        "Credential Validation" = "Success and Failure"
        "Security Group Management" = "Success"
        "User Account Management" = "Success and Failure"
        "Logon" = "Success and Failure"
        "Special Logon" = "Success"
        "Audit Policy Change" = "Success"
        "Sensitive Privilege Use" = "Success and Failure"
    }
 
    foreach ($audit in $requiredAudits.GetEnumerator()) {
        $pattern = "$($audit.Key)\s+(\S+.*)"
        if ($auditPolicy -match $pattern) {
            $currentSetting = $Matches[1].Trim()
            $required = $audit.Value
 
            $status = "FAIL"
            if ($required -eq "Success and Failure" -and $currentSetting -match "Success and Failure") {
                $status = "PASS"
            } elseif ($required -eq "Success" -and $currentSetting -match "Success") {
                $status = "PASS"
            }
 
            $results += [PSCustomObject]@{
                Check = $audit.Key
                Current = $currentSetting
                Required = $required
                Status = $status
            }
        }
    }
 
    $results | Format-Table -AutoSize
    return $results
}

Step 4: Check Security Options

Validate critical security settings in the registry.

PowerShell Script:

function Test-SecurityOptions {
    Write-Host "`n=== Security Options ===" -ForegroundColor Cyan
 
    $results = @()
 
    # UAC: Admin Approval Mode
    $uacAdmin = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableLUA" -ErrorAction SilentlyContinue).EnableLUA
    $results += [PSCustomObject]@{
        Check = "UAC: Admin Approval Mode"
        Current = if ($uacAdmin -eq 1) { "Enabled" } else { "Disabled" }
        Required = "Enabled"
        Status = if ($uacAdmin -eq 1) { "PASS" } else { "FAIL" }
    }
 
    # LAN Manager authentication level
    $lmLevel = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "LmCompatibilityLevel" -ErrorAction SilentlyContinue).LmCompatibilityLevel
    $results += [PSCustomObject]@{
        Check = "LAN Manager Auth Level"
        Current = switch ($lmLevel) {
            0 {"LM & NTLM"} 1 {"LM & NTLM + NTLMv2"} 2 {"NTLM only"}
            3 {"NTLMv2 only"} 4 {"NTLMv2, refuse LM"} 5 {"NTLMv2, refuse LM & NTLM"}
            default {"Unknown"}
        }
        Required = "NTLMv2 only (5)"
        Status = if ($lmLevel -ge 5) { "PASS" } else { "FAIL" }
    }
 
    # SMB signing
    $smbSigning = (Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" -Name "RequireSecuritySignature" -ErrorAction SilentlyContinue).RequireSecuritySignature
    $results += [PSCustomObject]@{
        Check = "SMB Server Signing Required"
        Current = if ($smbSigning -eq 1) { "Required" } else { "Not Required" }
        Required = "Required"
        Status = if ($smbSigning -eq 1) { "PASS" } else { "FAIL" }
    }
 
    $results | Format-Table -AutoSize
    return $results
}

Step 5: Check Windows Firewall

Verify firewall is enabled with proper defaults.

PowerShell Script:

function Test-FirewallStatus {
    Write-Host "`n=== Windows Firewall Status ===" -ForegroundColor Cyan
 
    $results = @()
    $profiles = @("Domain", "Private", "Public")
 
    foreach ($profile in $profiles) {
        $fw = Get-NetFirewallProfile -Name $profile
 
        $results += [PSCustomObject]@{
            Profile = $profile
            Enabled = $fw.Enabled
            InboundDefault = $fw.DefaultInboundAction
            OutboundDefault = $fw.DefaultOutboundAction
            Status = if ($fw.Enabled -and $fw.DefaultInboundAction -eq "Block") { "PASS" } else { "FAIL" }
        }
    }
 
    $results | Format-Table -AutoSize
    return $results
}

Step 6: Check Windows Defender

Verify antivirus protection is active.

PowerShell Script:

function Test-DefenderStatus {
    Write-Host "`n=== Windows Defender Status ===" -ForegroundColor Cyan
 
    $results = @()
 
    try {
        $defender = Get-MpComputerStatus
 
        $results += [PSCustomObject]@{
            Check = "Real-Time Protection"
            Current = if ($defender.RealTimeProtectionEnabled) { "Enabled" } else { "Disabled" }
            Required = "Enabled"
            Status = if ($defender.RealTimeProtectionEnabled) { "PASS" } else { "FAIL" }
        }
 
        $results += [PSCustomObject]@{
            Check = "Tamper Protection"
            Current = if ($defender.IsTamperProtected) { "Enabled" } else { "Disabled" }
            Required = "Enabled"
            Status = if ($defender.IsTamperProtected) { "PASS" } else { "FAIL" }
        }
 
        # Signature age
        $sigAge = (Get-Date) - $defender.AntivirusSignatureLastUpdated
        $results += [PSCustomObject]@{
            Check = "Signature Age"
            Current = "$([math]::Round($sigAge.TotalDays, 1)) days"
            Required = "7 days or less"
            Status = if ($sigAge.TotalDays -le 7) { "PASS" } else { "FAIL" }
        }
    }
    catch {
        $results += [PSCustomObject]@{
            Check = "Windows Defender"
            Current = "Not Available"
            Required = "Installed and Running"
            Status = "FAIL"
        }
    }
 
    $results | Format-Table -AutoSize
    return $results
}

Step 7: Run Complete Audit

Execute all checks and generate summary report.

Complete Audit Script:

function Invoke-SecurityBaselineAudit {
    Write-Host "========================================" -ForegroundColor Cyan
    Write-Host "  Windows Security Baseline Audit" -ForegroundColor Cyan
    Write-Host "  Computer: $env:COMPUTERNAME" -ForegroundColor Cyan
    Write-Host "  Date: $(Get-Date)" -ForegroundColor Cyan
    Write-Host "========================================" -ForegroundColor Cyan
 
    $allResults = @()
 
    # Run all checks
    $allResults += Test-PasswordPolicy
    $allResults += Test-LockoutPolicy
    $allResults += Test-AuditPolicy
    $allResults += Test-SecurityOptions
    $allResults += Test-FirewallStatus
    $allResults += Test-DefenderStatus
 
    # Summary
    Write-Host "`n========================================" -ForegroundColor Cyan
    Write-Host "  AUDIT SUMMARY" -ForegroundColor Cyan
    Write-Host "========================================" -ForegroundColor Cyan
 
    $passed = ($allResults | Where-Object { $_.Status -eq "PASS" }).Count
    $failed = ($allResults | Where-Object { $_.Status -eq "FAIL" }).Count
    $total = $allResults.Count
 
    Write-Host "Total Checks: $total"
    Write-Host "Passed: $passed" -ForegroundColor Green
    Write-Host "Failed: $failed" -ForegroundColor Red
 
    $compliance = [math]::Round(($passed / $total) * 100, 1)
    Write-Host "`nCompliance Score: $compliance%" -ForegroundColor $(
        if ($compliance -ge 90) { 'Green' }
        elseif ($compliance -ge 70) { 'Yellow' }
        else { 'Red' }
    )
 
    return $allResults
}
 
# Run the audit
$results = Invoke-SecurityBaselineAudit

Remediation Commands

Fix common failures with these commands:

Password Policy:

# Set minimum password length to 14
net accounts /minpwlen:14
 
# Set account lockout threshold
net accounts /lockoutthreshold:5
 
# Set lockout duration
net accounts /lockoutduration:30

Audit Policy:

# Enable required audit policies
auditpol /set /category:"Account Logon" /success:enable /failure:enable
auditpol /set /category:"Logon/Logoff" /success:enable /failure:enable
auditpol /set /category:"Account Management" /success:enable /failure:enable

Security Options:

# Enable SMB signing
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" -Name "RequireSecuritySignature" -Value 1
 
# Set LAN Manager authentication level to NTLMv2 only
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "LmCompatibilityLevel" -Value 5

Troubleshooting

SymptomPossible CauseSolution
Access deniedNot running as adminRun PowerShell elevated
secedit failsPolicy corruptionRun secedit /configure /cfg defltbase.inf /db defltbase.sdb /verbose
Audit policy unchangedGroup Policy overrideCheck GPO settings
Registry key not foundDifferent Windows versionVerify path for your OS version

Verification Checklist

Account Policies

  • Password minimum length ≥ 14
  • Password complexity enabled
  • Account lockout configured

Audit Policies

  • Logon events audited
  • Account management audited
  • Privilege use audited

Security Options

  • UAC enabled
  • NTLMv2 authentication only
  • SMB signing required

Protection

  • Windows Firewall enabled
  • Defender real-time protection active
  • Signatures up to date

Scheduling Regular Audits

Automate weekly compliance checks:

$action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-ExecutionPolicy Bypass -File C:\Scripts\Security-Baseline-Audit.ps1"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday -At 6am
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
 
Register-ScheduledTask -TaskName "Weekly Security Audit" -Action $action -Trigger $trigger -Principal $principal

References

  • CIS Benchmarks
  • Microsoft Security Baselines
  • NIST Cybersecurity Framework

Last Updated: January 2026

#Windows#Security#CIS Benchmarks#Compliance#PowerShell#Hardening

Related Articles

Windows Server Hardening: Complete Security Guide for

Step-by-step Windows Server hardening covering CIS benchmarks, attack surface reduction, service hardening, firewall rules, credential protection, and...

43 min read

Windows Security Event Log Analysis: Detect Threats and

Learn to analyze Windows Security Event Logs to detect brute force attacks, lateral movement, privilege escalation, and other security threats using PowerShell.

9 min read

Domain Controller Hardening: Securing Active Directory

Comprehensive DC hardening guide covering tier model implementation, LDAP signing, NTLM restrictions, Kerberos hardening, AdminSDHolder, DSRM security,...

46 min read
Back to all HOWTOs