<# .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)" }