Files
audit-web/audit_check_script/audit_cis_windows.ps1
T
2026-08-26 14:11:37 +07:00

1134 lines
60 KiB
PowerShell

<#
.SYNOPSIS
CIS Windows Server Hardening Audit Script
.DESCRIPTION
Audits Windows Server configuration against CIS Benchmarks.
Outputs JSON results for each check and a summary at the end.
.PARAMETER JsonOnly
Only output JSON-formatted results, skip verbose detail lines.
.PARAMETER SecpolPath
Temporary path for secpol.cfg export (default: $env:TEMP\secpol.cfg)
.EXAMPLE
.\audit_cis_windows.ps1 -JsonOnly
.NOTES
Version: 2.0 (Refactored)
#>
param(
[string]$SecpolPath = "$env:TEMP\secpol.cfg",
[switch]$JsonOnly
)
# ============================================
# INITIALIZATION
# ============================================
$script:Results = [System.Collections.ArrayList]::new()
$script:AllResults = @()
Write-Output "Operating System: $((Get-CimInstance -Class Win32_OperatingSystem).Caption)"
Write-Output "Hostname: $env:COMPUTERNAME"
Write-Output "Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "############################################################################"
secedit /export /cfg $SecpolPath > $null
$script:IsDomain = (Get-CimInstance Win32_ComputerSystem).PartOfDomain
if ($script:IsDomain) {
Write-Output "This server is a part of domain (DC)"
} else {
Write-Output "This server is NOT a part of domain (DC)"
}
$script:SecpolCache = $null
$script:NetAccountsCache = $null
$script:AuditPolCache = $null
# ============================================
# HELPER FUNCTIONS
# ============================================
function Write-CheckResult {
param([string]$CheckId, [string]$Description, [bool]$Passed)
$status = if ($Passed) { "PASSED" } else { "FAILED" }
$json = "{`"$CheckId. $Description`" : `"$status`"}"
Write-Output $json
$script:AllResults += @{ CheckId = $CheckId; Description = $Description; Status = $status }
}
function Get-NetAccountsValue {
param([string]$Key)
if (-not $script:NetAccountsCache) { $script:NetAccountsCache = net accounts }
$line = $script:NetAccountsCache | Select-String $Key
if (-not $line) { return $null }
$val = $line.ToString().Split(':')[1].Trim()
if ($val -eq 'Never' -or $val -eq 'None') { return $val }
try { return [int]$val } catch { return $val }
}
function Get-SecpolCache {
if (-not $script:SecpolCache) {
$script:SecpolCache = Get-Content $SecpolPath -ErrorAction SilentlyContinue
}
return $script:SecpolCache
}
function Get-SecpolNumeric {
param([string]$Key)
$content = Get-SecpolCache
$line = $content | Select-String $Key | Select-Object -First 1
if (-not $line) { return $null }
try { return [int]$line.ToString().Split('=')[1].Trim() } catch { return $null }
}
function Get-SecpolSID {
param([string]$Key)
$content = Get-SecpolCache
$line = $content | Select-String $Key | Select-Object -First 1
if (-not $line) { return '' }
return $line.ToString().Split('=')[1].Trim()
}
function Test-SecpolPrivilegeNotAssigned {
param([string]$Key)
$content = Get-SecpolCache
$matches = $content | Select-String $Key
return ($matches | Measure-Object).Count -eq 0
}
function Get-RegistryValue {
param([string]$Path, [string]$Name)
try {
return Get-ItemPropertyValue -Path $Path -Name $Name -ErrorAction Stop
} catch {
return $null
}
}
function Test-RegistryDword {
param([string]$Path, [string]$Name, [int]$Expected, [string]$Comparison = 'eq')
$val = Get-RegistryValue -Path $Path -Name $Name
if ($null -eq $val) { return $null }
switch ($Comparison) {
'eq' { return [int]$val -eq $Expected }
'ne' { return [int]$val -ne $Expected }
'ge' { return [int]$val -ge $Expected }
'le' { return [int]$val -le $Expected }
'gt' { return [int]$val -gt $Expected }
'lt' { return [int]$val -lt $Expected }
default { return $null }
}
}
function Test-RegistryDwordRange {
param([string]$Path, [string]$Name, [int]$Min, [int]$Max)
$val = Get-RegistryValue -Path $Path -Name $Name
if ($null -eq $val) { return $null }
return ([int]$val -ge $Min -and [int]$val -le $Max -and [int]$val -ne 0)
}
function Test-RegistryString {
param([string]$Path, [string]$Name, [string]$Expected)
$val = Get-RegistryValue -Path $Path -Name $Name
if ($null -eq $val) { return $false }
return [string]$val -eq $Expected
}
function Get-AuditPolCache {
if (-not $script:AuditPolCache) {
$script:AuditPolCache = auditpol.exe /get /category:*
}
return $script:AuditPolCache
}
function Test-AuditPolValue {
param([string]$SearchPattern, [int]$FieldIndex, [string]$Expected)
$content = Get-AuditPolCache
$line = $content | Select-String $SearchPattern
if (-not $line) { return $false }
$field = ($line.ToString() -split '\s+', $FieldIndex + 2)[$FieldIndex]
return [string]$field -eq $Expected
}
function Get-AdminAccountName {
$desc = Get-SecpolCache | Select-String 'NewAdministratorName'
if ($desc -and $desc.ToString().Split('=')[1].Trim() -ne '"Administrator"') {
return $desc.ToString().Split('=')[1].Trim().Trim('"')
}
return 'Administrator'
}
function Get-GuestAccountName {
$desc = Get-SecpolCache | Select-String 'NewGuestName'
if ($desc -and $desc.ToString().Split('=')[1].Trim() -ne '"Guest"') {
return $desc.ToString().Split('=')[1].Trim().Trim('"')
}
return 'Guest'
}
# ============================================
# 1. ACCOUNT POLICIES
# ============================================
Write-Output ""
Write-Output "# SECTION 1: ACCOUNT POLICIES"
Write-Output "############################################################################"
# --- 1.1 Password Policy ---
# 1.1.1 Enforce password history >= 24
$val = Get-NetAccountsValue 'Length of password history maintained'
$passed = ($val -ne 'None') -and ([int]$val -ge 24)
Write-CheckResult "1.1.1" "Cau hinh tham so 'Enforce password history'" $passed
# 1.1.2 Maximum password age <= 90 (not 0)
$val = Get-NetAccountsValue 'Maximum password age'
$passed = ([int]$val -le 90) -and ([int]$val -ne 0)
Write-CheckResult "1.1.2" "Cau hinh tham so 'Maximum password age'" $passed
# 1.1.3 Minimum password age >= 1
$val = Get-NetAccountsValue 'Minimum password age'
$passed = [int]$val -ge 1
Write-CheckResult "1.1.3" "Cau hinh tham so 'Minimum password age'" $passed
# 1.1.4 Minimum password length >= 8
$val = Get-NetAccountsValue 'Minimum password length'
$passed = [int]$val -ge 8
Write-CheckResult "1.1.4" "Cau hinh tham so 'Minimum password length'" $passed
# 1.1.5 Password complexity - Enabled (1)
$val = Get-SecpolNumeric 'PasswordComplexity'
$passed = ($null -ne $val) -and ($val -eq 1)
Write-CheckResult "1.1.5" "Cau hinh chinh sach 'Password must meet complexity requirements'" $passed
# 1.1.6 Store passwords using reversible encryption - Disabled (0)
$val = Get-SecpolNumeric 'ClearTextPassword'
$passed = ($null -ne $val) -and ($val -eq 0)
Write-CheckResult "1.1.6" "Cau hinh tham so 'Store passwords using reversible encryption'" $passed
# --- 1.2 Account Lockout Policy ---
# 1.2.1 Account lockout duration >= 15
$val = Get-NetAccountsValue 'Lockout duration'
$passed = ($val -ne 'Never') -and ([int]$val -ge 15)
Write-CheckResult "1.2.1" "Cau hinh tham so 'Account lockout duration'" $passed
# 1.2.2 Account lockout threshold <= 5 (not 0)
$val = Get-NetAccountsValue 'Lockout threshold'
$passed = ([int]$val -le 5) -and ([int]$val -ne 0)
Write-CheckResult "1.2.2" "Cau hinh tham so 'Account lockout threshold'" $passed
# 1.2.3 Reset account lockout counter after >= 15
$val = Get-NetAccountsValue 'observation'
$passed = ($val -ne 'Never') -and ([int]$val -ge 15)
Write-CheckResult "1.2.3" "Cau hinh tham so 'Reset account lockout counter after'" $passed
# ============================================
# 2. LOCAL POLICIES
# ============================================
Write-Output ""
Write-Output "# SECTION 2: LOCAL POLICIES"
Write-Output "############################################################################"
# --- 2.1 User Rights Assignment ---
# 2.1.1 Access Credential Manager as a trusted caller - No One
$passed = Test-SecpolPrivilegeNotAssigned 'SeTrustedCredManAccessPrivilege'
Write-CheckResult "2.1.1" "Cau hinh chinh sach 'Access Credential Manager as a trusted caller'" $passed
# 2.1.2 Access this computer from the network
$sid = Get-SecpolSID 'SeNetworkLogonRight'
if ($script:IsDomain) {
$passed = ($sid -eq '*S-1-5-11,*S-1-5-32-544,*S-1-5-9')
Write-CheckResult "2.1.2" "Cau hinh chinh sach 'Access this computer from the network' [Chỉ DC]" $passed
} else {
$passed = ($sid -eq '*S-1-5-11,*S-1-5-32-544')
Write-CheckResult "2.1.2" "Cau hinh chinh sach 'Access this computer from the network' [Chỉ MS]" $passed
}
# 2.1.3 Act as part of the operating system - No One
$passed = Test-SecpolPrivilegeNotAssigned 'SeTcbPrivilege'
Write-CheckResult "2.1.3" "Cau hinh chinh sach 'Act as part of the operating system'" $passed
# 2.1.4 Add workstations to domain - Administrators (DC only)
if ($script:IsDomain) {
$count = (Get-SecpolCache | Select-String 'SeMachineAccountPrivilege' | Measure-Object).Count
$sid = Get-SecpolSID 'SeMachineAccountPrivilege'
$passed = ($count -eq 1) -and ($sid -eq '*S-1-5-32-544')
Write-CheckResult "2.1.4" "Cau hinh chinh sach 'Add workstations to domain' [Chỉ DC]" $passed
}
# 2.1.5 Adjust memory quotas for a process
$passed = (Get-SecpolSID 'SeIncreaseQuotaPrivilege') -eq '*S-1-5-19,*S-1-5-20,*S-1-5-32-544'
Write-CheckResult "2.1.5" "Cau hinh chinh sach 'Adjust memory quotas for a process'" $passed
# 2.1.6 Allow log on locally - Administrators
$passed = (Get-SecpolSID 'SeInteractiveLogonRight') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.6" "Cau hinh chinh sach 'Allow log on locally'" $passed
# 2.1.7 Allow log on through Remote Desktop Services
$sid = Get-SecpolSID 'SeRemoteInteractiveLogonRight'
if ($script:IsDomain) {
$passed = ($sid -eq '*S-1-5-32-544')
Write-CheckResult "2.1.7" "Cau hinh chinh sach 'Allow log on through Remote Desktop Services' [Chỉ DC]" $passed
} else {
$passed = ($sid -eq '*S-1-5-32-544,*S-1-5-32-555')
Write-CheckResult "2.1.7" "Cau hinh chinh sach 'Allow log on through Remote Desktop Services' [Chỉ MS]" $passed
}
# 2.1.8 Back up files and directories - Administrators
$passed = (Get-SecpolSID 'SeBackupPrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.8" "Cau hinh chinh sach 'Back up files and directories'" $passed
# 2.1.9 Change the system time
$passed = (Get-SecpolSID 'SeSystemtimePrivilege') -eq '*S-1-5-19,*S-1-5-32-544'
Write-CheckResult "2.1.9" "Cau hinh chinh sach 'Change the system time'" $passed
# 2.1.10 Change the time zone
$passed = (Get-SecpolSID 'SeTimeZonePrivilege') -eq '*S-1-5-19,*S-1-5-32-544'
Write-CheckResult "2.1.10" "Cau hinh chinh sach 'Change the time zone'" $passed
# 2.1.11 Create a pagefile - Administrators
$passed = (Get-SecpolSID 'SeCreatePagefilePrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.11" "Cau hinh chinh sach 'Create a pagefile'" $passed
# 2.1.12 Create a token object - No One
$passed = Test-SecpolPrivilegeNotAssigned 'SeCreateTokenPrivilege'
Write-CheckResult "2.1.12" "Cau hinh chinh sach 'Create a token object'" $passed
# 2.1.13 Create global objects
$passed = (Get-SecpolSID 'SeCreateGlobalPrivilege') -eq '*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6'
Write-CheckResult "2.1.13" "Cau hinh chinh sach 'Create global objects'" $passed
# 2.1.14 Create permanent shared objects - No One
$passed = Test-SecpolPrivilegeNotAssigned 'SeCreatePermanentPrivilege'
Write-CheckResult "2.1.14" "Cau hinh chinh sach 'Create permanent shared objects'" $passed
# 2.1.15 Create symbolic links
$sid = Get-SecpolSID 'SeCreateSymbolicLinkPrivilege'
if ($script:IsDomain) {
$passed = ($sid -eq '*S-1-5-32-544')
Write-CheckResult "2.1.15" "Cau hinh chinh sach 'Create symbolic links' [Chỉ DC]" $passed
} else {
try {
$hyperVInstalled = -not [string]::IsNullOrEmpty((Get-WindowsFeature -Name Hyper-V).InstallDate)
} catch { $hyperVInstalled = $false }
if ($hyperVInstalled) {
$passed = ($sid -eq '*S-1-5-32-544,*S-1-5-83-0')
} else {
$passed = ($sid -eq '*S-1-5-32-544')
}
Write-CheckResult "2.1.15" "Cau hinh chinh sach 'Create symbolic links' [Chỉ MS]" $passed
}
# 2.1.16 Debug programs - Administrators
$passed = (Get-SecpolSID 'SeDebugPrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.16" "Cau hinh chinh sach 'Debug programs'" $passed
# 2.1.17 Deny access to this computer from the network
$count = (Get-SecpolCache | Select-String "SeDenyNetworkLogonRight" | Measure-Object).Count
$sid = Get-SecpolSID 'SeDenyNetworkLogonRight'
if ($script:IsDomain) {
$passed = ($count -eq 1) -and ($sid -eq '*S-1-5-32-546')
Write-CheckResult "2.1.17" "Cau hinh chinh sach 'Deny access to this computer from the network' [Chỉ DC]" $passed
} else {
$rdpEnabled = [int](Get-RegistryValue "HKLM:\System\CurrentControlSet\Control\Terminal Server" "fDenyTSConnections") -eq 0
if ($rdpEnabled) {
$passed = ($count -eq 1) -and ($sid -eq '*S-1-5-32-546')
} else {
$passed = ($count -eq 1) -and (($sid -eq '*S-1-5-32-546') -or ($sid -eq '*S-1-5-113,*S-1-5-32-544,*S-1-5-32-546'))
}
Write-CheckResult "2.1.17" "Cau hinh chinh sach 'Deny access to this computer from the network' [Chỉ MS]" $passed
}
# 2.1.18 Deny log on as a batch job - Guests
$passed = (Get-SecpolSID 'SeDenyBatchLogonRight') -eq '*S-1-5-32-546'
Write-CheckResult "2.1.18" "Cau hinh chinh sach 'Deny log on as a batch job'" $passed
# 2.1.19 Deny log on as a service - Guests
$passed = (Get-SecpolSID 'SeDenyServiceLogonRight') -eq '*S-1-5-32-546'
Write-CheckResult "2.1.19" "Cau hinh chinh sach 'Deny log on as a service'" $passed
# 2.1.20 Deny log on locally - Guests
$count = (Get-SecpolCache | Select-String "SeDenyInteractiveLogonRight" | Measure-Object).Count
$sid = Get-SecpolSID 'SeDenyInteractiveLogonRight'
$passed = ($count -ne 0) -and ($sid -eq '*S-1-5-32-546')
Write-CheckResult "2.1.20" "Cau hinh chinh sach 'Deny log on locally'" $passed
# 2.1.21 Deny log on through Remote Desktop Services
$count = (Get-SecpolCache | Select-String "SeDenyRemoteInteractiveLogonRight" | Measure-Object).Count
$sid = Get-SecpolSID 'SeDenyRemoteInteractiveLogonRight'
if ($script:IsDomain) {
$passed = ($count -ne 0) -and ($sid -eq '*S-1-5-32-546')
Write-CheckResult "2.1.21" "Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Chỉ DC]" $passed
} else {
$rdpEnabled = [int](Get-RegistryValue "HKLM:\System\CurrentControlSet\Control\Terminal Server" "fDenyTSConnections") -eq 0
if ($rdpEnabled) {
$passed = ($count -ne 0) -and ($sid -eq '*S-1-5-32-546')
} else {
$passed = ($count -ne 0) -and (($sid -eq '*S-1-5-32-546') -or ($sid -eq '*S-1-5-113,*S-1-5-32-546') -or ($sid -eq 'S-1-5-113,*S-1-5-32-546'))
}
Write-CheckResult "2.1.21" "Cau hinh chinh sach 'Deny log on through Remote Desktop Services' [Chỉ MS]" $passed
}
# 2.1.22 Enable computer and user accounts to be trusted for delegation
$count = (Get-SecpolCache | Select-String "SeEnableDelegationPrivilege" | Measure-Object).Count
$sid = Get-SecpolSID 'SeEnableDelegationPrivilege'
if ($script:IsDomain) {
$passed = ($count -ne 0) -and ($sid -eq '*S-1-5-32-544')
Write-CheckResult "2.1.22" "Cau hinh chinh sach 'Enable computer and user accounts to be trusted for delegation' [Chỉ DC]" $passed
} else {
$passed = ($count -eq 0)
Write-CheckResult "2.1.22" "Cau hinh chinh sach 'Enable computer and user accounts to be trusted for delegation' [Chỉ MS]" $passed
}
# 2.1.23 Force shutdown from a remote system - Administrators
$passed = (Get-SecpolSID 'SeRemoteShutdownPrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.23" "Cau hinh chinh sach 'Force shutdown from a remote system'" $passed
# 2.1.24 Generate security audits
$passed = (Get-SecpolSID 'SeAuditPrivilege') -eq '*S-1-5-19,*S-1-5-20'
Write-CheckResult "2.1.24" "Cau hinh chinh sach 'Generate security audits'" $passed
# 2.1.25 Impersonate a client after authentication
$sid = Get-SecpolSID 'SeImpersonatePrivilege'
if ($script:IsDomain) {
$passed = ($sid -eq '*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6')
Write-CheckResult "2.1.25" "Cau hinh chinh sach 'Impersonate a client after authentication' [Chỉ DC]" $passed
} else {
try { $iisInstalled = (Get-WindowsFeature -Name Web-Server, Web-Services).Installed } catch { $iisInstalled = $false }
if ($iisInstalled) {
$passed = ($sid -eq '*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-32-568,*S-1-5-6')
} else {
$passed = ($sid -eq '*S-1-5-19,*S-1-5-20,*S-1-5-32-544,*S-1-5-6')
}
Write-CheckResult "2.1.25" "Cau hinh chinh sach 'Impersonate a client after authentication' [Chỉ MS]" $passed
}
# 2.1.26 Increase scheduling priority
$sid = Get-SecpolSID 'SeIncreaseBasePriorityPrivilege'
try { $wmGroup = Get-LocalGroup -Name "Window Manager\Window Manager Group" -ErrorAction Stop; $wmExists = $true } catch { $wmExists = $false }
if ($wmExists) {
$passed = ($sid -eq '*S-1-5-32-544,*S-1-5-90-0')
} else {
$passed = ($sid -eq '*S-1-5-32-544')
}
Write-CheckResult "2.1.26" "Cau hinh chinh sach 'Increase scheduling priority'" $passed
# 2.1.27 Load and unload device drivers - Administrators
$passed = (Get-SecpolSID 'SeLoadDriverPrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.27" "Cau hinh chinh sach 'Load and unload device drivers'" $passed
# 2.1.28 Lock pages in memory - No One
$passed = Test-SecpolPrivilegeNotAssigned 'SeLockMemoryPrivilege'
Write-CheckResult "2.1.28" "Cau hinh chinh sach 'Lock pages in memory'" $passed
# 2.1.29 Manage auditing and security log
$sid = Get-SecpolSID 'SeSecurityPrivilege'
if ($script:IsDomain) {
$passed = ($sid -eq '*S-1-5-32-544')
Write-CheckResult "2.1.29" "Cau hinh chinh sach 'Manage auditing and security log' [Chỉ DC]" $passed
} else {
try { $exchangeRunning = (Get-Service -Name "MSExchangeServiceHost" -ErrorAction Stop).Status -eq "Running" } catch { $exchangeRunning = $false }
if ($exchangeRunning) {
$domainName = (Get-CimInstance -Namespace root\cimv2 -Class Win32_ComputerSystem).Domain
$domainSuffix = $domainName.Replace('.', '-')
$passed = ($sid -eq "*S-1-5-32-544,*S-1-5-21-$domainSuffix-498")
} else {
$passed = ($sid -eq '*S-1-5-32-544')
}
Write-CheckResult "2.1.29" "Cau hinh chinh sach 'Manage auditing and security log' [Chỉ MS]" $passed
}
# 2.1.30 Modify an object label - No One
$passed = Test-SecpolPrivilegeNotAssigned 'SeRelabelPrivilege'
Write-CheckResult "2.1.30" "Cau hinh chinh sach 'Modify an object label'" $passed
# 2.1.31 Modify firmware environment values - Administrators
$passed = (Get-SecpolSID 'SeSystemEnvironmentPrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.31" "Cau hinh chinh sach 'Modify firmware environment values'" $passed
# 2.1.32 Perform volume maintenance tasks - Administrators
$passed = (Get-SecpolSID 'SeManageVolumePrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.32" "Cau hinh chinh sach 'Perform volume maintenance tasks'" $passed
# 2.1.33 Profile single process - Administrators
$passed = (Get-SecpolSID 'SeProfileSingleProcessPrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.33" "Cau hinh chinh sach 'Profile single process'" $passed
# 2.1.34 Profile system performance
$passed = (Get-SecpolSID 'SeSystemProfilePrivilege') -eq '*S-1-5-32-544,*S-1-5-80-3139157870-2983391045-3678747466-658725712-1809340420'
Write-CheckResult "2.1.34" "Cau hinh chinh sach 'Profile system performance'" $passed
# 2.1.35 Replace a process level token
$passed = (Get-SecpolSID 'SeAssignPrimaryTokenPrivilege') -eq '*S-1-5-19,*S-1-5-20'
Write-CheckResult "2.1.35" "Cau hinh chinh sach 'Replace a process level token'" $passed
# 2.1.36 Restore files and directories
$sid = Get-SecpolSID 'SeRestorePrivilege'
$passed = ($sid -eq '*S-1-5-32-544') -or ($sid -eq '*S-1-5-32-544,*S-1-5-32-551')
Write-CheckResult "2.1.36" "Cau hinh chinh sach 'Restore files and directories'" $passed
# 2.1.37 Shut down the system
$sid = Get-SecpolSID 'SeShutdownPrivilege'
$passed = ($sid -eq '*S-1-5-32-544') -or ($sid -eq '*S-1-5-32-544,*S-1-5-32-551')
Write-CheckResult "2.1.37" "Cau hinh chinh sach 'Shut down the system'" $passed
# 2.1.38 Synchronize directory service data (DC only)
if ($script:IsDomain) {
$passed = Test-SecpolPrivilegeNotAssigned 'SeSyncAgentPrivilege'
Write-CheckResult "2.1.38" "Cau hinh chinh sach 'Synchronize directory service data' [Chỉ DC]" $passed
}
# 2.1.39 Take ownership of files or other objects - Administrators
$passed = (Get-SecpolSID 'SeTakeOwnershipPrivilege') -eq '*S-1-5-32-544'
Write-CheckResult "2.1.39" "Cau hinh chinh sach 'Take ownership of files or other objects'" $passed
# --- 2.2 Security Options ---
# 2.2.1.1 Administrator account status - Disabled
$adminName = Get-AdminAccountName
$isActive = (net user $adminName | Select-String 'Account active').ToString().Split(' ')[-1].Trim()
$passed = ($isActive -eq 'No')
Write-CheckResult "2.2.1.1" "Cau hinh trang thai tai khoan 'Administrator account status'" $passed
# 2.2.1.2 Block Microsoft accounts
$noConnectedUser = Get-RegistryValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "NoConnectedUser"
$passed = ($null -ne $noConnectedUser) -and ([int]$noConnectedUser -eq 3)
Write-CheckResult "2.2.1.2" "Cau hinh chinh sach tai khoan 'Block Microsoft accounts'" $passed
# 2.2.1.3 Guest account status - Disabled
$guestName = Get-GuestAccountName
$isActive = (net user $guestName 2>$null | Select-String 'Account active').ToString().Split(' ')[-1].Trim()
$passed = ($isActive -eq 'No')
Write-CheckResult "2.2.1.3" "Cau hinh trang thai tai khoan 'Guest account status'" $passed
# 2.2.1.4 Limit local account use of blank passwords - Enabled
$limitBlank = Get-RegistryValue "HKLM:\System\CurrentControlSet\Control\Lsa" "LimitBlankPasswordUse"
$passed = ($null -ne $limitBlank) -and ([int]$limitBlank -eq 1)
Write-CheckResult "2.2.1.4" "Cau hinh chinh sach tai khoan 'Limit local account use of blank passwords to console logon only'" $passed
# 2.2.1.5 Rename administrator account
$passed = $adminName -ne 'Administrator'
Write-CheckResult "2.2.1.5" "Cau hinh thay doi ten mac dinh tai khoan quan tri 'Rename administrator account'" $passed
# 2.2.1.6 Rename guest account
$passed = $guestName -ne 'Guest'
Write-CheckResult "2.2.1.6" "Cau hinh thay doi ten mac dinh tai khoan Guests 'Rename guest account'" $passed
# 2.2.2.1 Audit: Force audit policy subcategory settings - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "SCENoApplyLegacyAuditPolicy" 1)
Write-CheckResult "2.2.2.1" "Cau hinh chinh sach 'Audit: Force audit policy subcategory settings'" $passed
# 2.2.2.2 Audit: Shut down system immediately if unable to log security audits - Disabled
$passed = (Test-RegistryDword "HKLM:\System\CurrentControlSet\Control\Lsa" "CrashOnAuditFail" 0)
Write-CheckResult "2.2.2.2" "Cau hinh chinh sach 'Audit: Shut down system immediately if unable to log security audits'" $passed
# 2.2.3.1 Devices: Allowed to format and eject removable media - Administrators
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" "AllocateDASD" 0)
Write-CheckResult "2.2.3.1" "Cau hinh chinh sach 'Devices: Allowed to format and eject removable media'" $passed
# 2.2.3.2 Devices: Prevent users from installing printer drivers - Enabled
$passed = (Test-RegistryDword "HKLM:\System\CurrentControlSet\Control\Print\Providers\Lanman Print Services\Servers" "AddPrinterDrivers" 1)
Write-CheckResult "2.2.3.2" "Cau hinh chinh sach 'Devices: Prevent users from installing printer drivers'" $passed
# 2.2.4.1 Domain controller: Allow server operators to schedule tasks - Disabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "SubmitControl" 0)
Write-CheckResult "2.2.4.1" "Cau hinh chinh sach 'Domain controller: Allow server operators to schedule tasks'" $passed
# 2.2.4.2 Domain controller: Refuse machine account password changes - Disabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" "RefusePasswordChange" 0)
Write-CheckResult "2.2.4.2" "Cau hinh chinh sach 'Domain controller: Refuse machine account password changes'" $passed
# 2.2.5.1 Domain member: Digitally encrypt or sign secure channel data (always) - Enabled
$passed = (Get-SecpolNumeric 'RequireSignOrSeal') -eq '4,1'
Write-CheckResult "2.2.5.1" "Cau hinh chinh sach 'Domain member: Digitally encrypt or sign secure channel data (always)'" $passed
# 2.2.5.2 Domain member: Digitally encrypt secure channel data (when possible) - Enabled
$passed = (Test-RegistryDword "HKLM:\System\CurrentControlSet\Services\Netlogon\Parameters" "SealSecureChannel" 1)
Write-CheckResult "2.2.5.2" "Cau hinh chinh sach 'Domain member: Digitally encrypt secure channel data (when possible)'" $passed
# 2.2.5.3 Domain member: Digitally sign secure channel data (when possible) - Enabled
$passed = (Test-RegistryDword "HKLM:\System\CurrentControlSet\Services\Netlogon\Parameters" "SignSecureChannel" 1)
Write-CheckResult "2.2.5.3" "Cau hinh chinh sach 'Domain member: Digitally sign secure channel data (when possible)'" $passed
# 2.2.5.4 Domain member: Disable machine account password changes - Disabled
$passed = (Test-RegistryDword "HKLM:\System\CurrentControlSet\Services\Netlogon\Parameters" "DisablePasswordChange" 0)
Write-CheckResult "2.2.5.4" "Cau hinh chinh sach 'Domain member: Disable machine account password changes'" $passed
# 2.2.5.5 Domain member: Maximum machine account password age - <= 30
$val = Get-RegistryValue "HKLM:\System\CurrentControlSet\Services\Netlogon\Parameters" "MaximumPasswordAge"
$passed = ($null -ne $val) -and ([int]$val -ge 1) -and ([int]$val -le 30)
Write-CheckResult "2.2.5.5" "Cau hinh chinh sach 'Domain member: Maximum machine account password age'" $passed
# 2.2.5.6 Domain member: Require strong session key - Enabled
$passed = (Test-RegistryDword "HKLM:\System\CurrentControlSet\Services\Netlogon\Parameters" "RequireStrongKey" 1)
Write-CheckResult "2.2.5.6" "Cau hinh chinh sach 'Domain member: Require strong (Windows 2000 or later) session key'" $passed
# 2.2.6.1 Interactive logon: Don't display last signed-in - Enabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "DontDisplayLastUserName" 1)
Write-CheckResult "2.2.6.1" "Thiet lap 'Interactive logon: Do not display last user name'" $passed
# 2.2.6.2 Interactive logon: Do not require CTRL+ALT+DEL - Disabled
$passed = (Test-RegistryDword "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System" "DisableCAD" 0)
Write-CheckResult "2.2.6.2" "Thiet lap 'CTRL+ALT+DEL'" $passed
# 2.2.6.3 Interactive logon: Machine inactivity limit <= 900 sec (not 0)
$val = Get-RegistryValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "InactivityTimeoutSecs"
$passed = ($null -ne $val) -and ([int]$val -ge 1) -and ([int]$val -le 900)
Write-CheckResult "2.2.6.3" "Thiet lap 'Interactive logon: Machine inactivity limit'" $passed
# 2.2.6.4 Interactive logon: Message text for users attempting to log on
$legalText = Get-RegistryValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "LegalNoticeText"
$passed = ($null -ne $legalText) -and ($legalText -match '[A-Za-z]')
Write-CheckResult "2.2.6.4" "Cau hinh 'Interactive logon: Message text for users attempting to log on'" $passed
# 2.2.6.5 Interactive logon: Message title for users attempting to log on
$legalCaption = Get-RegistryValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "LegalNoticeCaption"
$passed = ($null -ne $legalCaption) -and ($legalCaption -match '[A-Za-z]')
Write-CheckResult "2.2.6.5" "Thiet lap 'Interactive logon: Message title for users attempting to log on'" $passed
# 2.2.6.6 Interactive logon: Prompt user to change password before expiration - 5 to 14 days
$val = Get-RegistryValue "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" "PasswordExpiryWarning"
$passed = ($null -ne $val) -and ([int]$val -ge 5) -and ([int]$val -le 14)
Write-CheckResult "2.2.6.6" "Thiet lap 'Interactive logon: Prompt user to change password before expiration'" $passed
# 2.2.6.7 Require Domain Controller Authentication to unlock workstation (MS only)
if (-not $script:IsDomain) {
$passed = (Test-RegistryDword "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" "ForceUnlockLogon" 1)
Write-CheckResult "2.2.6.7" "Thiet lap 'Interactive logon: Require Domain Controller Authentication to unlock workstation' [Chỉ MS]" $passed
}
# 2.2.6.8 Smart card removal behavior - Lock Workstation
$passed = (Test-RegistryDword "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" "ScRemoveOption" 1)
Write-CheckResult "2.2.6.8" "Thiet lap 'Interactive logon: Smart card removal behavior'" $passed
# 2.2.7.1 Microsoft network client: Digitally sign communications (if server agrees) - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" "EnableSecuritySignature" 1)
Write-CheckResult "2.2.7.1" "Thiet lap 'Microsoft network client: Digitally sign communications (if server agrees)'" $passed
# 2.2.7.2 Microsoft network client: Send unencrypted password - Disabled
$passed = (Test-RegistryDword "HKLM:\System\CurrentControlSet\Services\LanmanWorkstation\Parameters" "EnablePlainTextPassword" 0)
Write-CheckResult "2.2.7.2" "Thiet lap 'Microsoft network client: Send unencrypted password to third-party SMB servers'" $passed
# 2.2.7.3 Microsoft network client: Digitally sign communications (always) - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" "RequireSecuritySignature" 1)
Write-CheckResult "2.2.7.3" "Thiet lap 'Microsoft network client: Digitally sign communications (always)'" $passed
# 2.2.8.1 Microsoft network server: Amount of idle time before suspending session - <= 15 min
$val = Get-RegistryValue "HKLM:\System\CurrentControlSet\Services\LanManServer\Parameters" "AutoDisconnect"
$passed = ($null -ne $val) -and ([int]$val -ge 1) -and ([int]$val -le 15)
Write-CheckResult "2.2.8.1" "Thiet lap 'Microsoft network server: Amount of idle time required before suspending session'" $passed
# 2.2.8.2 Microsoft network server: Disconnect clients when logon hours expire - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" "enableforcedlogoff" 1)
Write-CheckResult "2.2.8.2" "Thiet lap 'Microsoft network server: Disconnect clients when logon hours expire'" $passed
# 2.2.8.3 Microsoft network server: Digitally sign communications (always) - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" "RequireSecuritySignature" 1)
Write-CheckResult "2.2.8.3" "Thiet lap 'Microsoft network server: Digitally sign communications (always)'" $passed
# 2.2.8.4 Microsoft network server: Digitally sign communications (if client agrees) - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" "EnableSecuritySignature" 1)
Write-CheckResult "2.2.8.4" "Thiet lap 'Microsoft network server: Digitally sign communications (if client agrees)'" $passed
# 2.2.8.5 Microsoft network server: Server SPN target name validation level (MS only)
if (-not $script:IsDomain) {
$val = Get-RegistryValue "HKLM:\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" "SMBServerNameHardeningLevel"
$passed = ($null -ne $val) -and ([int]$val -ge 1)
Write-CheckResult "2.2.8.5" "Thiet lap 'Microsoft network server: Server SPN target name validation level' [Chỉ MS]" $passed
}
# 2.2.9.1 Network access: Allow anonymous SID/Name translation - Disabled
$passed = (Get-SecpolNumeric 'LSAAnonymousNameLookup') -eq 0
Write-CheckResult "2.2.9.1" "Thiet lap 'Network access: Allow anonymous SID/Name translation'" $passed
# 2.2.9.2 Network access: Do not allow anonymous enumeration of SAM accounts (MS only)
if (-not $script:IsDomain) {
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "RestrictAnonymousSAM" 1)
Write-CheckResult "2.2.9.2" "Thiet lap 'Network access: Do not allow anonymous enumeration of SAM accounts' [Chỉ MS]" $passed
}
# 2.2.9.3 Network access: Do not allow anonymous enumeration of SAM accounts and shares (MS only)
if (-not $script:IsDomain) {
$content = Get-SecpolCache
$line = $content | Select-String 'RestrictAnonymous='
$passed = ($line -and $line.ToString().Split('=')[1].Trim() -eq '4,1')
Write-CheckResult "2.2.9.3" "Thiet lap 'Network access: Do not allow anonymous enumeration of SAM accounts and shares' [Chỉ MS]" $passed
}
# 2.2.9.4 Network access: Let Everyone permissions apply to anonymous users - Disabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "EveryoneIncludesAnonymous" 0)
Write-CheckResult "2.2.9.4" "Thiet lap 'Network access: Let Everyone permissions apply to anonymous users'" $passed
# 2.2.9.5 Network access: Named Pipes that can be accessed anonymously
try { $browserStopped = (Get-Service -Name Browser).Status -eq "Stopped" } catch { $browserStopped = $true }
$nullPipes = (Get-SecpolCache | Select-String 'NullSessionPipes').ToString()
if ($script:IsDomain) {
if ($browserStopped) {
$passed = ($nullPipes -eq 'MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\NullSessionPipes=7,LSARPC,NETLOGON,SAMR,BROWSER')
} else {
$passed = ($nullPipes -eq 'MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\NullSessionPipes=7,LSARPC,NETLOGON,SAMR,')
}
Write-CheckResult "2.2.9.5" "Cau hinh 'Network access: Named Pipes that can be accessed anonymously' [Chỉ DC]" $passed
} else {
if ($browserStopped) {
$passed = ($nullPipes -eq 'MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\NullSessionPipes=7,BROWSER')
} else {
$passed = ($nullPipes -eq 'MACHINE\System\CurrentControlSet\Services\LanManServer\Parameters\NullSessionPipes=7,')
}
Write-CheckResult "2.2.9.5" "Cau hinh 'Network access: Named Pipes that can be accessed anonymously' [Chỉ MS]" $passed
}
# 2.2.9.6 Network access: Remotely accessible registry paths
$content = Get-SecpolCache
$line = $content | Select-String 'Winreg.*AllowedExactPaths.*Machine'
$passed = ($line -and $line.ToString().Split('=')[1].Trim() -eq '7,System\CurrentControlSet\Control\ProductOptions,System\CurrentControlSet\Control\Server Applications,Software\Microsoft\Windows NT\CurrentVersion')
Write-CheckResult "2.2.9.6" "Cau hinh 'Network access: Remotely accessible registry paths'" $passed
# 2.2.9.7 Network access: Remotely accessible registry paths and sub-paths
$line = $content | Select-String 'AllowedPaths.*Machine'
$expected = '7,System\CurrentControlSet\Control\Print\Printers,System\CurrentControlSet\Services\Eventlog,Software\Microsoft\OLAP Server,Software\Microsoft\Windows NT\CurrentVersion\Print,Software\Microsoft\Windows NT\CurrentVersion\Windows,System\CurrentControlSet\Control\ContentIndex,System\CurrentControlSet\Control\Terminal Server,System\CurrentControlSet\Control\Terminal Server\UserConfig,System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration,Software\Microsoft\Windows NT\CurrentVersion\Perflib,System\CurrentControlSet\Services\SysmonLog'
$passed = ($line -and $line.ToString().Split('=')[1].Trim() -eq $expected)
Write-CheckResult "2.2.9.7" "Cau hinh 'Network access: Remotely accessible registry paths and sub-paths'" $passed
# 2.2.9.8 Network access: Restrict anonymous access to Named Pipes and Shares - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" "RestrictNullSessAccess" 1)
Write-CheckResult "2.2.9.8" "Cau hinh 'Network access: Restrict anonymous access to Named Pipes and Shares'" $passed
# 2.2.9.9 Network access: Shares that can be accessed anonymously - None
$val = Get-RegistryValue "HKLM:\SYSTEM\CurrentControlSet\Services\LanManServer\Parameters" "NullSessionShares"
$passed = ($null -eq $val) -or ([string]$val).Trim().Length -eq 0
Write-CheckResult "2.2.9.9" "Cau hinh 'Network access: Shares that can be accessed anonymously'" $passed
# 2.2.9.10 Network access: Sharing and security model for local accounts - Classic
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "ForceGuest" 0)
Write-CheckResult "2.2.9.10" "Cau hinh 'Network access: Sharing and security model for local accounts'" $passed
# 2.2.10.1 Network security: Allow LocalSystem NULL session fallback - Disabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" "AllowNullSessionFallback" 0)
Write-CheckResult "2.2.10.1" "Thiet lap 'Network security: Allow LocalSystem NULL session fallback'" $passed
# 2.2.10.2 Network Security: Allow PKU2U authentication - Disabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\pku2u" "AllowOnlineID" 0)
Write-CheckResult "2.2.10.2" "Thiet lap 'Network Security: Allow PKU2U authentication requests to this computer to use online identities'" $passed
# 2.2.10.3 Network security: Configure encryption types allowed for Kerberos
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" "SupportedEncryptionTypes" 0x7ffffff8)
Write-CheckResult "2.2.10.3" "Thiet lap 'Network security: Configure encryption types allowed for Kerberos'" $passed
# 2.2.10.4 Network security: Do not store LAN Manager hash value - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "NoLMHash" 1)
Write-CheckResult "2.2.10.4" "Thiet lap 'Network security: Do not store LAN Manager hash value on next password change'" $passed
# 2.2.10.5 Network security: Force logoff when logon hours expire - Enabled
$passed = (Get-SecpolNumeric 'ForceLogoffWhenHourExpire') -eq 1
Write-CheckResult "2.2.10.5" "Thiet lap 'Network security: Force logoff when logon hours expire'" $passed
# 2.2.10.6 Network security: Allow Local System to use computer identity for NTLM - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "UseMachineId" 1)
Write-CheckResult "2.2.10.6" "Thiet lap 'Network security: Allow Local System to use computer identity for NTLM'" $passed
# 2.2.10.7 Network security: LAN Manager authentication level - Send NTLMv2 only, Refuse LM & NTLM
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" "LmCompatibilityLevel" 5)
Write-CheckResult "2.2.10.7" "Thiet lap 'Network security: LAN Manager authentication level'" $passed
# 2.2.10.8 Network security: LDAP client signing requirements - Negotiate signing
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Services\LDAP" "LDAPClientIntegrity" 1)
Write-CheckResult "2.2.10.8" "Thiet lap 'Network security: LDAP client signing requirements'" $passed
# 2.2.10.9 Network security: Minimum session security for NTLM SSP clients
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" "NTLMMinClientSec" 0x20080000)
Write-CheckResult "2.2.10.9" "Thiet lap 'Network security: Minimum session security for NTLM SSP based (including secure RPC) clients'" $passed
# 2.2.10.10 Network security: Minimum session security for NTLM SSP servers - FIXED BUG
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" "NTLMMinServerSec" 0x20080000)
Write-CheckResult "2.2.10.10" "Thiet lap 'Network security: Minimum session security for NTLM SSP based (including secure RPC) servers'" $passed
# 2.2.11.1 Shutdown: Allow system to be shut down without having to log on - Disabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "ShutdownWithoutLogon" 0)
Write-CheckResult "2.2.11.1" "Thiet lap 'Shutdown: Allow system to be shut down without having to log on'" $passed
# 2.2.12.1 System objects: Require case insensitivity - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Kernel" "ObCaseInsensitive" 1)
Write-CheckResult "2.2.12.1" "Cau hinh chinh sach 'System objects: Require case insensitivity for non-Windows subsystems'" $passed
# 2.2.12.2 System objects: Strengthen default permissions - Enabled
$passed = (Test-RegistryDword "HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager" "ProtectionMode" 1)
Write-CheckResult "2.2.12.2" "Cau hinh chinh sach 'System objects: Strengthen default permissions of internal system objects'" $passed
# 2.2.13.1 User Account Control: Admin Approval Mode - Enabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "FilterAdministratorToken" 1)
Write-CheckResult "2.2.13.1" "Thiet lap 'User Account Control: Admin Approval Mode for the Built-in Administrator account'" $passed
# 2.2.13.2 User Account Control: Behavior of elevation prompt for admins - Prompt for consent
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "ConsentPromptBehaviorAdmin" 2)
Write-CheckResult "2.2.13.2" "Thiet lap 'User Account Control: Behavior of the elevation prompt for administrators in Admin Approval Mode'" $passed
# 2.2.13.3 User Account Control: Detect application installations - Enabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableInstallerDetection" 1)
Write-CheckResult "2.2.13.3" "Thiet lap 'User Account Control: Detect application installations and prompt for elevation'" $passed
# 2.2.13.4 User Account Control: Only elevate UIAccess in secure locations - Enabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableSecureUIAPaths" 1)
Write-CheckResult "2.2.13.4" "Thiet lap 'User Account Control: Only elevate UIAccess applications that are installed in secure locations'" $passed
# 2.2.13.5 User Account Control: Run all admins in Admin Approval Mode - Enabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableLUA" 1)
Write-CheckResult "2.2.13.5" "Thiet lap 'User Account Control: Run all administrators in Admin Approval Mode'" $passed
# 2.2.13.6 User Account Control: Switch to secure desktop - Enabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "PromptOnSecureDesktop" 1)
Write-CheckResult "2.2.13.6" "Thiet lap 'User Account Control: Switch to the secure desktop when prompting for elevation'" $passed
# 2.2.13.7 User Account Control: Virtualize file/registry write failures - Enabled
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableVirtualization" 1)
Write-CheckResult "2.2.13.7" "Thiet lap 'User Account Control: Virtualize file and registry write failures to per-user locations'" $passed
# 2.2.13.8 User Account Control: Behavior of elevation prompt for standard users - Auto deny
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "ConsentPromptBehaviorUser" 0)
Write-CheckResult "2.2.13.8" "Thiet lap 'User Account Control: Behavior of the elevation prompt for standard users'" $passed
# ============================================
# 3. WINDOWS FIREWALL
# ============================================
Write-Output ""
Write-Output "# SECTION 3: WINDOWS FIREWALL"
Write-Output "############################################################################"
function Test-FirewallProfile {
param([string]$Profile, [string]$CheckIdPrefix, [string]$LabelPrefix)
$profilePath = "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\$Profile"
$loggingPath = "$profilePath\Logging"
# Firewall state - On
$passed = (Test-RegistryDword $profilePath "EnableFirewall" 1)
Write-CheckResult "$CheckIdPrefix.1" "Thiet lap trang thai 'Windows Firewall: $LabelPrefix : Firewall state'" $passed
# Inbound connections - Block
$passed = (Test-RegistryDword $profilePath "DefaultInboundAction" 1)
Write-CheckResult "$CheckIdPrefix.2" "Thiet lap trang thai 'Windows Firewall: $LabelPrefix : Inbound connections'" $passed
# Outbound connections - Allow
$passed = (Test-RegistryDword $profilePath "DefaultOutboundAction" 0)
Write-CheckResult "$CheckIdPrefix.3" "Thiet lap trang thai 'Windows Firewall: $LabelPrefix : Outbound connections'" $passed
}
# Domain Profile (3.1)
Test-FirewallProfile "DomainProfile" "3.1" "Domain"
# Domain Profile Logging
$logPath = "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\DomainProfile\Logging"
$passed = $true
Write-CheckResult "3.1.4" "Cau hinh vi tri luu tru nhat ky 'Windows Firewall: Domain: Logging: Name'" $passed # Path not checked strictly
$passed = (Test-RegistryDword $logPath "LogFileSize" 0x4000 "ge")
Write-CheckResult "3.1.5" "Cau hinh kich thuoc gioi han 'Windows Firewall: Domain: Logging: Size limit (KB)'" $passed
$passed = (Test-RegistryDword $logPath "LogDroppedPackets" 1 "ge")
Write-CheckResult "3.1.6" "Thiet lap chinh sach 'Windows Firewall: Domain: Logging: Log dropped packets'" $passed
$passed = (Test-RegistryDword $logPath "LogSuccessfulConnections" 1 "ge")
Write-CheckResult "3.1.7" "Thiet lap chinh sach 'Windows Firewall: Domain: Logging: Log successful connections'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\DomainProfile" "DisableNotifications" 1)
Write-CheckResult "3.1.8" "Thiet lap chinh sach 'Windows Firewall: Domain: Settings: Display a notification'" $passed
# Private Profile (3.2)
Test-FirewallProfile "PrivateProfile" "3.2" "Private"
$logPath = "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PrivateProfile\Logging"
$passed = (Test-RegistryDword $logPath "LogFileSize" 0x4000 "ge")
Write-CheckResult "3.2.4" "Cau hinh vi tri luu tru nhat ky 'Windows Firewall: Private: Logging: Name'" $true # Path not checked strictly
Write-CheckResult "3.2.5" "Cau hinh kich thuoc gioi han 'Windows Firewall: Private: Logging: Size limit (KB)'" $passed
$passed = (Test-RegistryDword $logPath "LogDroppedPackets" 1 "ge")
Write-CheckResult "3.2.6" "Thiet lap chinh sach 'Windows Firewall: Private: Logging: Log dropped packets'" $passed
$passed = (Test-RegistryDword $logPath "LogSuccessfulConnections" 1 "ge")
Write-CheckResult "3.2.7" "Thiet lap chinh sach 'Windows Firewall: Private: Logging: Log successful connections'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PrivateProfile" "DisableNotifications" 1)
Write-CheckResult "3.2.8" "Thiet lap trang thai 'Windows Firewall: Private: Settings: Display a notification'" $passed
# Public Profile (3.3)
Test-FirewallProfile "PublicProfile" "3.3" "Public"
$logPath = "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile\Logging"
$passed = (Test-RegistryDword $logPath "LogFileSize" 0x4000 "ge")
Write-CheckResult "3.3.4" "Cau hinh vi tri luu tru nhat ky 'Windows Firewall: Public: Logging: Name'" $true
Write-CheckResult "3.3.5" "Cau hinh kich thuoc gioi han 'Windows Firewall: Public: Logging: Size limit (KB)'" $passed
$passed = (Test-RegistryDword $logPath "LogDroppedPackets" 1 "ge")
Write-CheckResult "3.3.6" "Thiet lap chinh sach 'Windows Firewall: Public: Logging: Log dropped packets'" $passed
$passed = (Test-RegistryDword $logPath "LogSuccessfulConnections" 1 "ge")
Write-CheckResult "3.3.7" "Thiet lap chinh sach 'Windows Firewall: Public: Logging: Log successful connections'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile" "DisableNotifications" 1)
Write-CheckResult "3.3.8" "Thiet lap trang thai 'Windows Firewall: Public: Settings: Display a notification'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\WindowsFirewall\PublicProfile" "AllowLocalIPsecPolicyMerge" 0 "ne")
Write-CheckResult "3.3.9" "Thiet lap trang thai 'Windows Firewall: Public: Settings: Apply local connection security rules'" $passed
# ============================================
# 4. ADVANCED AUDIT POLICY CONFIGURATION
# ============================================
Write-Output ""
Write-Output "# SECTION 4: ADVANCED AUDIT POLICY"
Write-Output "############################################################################"
# 4.1 Account Logon
$passed = Test-AuditPolValue "Credential Validation" 3 "Success and Failure"
Write-CheckResult "4.1.1" "Cau hinh chinh sach 'Audit Credential Validation'" $passed
$passed = Test-AuditPolValue "Kerberos Authentication Service" 4 "Success and Failure"
Write-CheckResult "4.1.2" "Cau hinh chinh sach 'Audit Kerberos Authentication Service' [Chỉ DC]" $passed
$passed = Test-AuditPolValue "Kerberos Service Ticket Operations" 5 "Success and Failure"
Write-CheckResult "4.1.3" "Cau hinh chinh sach 'Audit Kerberos Service Ticket Operations' [Chỉ DC]" $passed
# 4.2 Account Management
$passed = Test-AuditPolValue "Application Group Management" 4 "Success and Failure"
Write-CheckResult "4.2.1" "Cau hinh chinh sach 'Audit Application Group Management'" $passed
$passed = Test-AuditPolValue "Computer Account Management" 4 "Success"
Write-CheckResult "4.2.2" "Cau hinh chinh sach 'Audit Computer Account Management' [Chỉ DC]" $passed
$passed = Test-AuditPolValue "Distribution Group Management" 4 "Success"
Write-CheckResult "4.2.3" "Cau hinh chinh sach 'Audit Distribution Group Management' [Chỉ DC]" $passed
$passed = Test-AuditPolValue "Other Account Management Events" 5 "Success"
Write-CheckResult "4.2.4" "Cau hinh chinh sach 'Audit Other Account Management Events' [Chỉ DC]" $passed
$passed = Test-AuditPolValue "Security Group Management" 4 "Success"
Write-CheckResult "4.2.5" "Cau hinh chinh sach 'Audit Security Group Management'" $passed
$passed = Test-AuditPolValue "User Account Management" 4 "Success and Failure"
Write-CheckResult "4.2.6" "Cau hinh chinh sach 'Audit User Account Management'" $passed
# 4.3 Detailed Tracking
$passed = Test-AuditPolValue "Process Creation" 3 "Success"
Write-CheckResult "4.3.1" "Cau hinh chinh sach 'Audit Process Creation'" $passed
$passed = Test-AuditPolValue "Plug and Play Events" 5 "Success"
Write-CheckResult "4.3.2" "Cau hinh chinh sach 'Audit PNP Activity'" $passed
# 4.4 DS Access
$passed = Test-AuditPolValue "Directory Service Access" 4 "Failure"
Write-CheckResult "4.4.1" "Cau hinh chinh sach 'Audit Directory Service Access' [Chỉ DC]" $passed
$passed = Test-AuditPolValue "Directory Service Changes" 4 "Success"
Write-CheckResult "4.4.2" "Cau hinh chinh sach 'Audit Directory Service Changes' [Chỉ DC]" $passed
# 4.5 Logon/Logoff
$passed = Test-AuditPolValue "Account Lockout" 3 "Failure"
Write-CheckResult "4.5.1" "Cau hinh chinh sach 'Audit Account Lockout'" $passed
$passed = Test-AuditPolValue " Logoff " 2 "Success"
Write-CheckResult "4.5.2" "Cau hinh chinh sach 'Audit Logoff'" $passed
$passed = Test-AuditPolValue " Logon " 2 "Success and Failure"
Write-CheckResult "4.5.3" "Cau hinh chinh sach 'Audit Logon'" $passed
$passed = Test-AuditPolValue "Other Logon/Logoff Events" 4 "Success and Failure"
Write-CheckResult "4.5.4" "Cau hinh chinh sach 'Audit Other Logon/Logoff Events'" $passed
$passed = Test-AuditPolValue "Special Logon" 3 "Success"
Write-CheckResult "4.5.5" "Cau hinh chinh sach 'Audit Special Logon'" $passed
$passed = Test-AuditPolValue "Group Membership" 3 "Success"
Write-CheckResult "4.5.6" "Cau hinh chinh sach 'Audit Group Membership'" $passed
# 4.6 Object Access
$passed = Test-AuditPolValue "Detailed File Share" 4 "Failure"
Write-CheckResult "4.6.1" "Cau hinh chinh sach 'Audit Detailed File Share'" $passed
$passed = Test-AuditPolValue " File Share" 3 "Success and Failure"
Write-CheckResult "4.6.2" "Cau hinh chinh sach 'Audit File Share'" $passed
$passed = Test-AuditPolValue "Other Object Access Events" 5 "Success and Failure"
Write-CheckResult "4.6.3" "Cau hinh chinh sach 'Audit Other Object Access Events'" $passed
$passed = Test-AuditPolValue "Removable Storage" 3 "Success and Failure"
Write-CheckResult "4.6.4" "Cau hinh chinh sach 'Audit Removable Storage'" $passed
# 4.7 Policy Change
$passed = Test-AuditPolValue "Audit Policy Change" 4 "Success"
Write-CheckResult "4.7.1" "Cau hinh chinh sach 'Audit Audit Policy Change'" $passed
$passed = Test-AuditPolValue "Authentication Policy Change" 4 "Success"
Write-CheckResult "4.7.2" "Cau hinh chinh sach 'Audit Authentication Policy Change'" $passed
$passed = Test-AuditPolValue "Authorization Policy Change" 4 "Success"
Write-CheckResult "4.7.3" "Cau hinh chinh sach 'Audit Authorization Policy Change'" $passed
$passed = Test-AuditPolValue "MPSSVC Rule-Level Policy Change" 5 "Success and Failure"
Write-CheckResult "4.7.4" "Cau hinh chinh sach 'Audit MPSSVC Rule-Level Policy Change'" $passed
$passed = Test-AuditPolValue "Other Policy Change Events" 5 "Failure"
Write-CheckResult "4.7.5" "Cau hinh chinh sach 'Audit Other Policy Change Events'" $passed
# 4.8 Privilege Use
$passed = Test-AuditPolValue "Sensitive Privilege Use " 4 "Success and Failure"
Write-CheckResult "4.8.1" "Cau hinh chinh sach 'Audit Sensitive Privilege Use'" $passed
# 4.9 System
$passed = Test-AuditPolValue "IPsec Driver" 3 "Success and Failure"
Write-CheckResult "4.9.1" "Cau hinh chinh sach 'Audit IPsec Driver'" $passed
$passed = Test-AuditPolValue "Other System Events" 4 "Success and Failure"
Write-CheckResult "4.9.2" "Cau hinh chinh sach 'Audit Other System Events'" $passed
$passed = Test-AuditPolValue "Security State Change" 4 "Success"
Write-CheckResult "4.9.3" "Cau hinh chinh sach 'Audit Security State Change'" $passed
$passed = Test-AuditPolValue "Security System Extension" 4 "Success"
Write-CheckResult "4.9.4" "Cau hinh chinh sach 'Audit Security System Extension'" $passed
$passed = Test-AuditPolValue "System Integrity" 3 "Success and Failure"
Write-CheckResult "4.9.5" "Cau hinh chinh sach 'Audit System Integrity'" $passed
# ============================================
# 5. ADMINISTRATIVE TEMPLATES
# ============================================
Write-Output ""
Write-Output "# SECTION 5: ADMINISTRATIVE TEMPLATES"
Write-Output "############################################################################"
# 5.1 Logon Policies
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" "DisableLockScreenAppNotifications" 1)
Write-CheckResult "5.1.1" "Cau hinh chinh sach 'Turn off app notifications on the lock screen'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" "BlockDomainPicturePassword" 1)
Write-CheckResult "5.1.2" "Cau hinh chinh sach 'Turn off picture password sign-in'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" "AllowDomainPINLogon" 0)
Write-CheckResult "5.1.3" "Cau hinh chinh sach 'Turn on convenience PIN sign-in'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" "BlockUserFromShowingAccountDetailsOnSignin" 1)
Write-CheckResult "5.1.4" "Cau hinh chinh sach 'Block user from showing account details on sign-in'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" "DontDisplayNetworkSelectionUI" 1)
Write-CheckResult "5.1.5" "Cau hinh chinh sach 'Do not display network selection UI'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" "DontEnumerateConnectedUsers" 1)
Write-CheckResult "5.1.6" "Cau hinh chinh sach 'Do not enumerate connected users on domain joined computers'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" "EnumerateLocalUsers" 0)
Write-CheckResult "5.1.7" "Cau hinh chinh sach 'Enumerate local users on domain-joined computers'" $passed
# 5.2 Power Management
$powerGuid = "0e796bdb-100d-47d6-a2d5-f7d2daa51f51"
$powerPath = "HKLM:\SOFTWARE\Policies\Microsoft\Power\PowerSettings\$powerGuid"
$passed = (Test-RegistryDword $powerPath "DCSettingIndex" 1)
Write-CheckResult "5.2.1" "Cau hinh chinh sach 'Require a password when a computer wakes (on battery)'" $passed
$passed = (Test-RegistryDword $powerPath "ACSettingIndex" 1)
Write-CheckResult "5.2.2" "Cau hinh chinh sach 'Require a password when a computer wakes (plugged in)'" $passed
# 5.3 AutoPlay Policies
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" "NoAutoplayfornonVolume" 1)
Write-CheckResult "5.3.1" "Cau hinh chinh sach 'Disallow Autoplay for non-volume devices'" $passed
$passed = (Test-RegistryDword "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" "NoAutorun" 1)
Write-CheckResult "5.3.2" "Cau hinh chinh sach 'Set the default behavior for AutoRun'" $passed
$noDriveType = Get-RegistryValue "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" "NoDriveTypeAutoRun"
$passed = ($null -ne $noDriveType) -and ([int]$noDriveType -eq 0xff)
Write-CheckResult "5.3.3" "Cau hinh chinh sach 'Turn off Autoplay'" $passed
# 5.4 Event Log Service
function Test-EventLogPolicy {
param([string]$LogName, [string]$CheckIdPrefix, [string]$Label, [int]$MinSize = 0x8000)
$logPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\EventLog\$LogName"
$passed = (Test-RegistryDword $logPath "Retention" 0)
Write-CheckResult "$CheckIdPrefix.1" "Thiet lap chinh sach '$Label : Control Event Log behavior when the log file reaches its maximum size'" $passed
$val = Get-RegistryValue $logPath "MaxSize"
$passed = ($null -ne $val) -and ([int]$val -ge $MinSize)
Write-CheckResult "$CheckIdPrefix.2" "Thiet lap chinh sach '$Label : Specify the maximum log file size (KB)'" $passed
}
Test-EventLogPolicy "Application" "5.4.1" "Application" 0x8000
Test-EventLogPolicy "Security" "5.4.2" "Security" 0x30000
Test-EventLogPolicy "Setup" "5.4.3" "Setup" 0x8000
Test-EventLogPolicy "System" "5.4.4" "System" 0x8000
# ============================================
# 6. HOTFIXES
# ============================================
Write-Output ""
Write-Output "# SECTION 6: HOTFIXES"
Write-Output "############################################################################"
Write-Output '{"6.1. Cai dat va cap nhat cac ban va bao mat" : "NONE"}'
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 5 | Format-Table -AutoSize | Out-String | Write-Output
# ============================================
# 7. ANTIVIRUS CHECK
# ============================================
Write-Output ""
Write-Output "# SECTION 7: ANTIVIRUS"
Write-Output "############################################################################"
Write-Output '{"7. Kiem tra cai dat phan mem Anti-virus" : "NONE"}'
try {
$avProducts = Get-CimInstance -Namespace "root\SecurityCenter2" -ClassName "AntivirusProduct" -ErrorAction SilentlyContinue
if ($avProducts) {
Write-Output "Trinh diet virus duoc cai dat tren may:"
$avProducts | ForEach-Object { Write-Output $_.displayName }
Write-CheckResult "7.1" "Kiem tra trang thai phan mem" $true
$defenderStatus = Get-MpComputerStatus -ErrorAction SilentlyContinue
if ($defenderStatus -and $defenderStatus.AntivirusEnabled -eq $true) {
$defenderPref = Get-MpPreference -ErrorAction SilentlyContinue
$passed = ($defenderPref.SignatureUpdateInterval -eq 0)
Write-CheckResult "7.2" "Kiem tra tinh nang tu dong cap nhat cua phan mem" $passed
$passed = ($null -ne $defenderPref.ScheduledScanTime -and [string]$defenderPref.ScheduledScanTime -ne "")
Write-CheckResult "7.3" "Thuc hien lich quet dinh ky may chu" $passed
}
} else {
Write-Output "Khong co trinh diet virus duoc cai dat tren may."
Write-CheckResult "7.1" "Kiem tra trang thai phan mem" $false
}
} catch {
Write-Output "Khong the truy van phan mem diet virus: $_"
Write-CheckResult "7.1" "Kiem tra trang thai phan mem" $false
}
# ============================================
# CLEANUP & SUMMARY
# ============================================
Remove-Item -Force $SecpolPath -Confirm:$false -ErrorAction SilentlyContinue
Write-Output ""
Write-Output "############################################################################"
Write-Output "# AUDIT SUMMARY"
Write-Output "############################################################################"
$passCount = ($script:AllResults | Where-Object { $_.Status -eq "PASSED" }).Count
$failCount = ($script:AllResults | Where-Object { $_.Status -eq "FAILED" }).Count
$totalCount = $script:AllResults.Count
Write-Output @{
TotalChecks = $totalCount
Passed = $passCount
Failed = $failCount
PassRate = if ($totalCount -gt 0) { "$([math]::Round($passCount / $totalCount * 100, 1))%" } else { "N/A" }
} | ConvertTo-Json
Write-Output ""
Write-Output "FAILED CHECKS:"
$script:AllResults | Where-Object { $_.Status -eq "FAILED" } | ForEach-Object {
Write-Output " [$($_.CheckId)] $($_.Description)"
}