Windows Infrastructure Security provides comprehensive guidance for securing Windows-based infrastructure components including domain controllers, member servers, and workstations against modern threats.
Security Architecture Overview
Defense in Depth Model
┌─────────────────────────────────────────────────────────────────┐
│ Windows Security Layers │
├─────────────────────────────────────────────────────────────────┤
│ Layer │ Components │
│ ├─ Physical │ Hardware Security, TPM, Secure Boot │
│ ├─ Network │ Firewall, IPSec, Network Segmentation │
│ ├─ Host │ OS Hardening, AV, HIPS │
│ ├─ Application │ Code Signing, AppLocker, WDAC │
│ ├─ Data │ Encryption, DLP, Rights Management │
│ └─ Identity │ MFA, Privileged Access, Account Policy │
└─────────────────────────────────────────────────────────────────┘
Security Framework Components
- Endpoint Protection: Anti-malware, behavior analysis, threat detection
- Access Control: RBAC, privilege management, authentication
- Data Protection: Encryption at rest and in transit, DLP
- Network Security: Segmentation, monitoring, traffic analysis
- Compliance: Policy enforcement, auditing, reporting
Domain Controller Security Hardening
Advanced Security Configuration
<#
.SYNOPSIS
Advanced Domain Controller security hardening automation.
.DESCRIPTION
Implements comprehensive security controls for domain controllers
including advanced threat protection, compliance settings, and monitoring.
#>
function Set-DomainControllerSecurityBaseline {
[CmdletBinding()]
param(
[Parameter()]
[string[]]$DomainControllers = @(),
[Parameter()]
[switch]$ApplyAdvancedProtection,
[Parameter()]
[string]$ComplianceProfile = "STIG",
[Parameter()]
[string]$LogPath = "C:\Security\Logs\DC-Hardening.log"
)
if ($DomainControllers.Count -eq 0) {
$DomainControllers = (Get-ADDomainController -Filter *).Name
}
$SecurityBaseline = @{
# Account Policies
PasswordPolicy = @{
MinimumPasswordLength = 14
PasswordComplexity = $true
MaximumPasswordAge = 60
MinimumPasswordAge = 1
PasswordHistoryCount = 24
LockoutThreshold = 5
LockoutDuration = 30
ResetLockoutCounterAfter = 30
}
# Audit Policies
AuditPolicy = @{
AccountLogon = "Success,Failure"
AccountManagement = "Success,Failure"
DirectoryServiceAccess = "Success,Failure"
LogonEvents = "Success,Failure"
ObjectAccess = "Success,Failure"
PolicyChange = "Success,Failure"
PrivilegeUse = "Success,Failure"
ProcessTracking = "Success"
SystemEvents = "Success,Failure"
}
# Security Options
SecurityOptions = @{
"Network access: Do not allow anonymous enumeration of SAM accounts" = "Enabled"
"Network access: Do not allow anonymous enumeration of SAM accounts and shares" = "Enabled"
"Network access: Restrict anonymous access to Named Pipes and Shares" = "Enabled"
"Network security: Do not store LAN Manager hash value on next password change" = "Enabled"
"Network security: LAN Manager authentication level" = "Send NTLMv2 response only. Refuse LM & NTLM"
"Network security: Minimum session security for NTLM SSP based clients" = "Require NTLMv2 session security, Require 128-bit encryption"
"Network security: Minimum session security for NTLM SSP based servers" = "Require NTLMv2 session security, Require 128-bit encryption"
"Interactive logon: Do not display last user name" = "Enabled"
"Interactive logon: Do not require CTRL+ALT+DEL" = "Disabled"
"Interactive logon: Prompt user to change password before expiration" = "14 days"
"Microsoft network client: Digitally sign communications (always)" = "Enabled"
"Microsoft network server: Digitally sign communications (always)" = "Enabled"
"Domain controller: Allow server operators to schedule tasks" = "Disabled"
"Domain controller: LDAP server signing requirements" = "Require signing"
"Domain controller: Refuse machine account password changes" = "Disabled"
}
# Services Configuration
Services = @{
"Disabled" = @(
"Fax", "WebClient", "Telephony", "RemoteRegistry",
"TermService", "TapiSrv", "WinRM"
)
"Manual" = @(
"BITS", "Browser", "CertPropSvc", "ClipSrv",
"CryptSvc", "Dhcp", "dmserver", "Dnscache"
)
}
# Registry Security
RegistrySettings = @{
"HKLM:\SYSTEM\CurrentControlSet\Control\LSA\RestrictAnonymous" = 2
"HKLM:\SYSTEM\CurrentControlSet\Control\LSA\RestrictAnonymousSAM" = 1
"HKLM:\SYSTEM\CurrentControlSet\Control\LSA\NoLMHash" = 1
"HKLM:\SYSTEM\CurrentControlSet\Control\LSA\LmCompatibilityLevel" = 5
"HKLM:\SYSTEM\CurrentControlSet\Control\LSA\MSV1_0\NTLMMinClientSec" = 0x20080000
"HKLM:\SYSTEM\CurrentControlSet\Control\LSA\MSV1_0\NTLMMinServerSec" = 0x20080000
"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\DisablePasswordChange" = 0
"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\MaximumPasswordAge" = 30
"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\RequireSignOrSeal" = 1
"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\RequireStrongKey" = 1
"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\SealSecureChannel" = 1
"HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\SignSecureChannel" = 1
}
}
foreach ($DC in $DomainControllers) {
Write-Log "Starting security hardening for DC: $DC" -LogPath $LogPath
try {
# Apply security baseline
Invoke-Command -ComputerName $DC -ScriptBlock {
param($Baseline, $ApplyAdvanced)
# Configure password policy
secedit /export /cfg C:\temp\current.cfg /quiet
$SecurityTemplate = Get-Content C:\temp\current.cfg
# Modify security template with baseline settings
$ModifiedTemplate = $SecurityTemplate | ForEach-Object {
$line = $_
# Password policy settings
if ($line -match "MinimumPasswordLength") {
"MinimumPasswordLength = $($Baseline.PasswordPolicy.MinimumPasswordLength)"
}
elseif ($line -match "PasswordComplexity") {
"PasswordComplexity = $($Baseline.PasswordPolicy.PasswordComplexity ? 1 : 0)"
}
elseif ($line -match "MaximumPasswordAge") {
"MaximumPasswordAge = $($Baseline.PasswordPolicy.MaximumPasswordAge)"
}
elseif ($line -match "MinimumPasswordAge") {
"MinimumPasswordAge = $($Baseline.PasswordPolicy.MinimumPasswordAge)"
}
elseif ($line -match "PasswordHistorySize") {
"PasswordHistorySize = $($Baseline.PasswordPolicy.PasswordHistoryCount)"
}
elseif ($line -match "LockoutBadCount") {
"LockoutBadCount = $($Baseline.PasswordPolicy.LockoutThreshold)"
}
elseif ($line -match "LockoutDuration") {
"LockoutDuration = $($Baseline.PasswordPolicy.LockoutDuration * 60)"
}
elseif ($line -match "ResetLockoutCount") {
"ResetLockoutCount = $($Baseline.PasswordPolicy.ResetLockoutCounterAfter * 60)"
}
else {
$line
}
}
# Apply modified template
$ModifiedTemplate | Out-File -FilePath C:\temp\security.cfg -Encoding ASCII
secedit /configure /db C:\temp\security.sdb /cfg C:\temp\security.cfg /quiet
# Configure audit policies
foreach ($Policy in $Baseline.AuditPolicy.GetEnumerator()) {
auditpol /set /category:"$($Policy.Key)" /success:enable /failure:enable
}
# Configure registry settings
foreach ($Setting in $Baseline.RegistrySettings.GetEnumerator()) {
$Path = Split-Path $Setting.Key
$Name = Split-Path $Setting.Key -Leaf
if (!(Test-Path $Path)) {
New-Item -Path $Path -Force | Out-Null
}
Set-ItemProperty -Path $Path -Name $Name -Value $Setting.Value -Force
}
# Configure services
foreach ($Service in $Baseline.Services.Disabled) {
if (Get-Service -Name $Service -ErrorAction SilentlyContinue) {
Stop-Service -Name $Service -Force -ErrorAction SilentlyContinue
Set-Service -Name $Service -StartupType Disabled -ErrorAction SilentlyContinue
}
}
foreach ($Service in $Baseline.Services.Manual) {
if (Get-Service -Name $Service -ErrorAction SilentlyContinue) {
Set-Service -Name $Service -StartupType Manual -ErrorAction SilentlyContinue
}
}
# Clean up temporary files
Remove-Item C:\temp\current.cfg -ErrorAction SilentlyContinue
Remove-Item C:\temp\security.cfg -ErrorAction SilentlyContinue
Remove-Item C:\temp\security.sdb -ErrorAction SilentlyContinue
} -ArgumentList $SecurityBaseline, $ApplyAdvancedProtection
# Configure Windows Defender Advanced Threat Protection
if ($ApplyAdvancedProtection) {
Enable-AdvancedThreatProtection -ComputerName $DC
}
# Configure Windows Event Forwarding
Configure-WindowsEventForwarding -ComputerName $DC
Write-Log "Security hardening completed for DC: $DC" -LogPath $LogPath -Level "Success"
}
catch {
Write-Log "Failed to harden DC $DC : $($_.Exception.Message)" -LogPath $LogPath -Level "Error"
}
}
}
function Enable-AdvancedThreatProtection {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$ComputerName
)
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
# Enable Windows Defender Advanced Threat Protection
try {
# Configure real-time protection
Set-MpPreference -DisableRealtimeMonitoring $false
Set-MpPreference -DisableBehaviorMonitoring $false
Set-MpPreference -DisableBlockAtFirstSeen $false
Set-MpPreference -DisableIOAVProtection $false
Set-MpPreference -DisableScriptScanning $false
# Configure cloud protection
Set-MpPreference -MAPSReporting Advanced
Set-MpPreference -SubmitSamplesConsent SendAllSamples
# Configure attack surface reduction rules
$ASRRules = @{
"BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550" = "Enabled" # Block executable content from email client and webmail
"D4F940AB-401B-4EFC-AADC-AD5F3C50688A" = "Enabled" # Block all Office applications from creating child processes
"3B576869-A4EC-4529-8536-B80A7769E899" = "Enabled" # Block Office applications from creating executable content
"75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84" = "Enabled" # Block Office applications from injecting code into other processes
"D3E037E1-3EB8-44C8-A917-57927947596D" = "Enabled" # Block JavaScript or VBScript from launching downloaded executable content
"5BEB7EFE-FD9A-4556-801D-275E5FFC04CC" = "Enabled" # Block execution of potentially obfuscated scripts
"92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B" = "Enabled" # Block Win32 API calls from Office macros
}
foreach ($Rule in $ASRRules.GetEnumerator()) {
Add-MpPreference -AttackSurfaceReductionRules_Ids $Rule.Key -AttackSurfaceReductionRules_Actions Enabled
}
# Configure controlled folder access
Set-MpPreference -EnableControlledFolderAccess Enabled
# Add critical system folders to protected list
$ProtectedFolders = @(
"C:\Windows\System32",
"C:\Windows\SysWOW64",
"C:\Program Files",
"C:\Program Files (x86)",
"$env:WINDIR\NTDS"
)
foreach ($Folder in $ProtectedFolders) {
Add-MpPreference -ControlledFolderAccessProtectedFolders $Folder
}
Write-EventLog -LogName Application -Source "SecurityHardening" -EventId 5001 -EntryType Information -Message "Advanced Threat Protection enabled on $env:COMPUTERNAME"
}
catch {
Write-EventLog -LogName Application -Source "SecurityHardening" -EventId 5002 -EntryType Error -Message "Failed to enable ATP on $env:COMPUTERNAME : $($_.Exception.Message)"
throw
}
}
}
function Configure-WindowsEventForwarding {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$ComputerName,
[Parameter()]
[string]$CollectorServer = "SIEM01.company.com"
)
Invoke-Command -ComputerName $ComputerName -ScriptBlock {
param($Collector)
# Configure WinRM for event forwarding
winrm quickconfig -q
winrm set winrm/config/service '@{AllowUnencrypted="false"}'
winrm set winrm/config/service/auth '@{Basic="false"}'
winrm set winrm/config/service/auth '@{Kerberos="true"}'
# Configure Windows Event Collector
wecutil cs "C:\Windows\System32\subscription.xml"
# Create subscription configuration
$SubscriptionXML = @"
<Subscription xmlns="http://schemas.microsoft.com/2006/03/windows/events/subscription">
<SubscriptionId>DomainControllerSecurity</SubscriptionId>
<SubscriptionType>SourceInitiated</SubscriptionType>
<Description>Domain Controller Security Events</Description>
<Enabled>true</Enabled>
<Uri>http://schemas.microsoft.com/wbem/wsman/1/windows/EventLog</Uri>
<ConfigurationMode>Normal</ConfigurationMode>
<Delivery Mode="Push">
<Batching>
<MaxItems>5</MaxItems>
<MaxLatencyTime>900000</MaxLatencyTime>
</Batching>
<PushSettings>
<Heartbeat Interval="900000"/>
</PushSettings>
</Delivery>
<Query>
<![CDATA[
<QueryList>
<Query Id="0">
<Select Path="Security">*[System[(EventID=4624 or EventID=4625 or EventID=4634 or EventID=4672 or EventID=4720 or EventID=4722 or EventID=4724 or EventID=4725 or EventID=4726 or EventID=4727 or EventID=4728 or EventID=4729 or EventID=4730 or EventID=4731 or EventID=4732 or EventID=4733 or EventID=4734 or EventID=4735 or EventID=4737 or EventID=4738 or EventID=4739 or EventID=4740 or EventID=4741 or EventID=4742 or EventID=4743 or EventID=4754 or EventID=4755 or EventID=4756 or EventID=4757 or EventID=4764 or EventID=4767 or EventID=4768 or EventID=4769 or EventID=4771 or EventID=4776 or EventID=4778 or EventID=4779 or EventID=4781)]]></Select>
</Query>
<Query Id="1">
<Select Path="System">*[System[(EventID=7030 or EventID=7045 or EventID=6005 or EventID=6006 or EventID=6008 or EventID=6013)]]></Select>
</Query>
<Query Id="2">
<Select Path="Directory Service">*</Select>
</Query>
</QueryList>
]]>
</Query>
<ReadExistingEvents>false</ReadExistingEvents>
<TransportName>HTTP</TransportName>
<ContentFormat>Events</ContentFormat>
<Locale Language="en-US"/>
<LogFile>ForwardedEvents</LogFile>
<AllowedSourceNonDomainComputers></AllowedSourceNonDomainComputers>
<AllowedSourceDomainComputers>O:NSG:BAD:P(A;;GA;;;DC)S:</AllowedSourceDomainComputers>
</Subscription>
"@
$SubscriptionXML | Out-File -FilePath "C:\Windows\System32\subscription.xml" -Encoding UTF8
# Configure the subscription
wecutil cs "C:\Windows\System32\subscription.xml"
Write-EventLog -LogName Application -Source "SecurityHardening" -EventId 5003 -EntryType Information -Message "Windows Event Forwarding configured on $env:COMPUTERNAME"
} -ArgumentList $CollectorServer
}
Endpoint Detection and Response (EDR)
Advanced Threat Detection
function Install-EDRSolution {
[CmdletBinding()]
param(
[Parameter()]
[string[]]$ComputerNames = @(),
[Parameter()]
[string]$EDRSolution = "WindowsDefenderATP",
[Parameter()]
[string]$OnboardingScript = "C:\Security\Scripts\WindowsDefenderATPOnboardingScript.cmd"
)
if ($ComputerNames.Count -eq 0) {
# Get all domain computers
$ComputerNames = (Get-ADComputer -Filter * -Properties OperatingSystem | Where-Object {$_.OperatingSystem -like "*Windows*"}).Name
}
foreach ($Computer in $ComputerNames) {
Write-Host "Installing EDR on $Computer..." -ForegroundColor Yellow
try {
# Copy onboarding script to target computer
$DestPath = "\\$Computer\C$\Temp\OnboardEDR.cmd"
Copy-Item -Path $OnboardingScript -Destination $DestPath -Force
# Execute onboarding script remotely
Invoke-Command -ComputerName $Computer -ScriptBlock {
param($ScriptPath)
# Run onboarding script
$Result = Start-Process -FilePath "cmd.exe" -ArgumentList "/c `"$ScriptPath`"" -Wait -PassThru -WindowStyle Hidden
if ($Result.ExitCode -eq 0) {
# Configure advanced features
Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Advanced Threat Protection" -Name "Enable" -Value 1 -Force
# Enable tamper protection
Set-MpPreference -DisableTamperProtection $false
# Configure telemetry level
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\DataCollection" -Name "AllowTelemetry" -Value 3 -Force
Write-EventLog -LogName Application -Source "EDRDeployment" -EventId 6001 -EntryType Information -Message "EDR successfully deployed on $env:COMPUTERNAME"
return $true
}
else {
Write-EventLog -LogName Application -Source "EDRDeployment" -EventId 6002 -EntryType Error -Message "EDR deployment failed on $env:COMPUTERNAME with exit code $($Result.ExitCode)"
return $false
}
} -ArgumentList "C:\Temp\OnboardEDR.cmd"
Write-Host "EDR installation completed on $Computer" -ForegroundColor Green
}
catch {
Write-Error "Failed to install EDR on $Computer : $($_.Exception.Message)"
}
}
}
function Get-ThreatDetectionReport {
[CmdletBinding()]
param(
[Parameter()]
[string[]]$ComputerNames = @(),
[Parameter()]
[int]$DaysBack = 7,
[Parameter()]
[string]$ReportPath = "C:\Security\Reports\ThreatDetection.html"
)
$StartDate = (Get-Date).AddDays(-$DaysBack)
$ThreatData = @()
if ($ComputerNames.Count -eq 0) {
$ComputerNames = (Get-ADComputer -Filter *).Name
}
foreach ($Computer in $ComputerNames) {
try {
# Get security events from remote computer
$SecurityEvents = Get-WinEvent -ComputerName $Computer -FilterHashtable @{
LogName = 'Security'
StartTime = $StartDate
ID = 4625, 4624, 4648, 4672, 4720, 4728, 4732, 4756
} -ErrorAction SilentlyContinue
# Get Windows Defender events
$DefenderEvents = Get-WinEvent -ComputerName $Computer -FilterHashtable @{
LogName = 'Microsoft-Windows-Windows Defender/Operational'
StartTime = $StartDate
ID = 1006, 1007, 1008, 1009, 1010, 1116, 1117
} -ErrorAction SilentlyContinue
# Get system events
$SystemEvents = Get-WinEvent -ComputerName $Computer -FilterHashtable @{
LogName = 'System'
StartTime = $StartDate
ID = 7045, 7030, 6005, 6008
} -ErrorAction SilentlyContinue
# Process events for threat indicators
foreach ($Event in ($SecurityEvents + $DefenderEvents + $SystemEvents)) {
$ThreatLevel = "Low"
$ThreatType = "Unknown"
switch ($Event.Id) {
4625 {
$ThreatLevel = "Medium"
$ThreatType = "Failed Logon"
}
4648 {
$ThreatLevel = "Medium"
$ThreatType = "Explicit Credential Use"
}
4672 {
$ThreatLevel = "High"
$ThreatType = "Special Privileges Assigned"
}
1006 {
$ThreatLevel = "Critical"
$ThreatType = "Malware Detected"
}
1007 {
$ThreatLevel = "Critical"
$ThreatType = "Malware Blocked"
}
7045 {
$ThreatLevel = "Medium"
$ThreatType = "Service Installation"
}
}
$ThreatData += [PSCustomObject]@{
ComputerName = $Computer
EventTime = $Event.TimeCreated
EventID = $Event.Id
ThreatType = $ThreatType
ThreatLevel = $ThreatLevel
Message = $Event.Message
UserName = if ($Event.Properties.Count -gt 5) { $Event.Properties[5].Value } else { "N/A" }
SourceIP = if ($Event.Properties.Count -gt 19) { $Event.Properties[19].Value } else { "N/A" }
}
}
}
catch {
Write-Warning "Failed to collect threat data from $Computer : $($_.Exception.Message)"
}
}
# Generate threat report
$CriticalThreats = ($ThreatData | Where-Object ThreatLevel -eq "Critical").Count
$HighThreats = ($ThreatData | Where-Object ThreatLevel -eq "High").Count
$MediumThreats = ($ThreatData | Where-Object ThreatLevel -eq "Medium").Count
$TotalThreats = $ThreatData.Count
$ReportHTML = @"
<!DOCTYPE html>
<html>
<head>
<title>Threat Detection Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.header { background-color: #d32f2f; color: white; padding: 15px; text-align: center; }
.summary { background-color: #f8f9fa; padding: 15px; margin: 20px 0; border-left: 4px solid #d32f2f; }
table { border-collapse: collapse; width: 100%; margin: 10px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.critical { background-color: #ffebee; color: #d32f2f; font-weight: bold; }
.high { background-color: #fff3e0; color: #f57c00; }
.medium { background-color: #e3f2fd; color: #1976d2; }
.low { background-color: #e8f5e8; color: #388e3c; }
.chart { background-color: #f8f9fa; padding: 20px; text-align: center; }
</style>
</head>
<body>
<div class="header">
<h1>Threat Detection Report</h1>
<p>Report Period: $StartDate to $(Get-Date)</p>
</div>
<div class="summary">
<h2>Threat Summary</h2>
<div class="chart">
<h3>Threat Distribution</h3>
<p>Critical: $CriticalThreats | High: $HighThreats | Medium: $MediumThreats | Total: $TotalThreats</p>
</div>
</div>
<h2>Detailed Threat Analysis</h2>
<table>
<tr>
<th>Computer</th>
<th>Time</th>
<th>Threat Type</th>
<th>Level</th>
<th>Event ID</th>
<th>User</th>
<th>Source IP</th>
</tr>
"@
foreach ($Threat in ($ThreatData | Sort-Object EventTime -Descending | Select-Object -First 100)) {
$RowClass = $Threat.ThreatLevel.ToLower()
$ReportHTML += @"
<tr class="$RowClass">
<td>$($Threat.ComputerName)</td>
<td>$($Threat.EventTime)</td>
<td>$($Threat.ThreatType)</td>
<td>$($Threat.ThreatLevel)</td>
<td>$($Threat.EventID)</td>
<td>$($Threat.UserName)</td>
<td>$($Threat.SourceIP)</td>
</tr>
"@
}
$ReportHTML += @"
</table>
<h2>Security Recommendations</h2>
<ul>
<li>Investigate all critical and high-severity threats immediately</li>
<li>Review failed logon patterns for potential brute force attacks</li>
<li>Monitor service installations for potential persistence mechanisms</li>
<li>Implement network segmentation to limit threat propagation</li>
<li>Ensure all endpoints have updated EDR solutions</li>
<li>Conduct regular threat hunting activities</li>
</ul>
<p><em>Generated by Windows Infrastructure Security Monitoring</em></p>
</body>
</html>
"@
# Save report
$ReportDir = Split-Path $ReportPath -Parent
if (!(Test-Path $ReportDir)) {
New-Item -ItemType Directory -Path $ReportDir -Force | Out-Null
}
$ReportHTML | Out-File -FilePath $ReportPath -Encoding UTF8
Write-Host "Threat detection report generated: $ReportPath" -ForegroundColor Green
Write-Host "Critical Threats: $CriticalThreats" -ForegroundColor Red
Write-Host "High Threats: $HighThreats" -ForegroundColor Yellow
return $ThreatData
}
Network Security Controls
Micro-segmentation and Traffic Analysis
function Enable-NetworkSegmentation {
[CmdletBinding()]
param(
[Parameter()]
[string[]]$ComputerNames = @(),
[Parameter()]
[hashtable]$SegmentationRules = @{},
[Parameter()]
[switch]$EnableTrafficAnalysis
)
# Default segmentation rules
if ($SegmentationRules.Count -eq 0) {
$SegmentationRules = @{
"DomainControllers" = @{
AllowedPorts = @(53, 88, 135, 389, 445, 464, 636, 3268, 3269, 9389)
AllowedSources = @("DomainControllers", "MemberServers", "Workstations")
DenyByDefault = $true
}
"MemberServers" = @{
AllowedPorts = @(80, 443, 3389, 5985, 5986)
AllowedSources = @("Workstations", "AdminWorkstations")
DenyByDefault = $true
}
"Workstations" = @{
AllowedPorts = @(80, 443, 445)
AllowedSources = @("DomainControllers", "FileServers", "PrintServers")
DenyByDefault = $false
}
}
}
foreach ($Computer in $ComputerNames) {
Write-Host "Configuring network segmentation for $Computer..." -ForegroundColor Yellow
try {
# Determine computer role
$ComputerRole = Get-ComputerRole -ComputerName $Computer
if ($SegmentationRules.ContainsKey($ComputerRole)) {
$Rules = $SegmentationRules[$ComputerRole]
Invoke-Command -ComputerName $Computer -ScriptBlock {
param($Role, $Rules)
# Enable Windows Firewall on all profiles
Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True -DefaultInboundAction Block -DefaultOutboundAction Allow
# Clear existing rules (be careful!)
# Remove-NetFirewallRule -DisplayGroup "Custom Segmentation Rules" -ErrorAction SilentlyContinue
# Create inbound rules based on role
foreach ($Port in $Rules.AllowedPorts) {
New-NetFirewallRule -DisplayName "Allow Inbound Port $Port ($Role)" -Direction Inbound -Protocol TCP -LocalPort $Port -Action Allow -Group "Custom Segmentation Rules"
}
# Create outbound monitoring rules
if ($Rules.DenyByDefault) {
New-NetFirewallRule -DisplayName "Log Outbound Connections ($Role)" -Direction Outbound -Action Allow -Group "Custom Segmentation Rules" -Enabled True
}
# Enable logging
Set-NetFirewallProfile -Profile Domain -LogAllowed True -LogBlocked True -LogMaxSizeKilobytes 32767 -LogFileName "C:\Windows\System32\LogFiles\Firewall\pfirewall.log"
Write-EventLog -LogName Application -Source "NetworkSecurity" -EventId 7001 -EntryType Information -Message "Network segmentation configured for $Role on $env:COMPUTERNAME"
} -ArgumentList $ComputerRole, $Rules
Write-Host "Network segmentation configured for $Computer ($ComputerRole)" -ForegroundColor Green
}
}
catch {
Write-Error "Failed to configure network segmentation for $Computer : $($_.Exception.Message)"
}
}
}
function Get-ComputerRole {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$ComputerName
)
try {
$Computer = Get-ADComputer -Identity $ComputerName -Properties OperatingSystem
# Check if it's a domain controller
$DCs = Get-ADDomainController -Filter *
if ($DCs.Name -contains $ComputerName) {
return "DomainControllers"
}
# Check operating system for server vs workstation
if ($Computer.OperatingSystem -like "*Server*") {
return "MemberServers"
}
else {
return "Workstations"
}
}
catch {
Write-Warning "Could not determine role for $ComputerName : $($_.Exception.Message)"
return "Unknown"
}
}
Compliance and Audit Framework
STIG and CIS Benchmark Implementation
function Test-ComplianceBaseline {
[CmdletBinding()]
param(
[Parameter()]
[string[]]$ComputerNames = @(),
[Parameter()]
[ValidateSet("STIG", "CIS", "NIST", "Custom")]
[string]$Framework = "STIG",
[Parameter()]
[string]$ReportPath = "C:\Security\Reports\Compliance.html"
)
$ComplianceResults = @()
$Framework = "STIG" # Default to STIG baseline
# Load compliance checks based on framework
$ComplianceChecks = Get-ComplianceChecks -Framework $Framework
foreach ($Computer in $ComputerNames) {
Write-Host "Running compliance assessment on $Computer..." -ForegroundColor Yellow
foreach ($Check in $ComplianceChecks) {
try {
$Result = Invoke-Command -ComputerName $Computer -ScriptBlock $Check.ScriptBlock
$ComplianceResults += [PSCustomObject]@{
ComputerName = $Computer
Framework = $Framework
CheckID = $Check.ID
Title = $Check.Title
Category = $Check.Category
Severity = $Check.Severity
Status = $Result.Status
Finding = $Result.Finding
Expected = $Check.Expected
Remediation = $Check.Remediation
Timestamp = Get-Date
}
}
catch {
$ComplianceResults += [PSCustomObject]@{
ComputerName = $Computer
Framework = $Framework
CheckID = $Check.ID
Title = $Check.Title
Category = $Check.Category
Severity = $Check.Severity
Status = "Error"
Finding = $_.Exception.Message
Expected = $Check.Expected
Remediation = $Check.Remediation
Timestamp = Get-Date
}
}
}
}
# Generate compliance report
Generate-ComplianceReport -Results $ComplianceResults -ReportPath $ReportPath
return $ComplianceResults
}
function Get-ComplianceChecks {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$Framework
)
switch ($Framework) {
"STIG" {
return @(
@{
ID = "V-73519"
Title = "Password history must be configured"
Category = "Account Management"
Severity = "Medium"
Expected = "24 passwords remembered"
Remediation = "Set password history to 24"
ScriptBlock = {
$Policy = secedit /export /cfg C:\temp\secpol.cfg /quiet
$Content = Get-Content C:\temp\secpol.cfg
$PasswordHistory = ($Content | Where-Object { $_ -match "PasswordHistorySize" }) -replace "PasswordHistorySize = ", ""
Remove-Item C:\temp\secpol.cfg -Force
if ($PasswordHistory -ge 24) {
return @{ Status = "Pass"; Finding = "Password history is $PasswordHistory" }
} else {
return @{ Status = "Fail"; Finding = "Password history is $PasswordHistory (should be 24)" }
}
}
},
@{
ID = "V-73521"
Title = "Minimum password length must be 14 characters"
Category = "Account Management"
Severity = "High"
Expected = "14 characters minimum"
Remediation = "Set minimum password length to 14"
ScriptBlock = {
$Policy = secedit /export /cfg C:\temp\secpol.cfg /quiet
$Content = Get-Content C:\temp\secpol.cfg
$MinLength = ($Content | Where-Object { $_ -match "MinimumPasswordLength" }) -replace "MinimumPasswordLength = ", ""
Remove-Item C:\temp\secpol.cfg -Force
if ($MinLength -ge 14) {
return @{ Status = "Pass"; Finding = "Minimum password length is $MinLength" }
} else {
return @{ Status = "Fail"; Finding = "Minimum password length is $MinLength (should be 14)" }
}
}
},
@{
ID = "V-73805"
Title = "Anonymous access to Named Pipes and Shares must be restricted"
Category = "Network Security"
Severity = "High"
Expected = "Restricted"
Remediation = "Enable 'Network access: Restrict anonymous access to Named Pipes and Shares'"
ScriptBlock = {
$RegValue = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\LSA" -Name "restrictanonymous" -ErrorAction SilentlyContinue
if ($RegValue.restrictanonymous -eq 1) {
return @{ Status = "Pass"; Finding = "Anonymous access is restricted" }
} else {
return @{ Status = "Fail"; Finding = "Anonymous access is not restricted" }
}
}
}
)
}
"CIS" {
return @(
@{
ID = "2.3.1.1"
Title = "Accounts: Administrator account status"
Category = "Account Policies"
Severity = "High"
Expected = "Disabled"
Remediation = "Disable the Administrator account"
ScriptBlock = {
$Admin = Get-LocalUser -Name "Administrator"
if ($Admin.Enabled -eq $false) {
return @{ Status = "Pass"; Finding = "Administrator account is disabled" }
} else {
return @{ Status = "Fail"; Finding = "Administrator account is enabled" }
}
}
},
@{
ID = "9.1.1"
Title = "Windows Firewall: Domain: Firewall state"
Category = "Windows Firewall"
Severity = "High"
Expected = "On"
Remediation = "Enable Domain profile firewall"
ScriptBlock = {
$Firewall = Get-NetFirewallProfile -Profile Domain
if ($Firewall.Enabled -eq $true) {
return @{ Status = "Pass"; Finding = "Domain firewall is enabled" }
} else {
return @{ Status = "Fail"; Finding = "Domain firewall is disabled" }
}
}
}
)
}
}
}