Bu script ile Active Directory Rıd Master Health Check kontrolü yaparak mevcut yapınızı analiz edebilirsiniz.

<# Volsys Vesion : 2.0 0fis : 13.3.2026#>[CmdletBinding()]param( [int]$DaysBack = 7, [int]$EventCount = 30)$ErrorActionPreference = 'Stop'try { Import-Module ActiveDirectory -ErrorAction Stop}catch { Write-Error "ActiveDirectory modülü yüklenemedi." exit 1}# -------------------------------------------------------------------# Output Paths# -------------------------------------------------------------------$TimeStamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"$BaseFolder = "C:\Volsys\AD-Ultimate-Health"$OutputFolder = Join-Path $BaseFolder $TimeStamp$TxtReport = Join-Path $OutputFolder "Volsys_AD_Ultimate_HealthCheck_$TimeStamp.txt"$HtmlReport = Join-Path $OutputFolder "Volsys_AD_Ultimate_HealthCheck_$TimeStamp.html"New-Item -Path $OutputFolder -ItemType Directory -Force | Out-Null# -------------------------------------------------------------------# Containers# -------------------------------------------------------------------$Global:DashboardResults = New-Object System.Collections.Generic.List[object]$Global:DetailSections = New-Object System.Collections.Generic.List[object]# -------------------------------------------------------------------# Logging# -------------------------------------------------------------------function Write-VolsysLog { param( [AllowEmptyString()] [string]$Text ) if ($null -eq $Text) { $Text = "" } $Text | Out-File -FilePath $TxtReport -Append -Encoding UTF8 Write-Host $Text}function Write-Section { param([string]$Title) Write-VolsysLog "" Write-VolsysLog ("=" * 100) Write-VolsysLog ("{0,-100}" -f $Title) Write-VolsysLog ("=" * 100)}function Write-SubSection { param([string]$Title) Write-VolsysLog "" Write-VolsysLog ("-" * 100) Write-VolsysLog ("{0,-100}" -f $Title) Write-VolsysLog ("-" * 100)}# -------------------------------------------------------------------# Dashboard Helpers# -------------------------------------------------------------------function Add-Result { param( [string]$Category, [string]$Check, [string]$Status, [string]$Details ) $obj = [PSCustomObject]@{ Category = $Category Check = $Check Status = $Status Details = $Details } $Global:DashboardResults.Add($obj) | Out-Null}function Add-DetailSection { param( [string]$Title, [string[]]$Lines ) $obj = [PSCustomObject]@{ Title = $Title Lines = $Lines } $Global:DetailSections.Add($obj) | Out-Null}function Safe-Run { param( [scriptblock]$ScriptBlock, [string]$OnError = "Command failed." ) try { & $ScriptBlock } catch { Write-VolsysLog "$OnError Error: $($_.Exception.Message)" Add-Result -Category "Execution" -Check $OnError -Status "FAIL" -Details $_.Exception.Message }}# -------------------------------------------------------------------# Utility Functions# -------------------------------------------------------------------function Convert-RIDBlockState { param($Value) if ($null -eq $Value) { return "Not Set / Normal" } elseif ($Value -eq $false) { return "FALSE - RID allocation blocked" } elseif ($Value -eq $true) { return "TRUE - Manual override may have been applied" } else { return "$Value" }}function Convert-IntervalToRange { param([Int64]$Value) $LowPart = $Value -band 0xFFFFFFFF $HighPart = $Value -shr 32 [PSCustomObject]@{ LowPart = $LowPart HighPart = $HighPart Count = ($HighPart - $LowPart + 1) }}function Get-StatusClass { param([string]$Status) switch ($Status.ToUpper()) { 'PASS' { return 'pass' } 'WARN' { return 'warn' } 'FAIL' { return 'fail' } default { return 'info' } }}function ConvertTo-HtmlSafe { param([string]$Text) if ($null -eq $Text) { return "" } return [System.Net.WebUtility]::HtmlEncode($Text)}# -------------------------------------------------------------------# Initial Header# -------------------------------------------------------------------Write-VolsysLog ("=" * 100)Write-VolsysLog ("{0,-100}" -f "VOLSYS AD ULTIMATE HEALTH CHECK - HTML DASHBOARD")Write-VolsysLog ("=" * 100)Write-VolsysLog "Report Time : $(Get-Date)"Write-VolsysLog "Computer Name : $env:COMPUTERNAME"Write-VolsysLog "User : $env:USERNAME"Write-VolsysLog "DaysBack : $DaysBack"Write-VolsysLog "EventCount : $EventCount"Write-VolsysLog "TXT Report : $TxtReport"Write-VolsysLog "HTML Report : $HtmlReport"# -------------------------------------------------------------------# Forest / Domain# -------------------------------------------------------------------$Forest = $null$Domain = $null$DCs = @()$DomainDN = $nullWrite-Section "FOREST AND DOMAIN SUMMARY"Safe-Run -OnError "Forest/Domain bilgisi alinamadi." -ScriptBlock { $Forest = Get-ADForest $Domain = Get-ADDomain $DomainDN = $Domain.DistinguishedName Write-VolsysLog "Forest Name : $($Forest.Name)" Write-VolsysLog "Forest Mode : $($Forest.ForestMode)" Write-VolsysLog "Root Domain : $($Forest.RootDomain)" Write-VolsysLog "Domains : $($Forest.Domains -join ', ')" Write-VolsysLog "Sites : $($Forest.Sites -join ', ')" Write-VolsysLog "Domain FQDN : $($Domain.DNSRoot)" Write-VolsysLog "NetBIOS Name : $($Domain.NetBIOSName)" Write-VolsysLog "Domain Mode : $($Domain.DomainMode)" Write-VolsysLog "Domain DN : $($Domain.DistinguishedName)" Add-Result -Category "Forest" -Check "Forest discovery" -Status "PASS" -Details "Forest: $($Forest.Name)" Add-Result -Category "Domain" -Check "Domain discovery" -Status "PASS" -Details "Domain: $($Domain.DNSRoot)" Add-DetailSection -Title "Forest and Domain Summary" -Lines @( "Forest Name: $($Forest.Name)", "Forest Mode: $($Forest.ForestMode)", "Root Domain: $($Forest.RootDomain)", "Domains: $($Forest.Domains -join ', ')", "Sites: $($Forest.Sites -join ', ')", "Domain FQDN: $($Domain.DNSRoot)", "NetBIOS Name: $($Domain.NetBIOSName)", "Domain Mode: $($Domain.DomainMode)", "Domain DN: $($Domain.DistinguishedName)" )}# -------------------------------------------------------------------# FSMO# -------------------------------------------------------------------Write-Section "FSMO ROLE OWNERS"Safe-Run -OnError "FSMO role bilgileri alinamadi." -ScriptBlock { Write-VolsysLog "Schema Master : $($Forest.SchemaMaster)" Write-VolsysLog "Domain Naming Master : $($Forest.DomainNamingMaster)" Write-VolsysLog "PDC Emulator : $($Domain.PDCEmulator)" Write-VolsysLog "RID Master : $($Domain.RIDMaster)" Write-VolsysLog "Infrastructure Master : $($Domain.InfrastructureMaster)" Add-Result -Category "FSMO" -Check "FSMO roles readable" -Status "PASS" -Details "FSMO role owners successfully collected" Add-DetailSection -Title "FSMO Role Owners" -Lines @( "Schema Master: $($Forest.SchemaMaster)", "Domain Naming Master: $($Forest.DomainNamingMaster)", "PDC Emulator: $($Domain.PDCEmulator)", "RID Master: $($Domain.RIDMaster)", "Infrastructure Master: $($Domain.InfrastructureMaster)" )}# -------------------------------------------------------------------# Domain Controllers# -------------------------------------------------------------------Write-Section "DOMAIN CONTROLLERS"Safe-Run -OnError "Domain Controller listesi alinamadi." -ScriptBlock { $DCs = Get-ADDomainController -Filter * | Sort-Object HostName if ($DCs.Count -eq 0) { Add-Result -Category "DC" -Check "Domain Controllers found" -Status "FAIL" -Details "No DCs returned" } else { Add-Result -Category "DC" -Check "Domain Controllers found" -Status "PASS" -Details "$($DCs.Count) DC(s) found" } $dcLines = @() foreach ($DC in $DCs) { Write-VolsysLog "" Write-VolsysLog "DC HostName : $($DC.HostName)" Write-VolsysLog "IPv4 Address : $($DC.IPv4Address)" Write-VolsysLog "Site : $($DC.Site)" Write-VolsysLog "OS Version : $($DC.OperatingSystem)" Write-VolsysLog "Is Global Catalog : $($DC.IsGlobalCatalog)" Write-VolsysLog "Is ReadOnly : $($DC.IsReadOnly)" $dcLines += "DC: $($DC.HostName) | IP: $($DC.IPv4Address) | Site: $($DC.Site) | OS: $($DC.OperatingSystem) | GC: $($DC.IsGlobalCatalog) | RODC: $($DC.IsReadOnly)" } Add-DetailSection -Title "Domain Controllers" -Lines $dcLines}# -------------------------------------------------------------------# RID Health# -------------------------------------------------------------------Write-Section "RID HEALTH"Safe-Run -OnError "RID health bilgileri alinamadi." -ScriptBlock { $RidManager = Get-ADObject ` -Identity "CN=RID Manager$,CN=System,$DomainDN" ` -Properties rIDAvailablePool, msDS-RIDPoolAllocationEnabled $GlobalPool = Convert-IntervalToRange -Value ([Int64]$RidManager.rIDAvailablePool) $DefaultMaxRID = 1073741823 $RemainingRIDs = [int64]$GlobalPool.Count $UsedRIDs = $DefaultMaxRID - $RemainingRIDs if ($UsedRIDs -lt 0) { $UsedRIDs = 0 } $UsedPercent = [math]::Round((($UsedRIDs / $DefaultMaxRID) * 100), 4) $RemainingPercent = [math]::Round((($RemainingRIDs / $DefaultMaxRID) * 100), 4) $BlockState = Convert-RIDBlockState -Value $RidManager.'msDS-RIDPoolAllocationEnabled' Write-VolsysLog "RID Master : $($Domain.RIDMaster)" Write-VolsysLog "RID Pool Raw : $($RidManager.rIDAvailablePool)" Write-VolsysLog "RID Low Part : $($GlobalPool.LowPart)" Write-VolsysLog "RID High Part : $($GlobalPool.HighPart)" Write-VolsysLog "Remaining RIDs : $RemainingRIDs" Write-VolsysLog "Used RIDs : $UsedRIDs" Write-VolsysLog "Used Percent : $UsedPercent %" Write-VolsysLog "Remaining Percent : $RemainingPercent %" Write-VolsysLog "RID Allocation State : $BlockState" if ($RidManager.'msDS-RIDPoolAllocationEnabled' -eq $false) { Add-Result -Category "RID" -Check "RID allocation state" -Status "FAIL" -Details "RID allocation blocked" } elseif ($RemainingPercent -le 15) { Add-Result -Category "RID" -Check "RID remaining percentage" -Status "WARN" -Details "Remaining RID percentage is low: $RemainingPercent %" } else { Add-Result -Category "RID" -Check "RID health" -Status "PASS" -Details "Remaining RID percentage: $RemainingPercent %" } Add-DetailSection -Title "RID Health" -Lines @( "RID Master: $($Domain.RIDMaster)", "RID Pool Raw: $($RidManager.rIDAvailablePool)", "RID Low Part: $($GlobalPool.LowPart)", "RID High Part: $($GlobalPool.HighPart)", "Remaining RIDs: $RemainingRIDs", "Used RIDs: $UsedRIDs", "Used Percent: $UsedPercent %", "Remaining Percent: $RemainingPercent %", "RID Allocation State: $BlockState" )}# -------------------------------------------------------------------# Replication# -------------------------------------------------------------------Write-Section "REPLICATION HEALTH"Safe-Run -OnError "Replication summary alinamadi." -ScriptBlock { $repSummary = & repadmin.exe /replsummary 2>&1 $repText = $repSummary | Out-String foreach ($line in $repSummary) { Write-VolsysLog "$line" } if ($repText -match '\bfails\b' -or $repText -match '\berror\b') { Add-Result -Category "Replication" -Check "repadmin /replsummary" -Status "WARN" -Details "Replication summary contains failure/error text" } else { Add-Result -Category "Replication" -Check "repadmin /replsummary" -Status "PASS" -Details "No obvious replication failure text detected" } Add-DetailSection -Title "Replication Summary" -Lines ($repSummary | ForEach-Object { "$_" })}# -------------------------------------------------------------------# DCDIAG Tests# -------------------------------------------------------------------Write-Section "DCDIAG TESTS"Safe-Run -OnError "dcdiag DNS testi alinamadi." -ScriptBlock { $dcdiagDns = & dcdiag.exe /e /test:DNS 2>&1 $text = $dcdiagDns | Out-String foreach ($line in $dcdiagDns) { Write-VolsysLog "$line" } if ($text -match 'failed test' -or $text -match 'error') { Add-Result -Category "DCDIAG" -Check "DCDIAG DNS" -Status "WARN" -Details "DNS test contains failure/error text" } else { Add-Result -Category "DCDIAG" -Check "DCDIAG DNS" -Status "PASS" -Details "No obvious DNS failure text detected" } Add-DetailSection -Title "DCDIAG DNS" -Lines ($dcdiagDns | ForEach-Object { "$_" })}Safe-Run -OnError "dcdiag SYSVOL testi alinamadi." -ScriptBlock { $dcdiagSysvol = & dcdiag.exe /e /test:sysvolcheck 2>&1 $text = $dcdiagSysvol | Out-String foreach ($line in $dcdiagSysvol) { Write-VolsysLog "$line" } if ($text -match 'failed test' -or $text -match 'error') { Add-Result -Category "DCDIAG" -Check "DCDIAG SYSVOL" -Status "WARN" -Details "SYSVOL test contains failure/error text" } else { Add-Result -Category "DCDIAG" -Check "DCDIAG SYSVOL" -Status "PASS" -Details "No obvious SYSVOL failure text detected" } Add-DetailSection -Title "DCDIAG SYSVOL" -Lines ($dcdiagSysvol | ForEach-Object { "$_" })}Safe-Run -OnError "dcdiag RID testi alinamadi." -ScriptBlock { $dcdiagRid = & dcdiag.exe /test:ridmanager /v 2>&1 $text = $dcdiagRid | Out-String foreach ($line in $dcdiagRid) { Write-VolsysLog "$line" } if ($text -match 'failed test' -or $text -match 'error') { Add-Result -Category "DCDIAG" -Check "DCDIAG RID Manager" -Status "WARN" -Details "RID Manager test contains failure/error text" } else { Add-Result -Category "DCDIAG" -Check "DCDIAG RID Manager" -Status "PASS" -Details "No obvious RID Manager failure text detected" } Add-DetailSection -Title "DCDIAG RID Manager" -Lines ($dcdiagRid | ForEach-Object { "$_" })}# -------------------------------------------------------------------# Per-DC Checks# -------------------------------------------------------------------Write-Section "PER-DC DETAILED CHECKS"foreach ($DC in $DCs) { Write-SubSection "DC DETAIL - $($DC.HostName)" $sectionLines = New-Object System.Collections.Generic.List[string] Safe-Run -OnError "DC detaylari alinamadi: $($DC.HostName)" -ScriptBlock { Write-VolsysLog "HostName : $($DC.HostName)" Write-VolsysLog "Site : $($DC.Site)" Write-VolsysLog "IPv4 : $($DC.IPv4Address)" Write-VolsysLog "Is Global Catalog : $($DC.IsGlobalCatalog)" Write-VolsysLog "Is ReadOnly : $($DC.IsReadOnly)" $sectionLines.Add("HostName: $($DC.HostName)") $sectionLines.Add("Site: $($DC.Site)") $sectionLines.Add("IPv4: $($DC.IPv4Address)") $sectionLines.Add("Is Global Catalog: $($DC.IsGlobalCatalog)") $sectionLines.Add("Is ReadOnly: $($DC.IsReadOnly)") # Ping try { $pingOk = Test-Connection -ComputerName $DC.HostName -Count 2 -Quiet -ErrorAction Stop if ($pingOk) { Add-Result -Category "Connectivity" -Check "Ping $($DC.HostName)" -Status "PASS" -Details "Host reachable" } else { Add-Result -Category "Connectivity" -Check "Ping $($DC.HostName)" -Status "FAIL" -Details "Host unreachable" } Write-VolsysLog "Ping Reachable : $pingOk" $sectionLines.Add("Ping Reachable: $pingOk") } catch { Add-Result -Category "Connectivity" -Check "Ping $($DC.HostName)" -Status "FAIL" -Details $_.Exception.Message Write-VolsysLog "Ping Check Error : $($_.Exception.Message)" $sectionLines.Add("Ping Check Error: $($_.Exception.Message)") } # Shares try { $shares = Get-WmiObject Win32_Share -ComputerName $DC.HostName $sysvolFound = $shares | Where-Object { $_.Name -eq 'SYSVOL' } $netlogonFound = $shares | Where-Object { $_.Name -eq 'NETLOGON' } Write-VolsysLog "SYSVOL Share Present : $([bool]$sysvolFound)" Write-VolsysLog "NETLOGON Share Present : $([bool]$netlogonFound)" $sectionLines.Add("SYSVOL Share Present: $([bool]$sysvolFound)") $sectionLines.Add("NETLOGON Share Present: $([bool]$netlogonFound)") if ($sysvolFound -and $netlogonFound) { Add-Result -Category "SYSVOL" -Check "$($DC.HostName) SYSVOL/NETLOGON shares" -Status "PASS" -Details "Both shares present" } else { Add-Result -Category "SYSVOL" -Check "$($DC.HostName) SYSVOL/NETLOGON shares" -Status "FAIL" -Details "One or both shares missing" } } catch { Add-Result -Category "SYSVOL" -Check "$($DC.HostName) SYSVOL/NETLOGON shares" -Status "WARN" -Details $_.Exception.Message Write-VolsysLog "Share Check Error : $($_.Exception.Message)" $sectionLines.Add("Share Check Error: $($_.Exception.Message)") } # Services try { $serviceNames = 'NTDS','DNS','DFSR','KDC','W32Time','Netlogon' $services = Get-Service -ComputerName $DC.HostName -Name $serviceNames -ErrorAction SilentlyContinue foreach ($svc in $services | Sort-Object Name) { Write-VolsysLog ("Service {0,-25}: {1}" -f $svc.Name, $svc.Status) $sectionLines.Add(("Service {0}: {1}" -f $svc.Name, $svc.Status)) if ($svc.Status -eq 'Running') { Add-Result -Category "Services" -Check "$($DC.HostName) service $($svc.Name)" -Status "PASS" -Details "Running" } else { Add-Result -Category "Services" -Check "$($DC.HostName) service $($svc.Name)" -Status "WARN" -Details "Status: $($svc.Status)" } } } catch { Add-Result -Category "Services" -Check "$($DC.HostName) service query" -Status "WARN" -Details $_.Exception.Message Write-VolsysLog "Service Check Error : $($_.Exception.Message)" $sectionLines.Add("Service Check Error: $($_.Exception.Message)") } # Time try { $w32status = & w32tm.exe /monitor /computers:$($DC.HostName) 2>&1 foreach ($line in $w32status) { Write-VolsysLog "$line" $sectionLines.Add("$line") } Add-Result -Category "Time" -Check "W32Time monitor $($DC.HostName)" -Status "INFO" -Details "Review time monitor output" } catch { Add-Result -Category "Time" -Check "W32Time monitor $($DC.HostName)" -Status "WARN" -Details $_.Exception.Message Write-VolsysLog "Time Check Error : $($_.Exception.Message)" $sectionLines.Add("Time Check Error: $($_.Exception.Message)") } } Add-DetailSection -Title "DC Detail - $($DC.HostName)" -Lines ($sectionLines.ToArray())}# -------------------------------------------------------------------# Event Checks# -------------------------------------------------------------------Write-Section "EVENT HEALTH CHECKS"foreach ($DC in $DCs) { # DFSR Safe-Run -OnError "DFSR eventleri alinamadi: $($DC.HostName)" -ScriptBlock { $dfsrEvents = Get-WinEvent -ComputerName $DC.HostName -FilterHashtable @{ LogName = 'DFS Replication' StartTime = (Get-Date).AddDays(-$DaysBack) } -MaxEvents $EventCount $lines = @() if ($dfsrEvents) { foreach ($evt in $dfsrEvents) { $msg = ($evt.Message -replace "`r`n", ' ') -replace '\s{2,}', ' ' $lines += "[{0}] ID={1} Level={2} Message={3}" -f $evt.TimeCreated, $evt.Id, $evt.LevelDisplayName, $msg } Add-Result -Category "DFSR" -Check "$($DC.HostName) DFSR events" -Status "INFO" -Details "$($dfsrEvents.Count) DFSR events collected" } else { $lines += "No DFSR events found." Add-Result -Category "DFSR" -Check "$($DC.HostName) DFSR events" -Status "PASS" -Details "No DFSR events found in selected range" } Add-DetailSection -Title "DFSR Events - $($DC.HostName)" -Lines $lines } # DNS Server Safe-Run -OnError "DNS eventleri alinamadi: $($DC.HostName)" -ScriptBlock { $dnsEvents = Get-WinEvent -ComputerName $DC.HostName -FilterHashtable @{ LogName = 'DNS Server' StartTime = (Get-Date).AddDays(-$DaysBack) } -MaxEvents $EventCount $lines = @() if ($dnsEvents) { foreach ($evt in $dnsEvents) { $msg = ($evt.Message -replace "`r`n", ' ') -replace '\s{2,}', ' ' $lines += "[{0}] ID={1} Level={2} Message={3}" -f $evt.TimeCreated, $evt.Id, $evt.LevelDisplayName, $msg } Add-Result -Category "DNS Events" -Check "$($DC.HostName) DNS events" -Status "INFO" -Details "$($dnsEvents.Count) DNS Server events collected" } else { $lines += "No DNS Server events found." Add-Result -Category "DNS Events" -Check "$($DC.HostName) DNS events" -Status "PASS" -Details "No DNS Server events found in selected range" } Add-DetailSection -Title "DNS Events - $($DC.HostName)" -Lines $lines } # Directory Service Safe-Run -OnError "Directory Service eventleri alinamadi: $($DC.HostName)" -ScriptBlock { $adEvents = Get-WinEvent -ComputerName $DC.HostName -FilterHashtable @{ LogName = 'Directory Service' StartTime = (Get-Date).AddDays(-$DaysBack) } -MaxEvents $EventCount $lines = @() if ($adEvents) { foreach ($evt in $adEvents) { $msg = ($evt.Message -replace "`r`n", ' ') -replace '\s{2,}', ' ' $lines += "[{0}] ID={1} Level={2} Message={3}" -f $evt.TimeCreated, $evt.Id, $evt.LevelDisplayName, $msg } Add-Result -Category "AD Events" -Check "$($DC.HostName) Directory Service events" -Status "INFO" -Details "$($adEvents.Count) Directory Service events collected" } else { $lines += "No Directory Service events found." Add-Result -Category "AD Events" -Check "$($DC.HostName) Directory Service events" -Status "PASS" -Details "No Directory Service events found in selected range" } Add-DetailSection -Title "Directory Service Events - $($DC.HostName)" -Lines $lines }}# -------------------------------------------------------------------# Object Creation Trend# -------------------------------------------------------------------Write-Section "OBJECT CREATION TREND"Safe-Run -OnError "Obje trend bilgisi alinamadi." -ScriptBlock { $Since = (Get-Date).AddDays(-$DaysBack) $ldapTime = $Since.ToUniversalTime().ToString("yyyyMMddHHmmss.0Z") $RecentUsers = @(Get-ADUser -LDAPFilter "(whenCreated>=$ldapTime)" -Properties whenCreated) $RecentComputers = @(Get-ADComputer -LDAPFilter "(whenCreated>=$ldapTime)" -Properties whenCreated) $RecentGroups = @(Get-ADGroup -LDAPFilter "(whenCreated>=$ldapTime)" -Properties whenCreated) $totalRecent = $RecentUsers.Count + $RecentComputers.Count + $RecentGroups.Count Write-VolsysLog "Since : $Since" Write-VolsysLog "Users Created : $($RecentUsers.Count)" Write-VolsysLog "Computers Created : $($RecentComputers.Count)" Write-VolsysLog "Groups Created : $($RecentGroups.Count)" Write-VolsysLog "Total Security Objects : $totalRecent" if ($totalRecent -ge 1000) { Add-Result -Category "Object Trend" -Check "Recent object creation volume" -Status "WARN" -Details "High object creation volume detected: $totalRecent" } elseif ($totalRecent -ge 250) { Add-Result -Category "Object Trend" -Check "Recent object creation volume" -Status "WARN" -Details "Elevated object creation volume detected: $totalRecent" } else { Add-Result -Category "Object Trend" -Check "Recent object creation volume" -Status "PASS" -Details "Normal object creation volume: $totalRecent" } Add-DetailSection -Title "Object Creation Trend" -Lines @( "Since: $Since", "Users Created: $($RecentUsers.Count)", "Computers Created: $($RecentComputers.Count)", "Groups Created: $($RecentGroups.Count)", "Total Security Objects: $totalRecent" )}# -------------------------------------------------------------------# HTML Report# -------------------------------------------------------------------Write-Section "GENERATING HTML DASHBOARD"$passCount = @($DashboardResults | Where-Object { $_.Status -eq 'PASS' }).Count$warnCount = @($DashboardResults | Where-Object { $_.Status -eq 'WARN' }).Count$failCount = @($DashboardResults | Where-Object { $_.Status -eq 'FAIL' }).Count$infoCount = @($DashboardResults | Where-Object { $_.Status -eq 'INFO' }).Count$totalCount = $DashboardResults.Count$overallStatus = if ($failCount -gt 0) { "FAIL" } elseif ($warnCount -gt 0) { "WARN" } else { "PASS" }$html = New-Object System.Text.StringBuilder[void]$html.AppendLine("<!DOCTYPE html>")[void]$html.AppendLine("<html lang='en'>")[void]$html.AppendLine("<head>")[void]$html.AppendLine("<meta charset='utf-8'>")[void]$html.AppendLine("<meta name='viewport' content='width=device-width, initial-scale=1.0'>")[void]$html.AppendLine("<title>Volsys AD Ultimate Health Check</title>")[void]$html.AppendLine("<style>")[void]$html.AppendLine("body { font-family: Segoe UI, Arial, sans-serif; background:#f5f7fb; margin:0; padding:0; color:#1f2937; }")[void]$html.AppendLine(".header { background:#0f172a; color:white; padding:24px 32px; }")[void]$html.AppendLine(".header h1 { margin:0; font-size:30px; }")[void]$html.AppendLine(".header p { margin:6px 0 0 0; opacity:0.9; }")[void]$html.AppendLine(".container { padding:24px 32px; }")[void]$html.AppendLine(".cards { display:flex; flex-wrap:wrap; gap:16px; margin-bottom:24px; }")[void]$html.AppendLine(".card { background:white; border-radius:14px; padding:18px 20px; box-shadow:0 2px 10px rgba(0,0,0,0.08); min-width:180px; }")[void]$html.AppendLine(".card h3 { margin:0 0 8px 0; font-size:14px; color:#6b7280; text-transform:uppercase; }")[void]$html.AppendLine(".card .value { font-size:28px; font-weight:700; }")[void]$html.AppendLine(".section { background:white; border-radius:14px; padding:20px; box-shadow:0 2px 10px rgba(0,0,0,0.08); margin-bottom:24px; }")[void]$html.AppendLine(".section h2 { margin-top:0; font-size:22px; }")[void]$html.AppendLine("table { width:100%; border-collapse:collapse; }")[void]$html.AppendLine("th, td { text-align:left; padding:10px 12px; border-bottom:1px solid #e5e7eb; vertical-align:top; }")[void]$html.AppendLine("th { background:#f8fafc; }")[void]$html.AppendLine(".badge { display:inline-block; padding:5px 10px; border-radius:999px; font-size:12px; font-weight:700; }")[void]$html.AppendLine(".pass { background:#dcfce7; color:#166534; }")[void]$html.AppendLine(".warn { background:#fef3c7; color:#92400e; }")[void]$html.AppendLine(".fail { background:#fee2e2; color:#991b1b; }")[void]$html.AppendLine(".info { background:#dbeafe; color:#1d4ed8; }")[void]$html.AppendLine(".detail-block { margin-bottom:20px; padding:14px; border:1px solid #e5e7eb; border-radius:12px; background:#fafafa; }")[void]$html.AppendLine(".detail-block h3 { margin-top:0; }")[void]$html.AppendLine("ul { margin:0; padding-left:20px; }")[void]$html.AppendLine("li { margin-bottom:6px; }")[void]$html.AppendLine("</style>")[void]$html.AppendLine("</head>")[void]$html.AppendLine("<body>")[void]$html.AppendLine("<div class='header'>")[void]$html.AppendLine("<h1>Volsys AD Ultimate Health Check</h1>")[void]$html.AppendLine("<p>Generated: $(ConvertTo-HtmlSafe ((Get-Date).ToString()))</p>")[void]$html.AppendLine("<p>Overall Status: <span class='badge $(Get-StatusClass $overallStatus)'>$(ConvertTo-HtmlSafe $overallStatus)</span></p>")[void]$html.AppendLine("</div>")[void]$html.AppendLine("<div class='container'>")[void]$html.AppendLine("<div class='cards'>")[void]$html.AppendLine("<div class='card'><h3>Total Checks</h3><div class='value'>$totalCount</div></div>")[void]$html.AppendLine("<div class='card'><h3>PASS</h3><div class='value'>$passCount</div></div>")[void]$html.AppendLine("<div class='card'><h3>WARN</h3><div class='value'>$warnCount</div></div>")[void]$html.AppendLine("<div class='card'><h3>FAIL</h3><div class='value'>$failCount</div></div>")[void]$html.AppendLine("<div class='card'><h3>INFO</h3><div class='value'>$infoCount</div></div>")[void]$html.AppendLine("</div>")[void]$html.AppendLine("<div class='section'>")[void]$html.AppendLine("<h2>Executive Summary</h2>")[void]$html.AppendLine("<table>")[void]$html.AppendLine("<thead><tr><th>Category</th><th>Check</th><th>Status</th><th>Details</th></tr></thead>")[void]$html.AppendLine("<tbody>")foreach ($row in $DashboardResults) { $cls = Get-StatusClass $row.Status [void]$html.AppendLine("<tr>") [void]$html.AppendLine("<td>$(ConvertTo-HtmlSafe $row.Category)</td>") [void]$html.AppendLine("<td>$(ConvertTo-HtmlSafe $row.Check)</td>") [void]$html.AppendLine("<td><span class='badge $cls'>$(ConvertTo-HtmlSafe $row.Status)</span></td>") [void]$html.AppendLine("<td>$(ConvertTo-HtmlSafe $row.Details)</td>") [void]$html.AppendLine("</tr>")}[void]$html.AppendLine("</tbody></table>")[void]$html.AppendLine("</div>")[void]$html.AppendLine("<div class='section'>")[void]$html.AppendLine("<h2>Detailed Findings</h2>")foreach ($section in $DetailSections) { [void]$html.AppendLine("<div class='detail-block'>") [void]$html.AppendLine("<h3>$(ConvertTo-HtmlSafe $section.Title)</h3>") [void]$html.AppendLine("<ul>") foreach ($line in $section.Lines) { [void]$html.AppendLine("<li>$(ConvertTo-HtmlSafe $line)</li>") } [void]$html.AppendLine("</ul>") [void]$html.AppendLine("</div>")}[void]$html.AppendLine("</div>")[void]$html.AppendLine("</div>")[void]$html.AppendLine("</body>")[void]$html.AppendLine("</html>")[System.IO.File]::WriteAllText($HtmlReport, $html.ToString(), [System.Text.Encoding]::UTF8)Write-VolsysLog "HTML dashboard olusturuldu: $HtmlReport"Write-VolsysLog "TXT rapor olusturuldu : $TxtReport"Write-VolsysLog ("=" * 100)