From 842286d57dd675063b8353fdbffa19e4d8a45036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Eggert=20Lundsteen=20Olsen?= Date: Fri, 2 Oct 2026 13:32:29 +0200 Subject: [PATCH] SQL Scripts for the Windows server and synthetic check rules (SQLI-WIN-001..013, SQLI-SYN-001..003) One reviewable file per rule id with a Danish header: what and why, thresholds with config keys and defaults, severity, required rights (never local administrator), supported versions, collector file and member, and the evaluation in plain Danish. The Windows rules use no SQL: their exact CIM/WQL queries, event log XPath and a read-only PowerShell snippet to verify them are in a comment block. SQLI-SYN-001/002 carry the exact SQL a SQL check runs (session settings, transaction that is always rolled back, SELECT 1). A test checks every server and check rule has its file. Co-Authored-By: Claude Opus 5.5 (1M context) --- SQL Scripts/SQLI-SYN-001.sql | 65 +++++++++++++++++++ SQL Scripts/SQLI-SYN-002.sql | 48 ++++++++++++++ SQL Scripts/SQLI-SYN-003.sql | 39 +++++++++++ SQL Scripts/SQLI-WIN-001.sql | 48 ++++++++++++++ SQL Scripts/SQLI-WIN-002.sql | 47 ++++++++++++++ SQL Scripts/SQLI-WIN-003.sql | 45 +++++++++++++ SQL Scripts/SQLI-WIN-004.sql | 40 ++++++++++++ SQL Scripts/SQLI-WIN-005.sql | 48 ++++++++++++++ SQL Scripts/SQLI-WIN-006.sql | 55 ++++++++++++++++ SQL Scripts/SQLI-WIN-007.sql | 50 ++++++++++++++ SQL Scripts/SQLI-WIN-008.sql | 41 ++++++++++++ SQL Scripts/SQLI-WIN-009.sql | 54 +++++++++++++++ SQL Scripts/SQLI-WIN-010.sql | 42 ++++++++++++ SQL Scripts/SQLI-WIN-011.sql | 39 +++++++++++ SQL Scripts/SQLI-WIN-012.sql | 50 ++++++++++++++ SQL Scripts/SQLI-WIN-013.sql | 44 +++++++++++++ .../ServerRuleScriptTests.cs | 37 +++++++++++ 17 files changed, 792 insertions(+) create mode 100644 SQL Scripts/SQLI-SYN-001.sql create mode 100644 SQL Scripts/SQLI-SYN-002.sql create mode 100644 SQL Scripts/SQLI-SYN-003.sql create mode 100644 SQL Scripts/SQLI-WIN-001.sql create mode 100644 SQL Scripts/SQLI-WIN-002.sql create mode 100644 SQL Scripts/SQLI-WIN-003.sql create mode 100644 SQL Scripts/SQLI-WIN-004.sql create mode 100644 SQL Scripts/SQLI-WIN-005.sql create mode 100644 SQL Scripts/SQLI-WIN-006.sql create mode 100644 SQL Scripts/SQLI-WIN-007.sql create mode 100644 SQL Scripts/SQLI-WIN-008.sql create mode 100644 SQL Scripts/SQLI-WIN-009.sql create mode 100644 SQL Scripts/SQLI-WIN-010.sql create mode 100644 SQL Scripts/SQLI-WIN-011.sql create mode 100644 SQL Scripts/SQLI-WIN-012.sql create mode 100644 SQL Scripts/SQLI-WIN-013.sql create mode 100644 tests/SQLInsight.Rules.Tests/ServerRuleScriptTests.cs diff --git a/SQL Scripts/SQLI-SYN-001.sql b/SQL Scripts/SQLI-SYN-001.sql new file mode 100644 index 0000000..32a41c3 --- /dev/null +++ b/SQL Scripts/SQLI-SYN-001.sql @@ -0,0 +1,65 @@ +/* + SQLI-SYN-001 – Et syntetisk tjek fejler + ======================================== + + Hvad og hvorfor + Agenten gør det, en bruger eller applikation ville gøre – forbinder til en port, henter en side, logger på SQL Server + og kører en forespørgsel, slår et navn op, logger på Dynamics AX – og det fejler. Er tjekket knyttet til en tjeneste + på en Windows-server, og kører tjenesten, siges det direkte: "… svarer ikke, selv om tjenesten kører" – den fejl, + en tjenesteovervågning alene ikke ser. + + Tærskler (agentens appsettings.json og tjekkets indstillinger) + SQLInsight:SyntheticChecks:FailuresBeforeFinding standard 2 (fejl i træk før et fund: ét tabt svar er ingen alarm) + Pr. tjek: interval (standard 300 s, 60–86400) og timeout (standard 15 s, AX 60 s, højst 120). + + Alvor + Høj. + + Rettigheder + TCP, HTTP(S), DNS: ingen ud over netværksadgang fra agentens server. HTTP med Windows-godkendelse: agentens konto. + SQL: login'et i tjekket (agentens Windows-konto eller et SQL-login, hvis adgangskode krypteres til agenten som i 1.3) + skal kunne logge ind og køre forespørgslen; least-privilege-login'et fra grant-least-privilege.sql er nok til standardforespørgslen. + AX-logon: agentens Windows-konto skal være AX-bruger (i firmaet), og .NET Business Connector skal være installeret på + agentens server; ellers testes kun AOS-porten (og resultatet siger det). + Tjenestens tilstand: WMI Remote Enable på root\cimv2 + læseret på Service Control Manager på tjenestens server. + + Understøttede versioner + SQL: SQL Server 2005 og nyere (SqlClient, ODBC-fallback for 2005). AX-logon: AX 2009 (kræver Windows PowerShell + 2.0-motoren) og AX 2012. Windows-tjenester: Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – SyntheticCheckRunner.RunAsync (TcpAsync, HttpAsync, SqlAsync, + DnsAsync, AxAsync), AX-logon: src/SQLInsight.Servers/Synthetic/AxBusinessConnector.cs og ax-logon.ps1. Køres efter + tjekkets interval af src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync, som også slår den tilknyttede + tjenestes tilstand op (CimQueries.SingleServiceQuery). + Regel + src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs – SyntheticCheckFailingRule + + Evaluering + Har de seneste FailuresBeforeFinding kørsler alle fejlet, er det et fund. Titlen siger, om den tilknyttede tjeneste + kører, er stoppet, eller om tjekket blot fejler, med fejlteksten som måling (følsom). + + SQL: Ved et SQL-tjek kører agenten præcis dette på den instans, tjekket peger på (ændrer intet: forespørgslen + valideres som én skrivebeskyttet SELECT, både når den gemmes og før den køres, og køres i en transaktion, der altid + rulles tilbage). Hver GO er en separat kommando på samme forbindelse. +*/ + +-- Variant: SQL-tjek med standardforespørgslen (alle versioner fra SQL Server 2005) +SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +GO +-- Kun hvis tjekket har en database (tjekkets "Database", ] fordoblet): USE []; +BEGIN TRANSACTION; +GO +SELECT 1 +GO +IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; +GO + +/* + Ikke-SQL-tjek, efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + TCP: Test-NetConnection -ComputerName aos01 -Port 2712 + HTTP: Invoke-WebRequest -Uri https://ep.firma.local/ -UseDefaultCredentials -UseBasicParsing | Select-Object StatusCode + DNS: Resolve-DnsName aos01.firma.local + AX: Test-NetConnection -ComputerName aos01 -Port 2712 (logon: se src/SQLInsight.Servers/Synthetic/ax-logon.ps1) + Tjeneste: Get-CimInstance -ComputerName aos01 -Query "SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service WHERE Name = 'AOS60`$01'" +*/ diff --git a/SQL Scripts/SQLI-SYN-002.sql b/SQL Scripts/SQLI-SYN-002.sql new file mode 100644 index 0000000..43b4cc3 --- /dev/null +++ b/SQL Scripts/SQLI-SYN-002.sql @@ -0,0 +1,48 @@ +/* + SQLI-SYN-002 – Et syntetisk tjek svarer langsomt + ================================================= + + Hvad og hvorfor + Tjekket lykkes, men svaret har de seneste gange taget længere end tjekkets grænse. Brugerne oplever det som en langsom + applikation, længe før den holder op med at svare. + + Tærskler (agentens appsettings.json og tjekkets indstillinger) + Pr. tjek: "Langsomt svar over (ms)" (insight.SyntheticChecks.SettingsJson: warnMilliseconds). Uden grænse: "ikke relevant". + SQLInsight:SyntheticChecks:SlowRunsBeforeFinding standard 3 (langsomme svar i træk før et fund) + + Alvor + Middel. + + Rettigheder + Som SQLI-SYN-001. + + Understøttede versioner + Som SQLI-SYN-001. + + Collector + src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – SyntheticCheckRunner.RunAsync (DurationMs: hele tjekket, for + SQL login + forespørgsel), fra src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync. + Regel + src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs – SyntheticCheckSlowRule + + Evaluering + Er de seneste SlowRunsBeforeFinding kørsler alle lykkedes og alle langsommere end grænsen, er det et fund. + + SQL: Et SQL-tjek kører præcis det samme som i SQLI-SYN-001 (svartiden er login plus forespørgsel): +*/ + +-- Variant: SQL-tjek med standardforespørgslen (alle versioner fra SQL Server 2005) +SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +GO +BEGIN TRANSACTION; +GO +SELECT 1 +GO +IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; +GO + +/* + Ikke-SQL-tjek, efterprøv svartiden med PowerShell (skrivebeskyttet): + Measure-Command { Invoke-WebRequest -Uri https://ep.firma.local/ -UseDefaultCredentials -UseBasicParsing } | Select-Object TotalMilliseconds + Measure-Command { Test-NetConnection -ComputerName aos01 -Port 2712 } | Select-Object TotalMilliseconds +*/ diff --git a/SQL Scripts/SQLI-SYN-003.sql b/SQL Scripts/SQLI-SYN-003.sql new file mode 100644 index 0000000..825ea78 --- /dev/null +++ b/SQL Scripts/SQLI-SYN-003.sql @@ -0,0 +1,39 @@ +/* + SQLI-SYN-003 – TLS-certifikatet udløber snart + ============================================== + + Hvad og hvorfor + Når certifikatet på en HTTPS-adresse udløber, afviser browsere og integrationer forbindelsen (eller viser en + sikkerhedsadvarsel), og siden er i praksis nede. Udløbsdatoen læses ved hvert HTTPS-tjek – også når certifikatet + afvises (fx selvsigneret). + + Tærskler (agentens appsettings.json) + SQLInsight:SyntheticChecks:CertificateWarningDays standard 21 (fund når certifikatet udløber inden for så mange dage) + SQLInsight:SyntheticChecks:CertificateCriticalDays standard 7 (Høj inden for så mange dage) + + Alvor + Middel; Høj inden for CertificateCriticalDays; Kritisk når det er udløbet. + + Rettigheder + Ingen ud over netværksadgang fra agentens server til adressen. + + Understøttede versioner + Alle HTTPS-servere (TLS 1.2 og nyere fra agentens server). + + Collector + src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – HttpAsync (RemoteCertificateValidationCallback gemmer + certifikatets NotAfter og Subject), fra src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync. + Regel + src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs – CertificateExpiryRule + + Evaluering + Kun HTTP-tjek med https://. Den nyeste kørsel, der har set et certifikat, bruges: dage til udløb = NotAfter − nu. + Uden set certifikat endnu: "ikke målbar". Andre tjek: "ikke relevant". + + Reglen bruger ikke SQL. Tjekket er en HTTPS GET; filen indeholder kun kommentarer og ændrer intet. + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server): + $c = New-Object System.Net.Sockets.TcpClient('ep.firma.local', 443) + $s = New-Object System.Net.Security.SslStream($c.GetStream(), $false, { $true }) + $s.AuthenticateAsClient('ep.firma.local'); $s.RemoteCertificate.GetExpirationDateString(); $c.Close() +*/ diff --git a/SQL Scripts/SQLI-WIN-001.sql b/SQL Scripts/SQLI-WIN-001.sql new file mode 100644 index 0000000..83abb09 --- /dev/null +++ b/SQL Scripts/SQLI-WIN-001.sql @@ -0,0 +1,48 @@ +/* + SQLI-WIN-001 – CPU-forbruget er højt i længere tid + =================================================== + + Hvad og hvorfor + Serverens processorer har i gennemsnit været næsten fuldt belastet i en længere periode. Alt på serveren bliver + langsommere (forespørgsler, AOS-kald, fildeling, logon). Korte toppe er normale og giver intet fund. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Cpu:HighPercent standard 90 (gennemsnitlig CPU i procent) + SQLInsight:Servers:Cpu:SustainedMinutes standard 15 (perioden gennemsnittet tages over) + Målingerne skal dække mindst 80 % af perioden (en kort top efter et hul tæller ikke). + + Alvor + Høj; Kritisk når gennemsnittet er 98 % eller derover. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + Performance Monitor Users (ydelsestællere) + WMI Enable Account/Remote Enable på root\cimv2 + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere (WS-Man fra Windows Server 2012 / WinRM 3.0; DCOM på alle). + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetPerformanceAsync (CimQueries.ProcessorQuery), + hvert minut (SQLInsight:Servers:Intervals:performance) fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync. + Beregning: src/SQLInsight.Core/Servers/ServerPerformance.cs – ServerPerformanceMath.Cpu. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – ServerCpuRule + + Evaluering + Hvert minut læses tælleren Processor(_Total)\% Processor Time som rå værdi. CPU for minuttet er + 100 × (1 − Δ tomgangstid / Δ tid) mellem to læsninger (PERF_100NSEC_TIMER_INV), altså gennemsnittet over hele + minuttet, ikke et øjebliksbillede. Er gennemsnittet af minutterne i de seneste SustainedMinutes minutter mindst + HighPercent, er det et fund. Uden to læsninger endnu: "ikke målbar". + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT PercentProcessorTime, Timestamp_Sys100NS FROM Win32_PerfRawData_PerfOS_Processor WHERE Name = '_Total' + SELECT NumberOfLogicalProcessors FROM Win32_ComputerSystem + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + $s = New-CimSession -ComputerName SERVER # DCOM: -SessionOption (New-CimSessionOption -Protocol Dcom) + $q = "SELECT PercentProcessorTime, Timestamp_Sys100NS FROM Win32_PerfRawData_PerfOS_Processor WHERE Name = '_Total'" + $a = Get-CimInstance -CimSession $s -Query $q; Start-Sleep -Seconds 60; $b = Get-CimInstance -CimSession $s -Query $q + 100 * (1 - ($b.PercentProcessorTime - $a.PercentProcessorTime) / ($b.Timestamp_Sys100NS - $a.Timestamp_Sys100NS)) +*/ diff --git a/SQL Scripts/SQLI-WIN-002.sql b/SQL Scripts/SQLI-WIN-002.sql new file mode 100644 index 0000000..7392616 --- /dev/null +++ b/SQL Scripts/SQLI-WIN-002.sql @@ -0,0 +1,47 @@ +/* + SQLI-WIN-002 – Serveren har næsten ingen ledig hukommelse + ========================================================== + + Hvad og hvorfor + Når Windows løber tør for ledig hukommelse, flyttes data til sidefilen, alt bliver langsomt, og processer kan fejle + med "out of memory". SQL Server kan blive tvunget til at give hukommelse tilbage. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Memory:AvailablePercent standard 5 (andel ledig af den samlede hukommelse) + SQLInsight:Servers:Memory:AvailableMegabytes standard 1024 (ledig hukommelse i MB) + Begge skal være under grænsen (gennemsnit over 5 minutter), så store SQL Server-hosts, der bevidst har lidt + tilbage, men stadig flere GB, ikke giver fund. + + Alvor + Middel; Høj under 2 % og under 256 MB. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + Performance Monitor Users + WMI Enable Account/Remote Enable på root\cimv2 + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetPerformanceAsync (CimQueries.MemoryQuery) og + Session.GetOperatingSystemAsync (CimQueries.OperatingSystemQuery), hvert minut fra + src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – ServerMemoryRule + + Evaluering + Ledig hukommelse er Memory\Available MBytes; andelen er den i forhold til Win32_OperatingSystem.TotalVisibleMemorySize. + Gennemsnittet over de seneste 5 minutter (mindst 80 % dækket) sammenlignes med begge grænser. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT AvailableMBytes, PagesPersec, CommittedBytes, CommitLimit, Timestamp_PerfTime, Frequency_PerfTime FROM Win32_PerfRawData_PerfOS_Memory + SELECT Caption, Version, BuildNumber, LastBootUpTime, TotalVisibleMemorySize, CSName FROM Win32_OperatingSystem + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + $s = New-CimSession -ComputerName SERVER + $m = Get-CimInstance -CimSession $s -Query "SELECT AvailableMBytes FROM Win32_PerfRawData_PerfOS_Memory" + $o = Get-CimInstance -CimSession $s -Query "SELECT TotalVisibleMemorySize FROM Win32_OperatingSystem" + "{0} MB ledig ({1:N1} %)" -f $m.AvailableMBytes, (100 * $m.AvailableMBytes * 1024 / $o.TotalVisibleMemorySize) +*/ diff --git a/SQL Scripts/SQLI-WIN-003.sql b/SQL Scripts/SQLI-WIN-003.sql new file mode 100644 index 0000000..8faad69 --- /dev/null +++ b/SQL Scripts/SQLI-WIN-003.sql @@ -0,0 +1,45 @@ +/* + SQLI-WIN-003 – Serveren pager hukommelse til disk + ================================================== + + Hvad og hvorfor + Windows læser og skriver hukommelsessider til sidefilen, fordi der ikke er plads i RAM. Det er mange gange + langsommere end hukommelse og belaster disken, som andre også bruger. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Memory:PagesPerSecond standard 1000 (Memory\Pages/sec, gennemsnit over 15 minutter) + Kun sammen med lidt ledig hukommelse (under 10 % i samme periode): Pages/sec alene er også fil-I/O gennem + memory-mapped filer og er ikke i sig selv et problem. + + Alvor + Middel. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + Performance Monitor Users + WMI Enable Account/Remote Enable på root\cimv2 + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetPerformanceAsync (CimQueries.MemoryQuery), hvert minut + fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync. + Beregning: src/SQLInsight.Core/Servers/ServerPerformance.cs – ServerPerformanceMath.PagesPerSecond. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – ServerPagingRule + + Evaluering + Pages/sec er en PERF_COUNTER_COUNTER: (Δ PagesPersec) / (Δ Timestamp_PerfTime / Frequency_PerfTime) mellem to + læsninger. Er gennemsnittet over 15 minutter mindst grænsen, og den ledige andel samtidig under 10 %, er det et fund. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT AvailableMBytes, PagesPersec, CommittedBytes, CommitLimit, Timestamp_PerfTime, Frequency_PerfTime FROM Win32_PerfRawData_PerfOS_Memory + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + $s = New-CimSession -ComputerName SERVER + $q = "SELECT PagesPersec, Timestamp_PerfTime, Frequency_PerfTime FROM Win32_PerfRawData_PerfOS_Memory" + $a = Get-CimInstance -CimSession $s -Query $q; Start-Sleep -Seconds 60; $b = Get-CimInstance -CimSession $s -Query $q + ($b.PagesPersec - $a.PagesPersec) / (($b.Timestamp_PerfTime - $a.Timestamp_PerfTime) / $b.Frequency_PerfTime) +*/ diff --git a/SQL Scripts/SQLI-WIN-004.sql b/SQL Scripts/SQLI-WIN-004.sql new file mode 100644 index 0000000..7d383be --- /dev/null +++ b/SQL Scripts/SQLI-WIN-004.sql @@ -0,0 +1,40 @@ +/* + SQLI-WIN-004 – Den reserverede hukommelse (commit) er tæt på grænsen + ===================================================================== + + Hvad og hvorfor + Commit charge er den hukommelse, programmerne har reserveret (RAM plus sidefil). Når grænsen nås, kan Windows ikke + give mere hukommelse ud, og programmer og tjenester fejler, selv om der måske er ledig RAM. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Memory:CommitPercent standard 90 (CommittedBytes / CommitLimit, gennemsnit over 5 minutter) + + Alvor + Middel; Høj ved 97 % eller derover. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + Performance Monitor Users + WMI Enable Account/Remote Enable på root\cimv2 + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetPerformanceAsync (CimQueries.MemoryQuery), hvert minut + fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – ServerCommitRule + + Evaluering + 100 × CommittedBytes / CommitLimit pr. minut; gennemsnittet over 5 minutter (mindst 80 % dækket) mod grænsen. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT AvailableMBytes, PagesPersec, CommittedBytes, CommitLimit, Timestamp_PerfTime, Frequency_PerfTime FROM Win32_PerfRawData_PerfOS_Memory + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + $s = New-CimSession -ComputerName SERVER + $m = Get-CimInstance -CimSession $s -Query "SELECT CommittedBytes, CommitLimit FROM Win32_PerfRawData_PerfOS_Memory" + 100 * $m.CommittedBytes / $m.CommitLimit +*/ diff --git a/SQL Scripts/SQLI-WIN-005.sql b/SQL Scripts/SQLI-WIN-005.sql new file mode 100644 index 0000000..7747373 --- /dev/null +++ b/SQL Scripts/SQLI-WIN-005.sql @@ -0,0 +1,48 @@ +/* + SQLI-WIN-005 – Lidt ledig plads på et drev + =========================================== + + Hvad og hvorfor + Når et drev løber fuldt, stopper alt, der skriver til det: SQL Server kan ikke vokse data- og logfiler, backup + fejler, AOS og Windows kan ikke skrive logfiler og midlertidige filer, og brugere kan ikke gemme. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Disks:FreePercent standard 10 (ledig andel, under: Middel) + SQLInsight:Servers:Disks:CriticalFreePercent standard 5 (under: Høj) + SQLInsight:Servers:Disks:EnoughFreeGigabytes standard 50 (er der mindst så mange GB ledige, er der intet fund, + uanset andelen: store drev med lille andel ledig kan være fine) + + Alvor + Middel under FreePercent, Høj under CriticalFreePercent, Kritisk under 1 GB eller 1 %. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\cimv2 + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetDisksAsync (CimQueries.VolumeQuery, ellers + CimQueries.LogicalDiskQuery), hvert 15. minut (SQLInsight:Servers:Intervals:disks) fra + src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectDisksAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – DiskFreeSpaceRule + + Evaluering + Lokale diske (DriveType 3) med drevbogstav eller monteringssti; partitioner uden (system/recovery, navn \\?\Volume{…}) + springes over. Ledig andel = FreeSpace / Capacity. Et fund pr. drev, der er under FreePercent og samtidig har + mindre end EnoughFreeGigabytes ledig. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT Name, Label, FileSystem, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3 + SELECT DeviceID, VolumeName, FileSystem, Size, FreeSpace FROM Win32_LogicalDisk WHERE DriveType = 3 (fallback) + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + $s = New-CimSession -ComputerName SERVER + Get-CimInstance -CimSession $s -Query "SELECT Name, Label, FileSystem, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3" | + Where-Object { $_.Name -notlike '\\?\*' } | + Select-Object Name, Label, @{n='LedigGB';e={[math]::Round($_.FreeSpace / 1GB, 1)}}, @{n='Ledig%';e={[math]::Round(100 * $_.FreeSpace / $_.Capacity, 1)}} +*/ diff --git a/SQL Scripts/SQLI-WIN-006.sql b/SQL Scripts/SQLI-WIN-006.sql new file mode 100644 index 0000000..90d16e8 --- /dev/null +++ b/SQL Scripts/SQLI-WIN-006.sql @@ -0,0 +1,55 @@ +/* + SQLI-WIN-006 – Et drev bliver fuldt om få dage + =============================================== + + Hvad og hvorfor + Varsler, at disken løber fuld om et antal dage, før det sker: pladsen på drevet er de seneste uger brugt i et jævnt + tempo, og fortsætter det, er drevet fuldt inden for prognosegrænsen. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Disks:ForecastDays standard 30 (fund når drevet forventes fuldt inden for så mange dage) + SQLInsight:Servers:Disks:ForecastHistoryDays standard 14 (dage med SQLInsights egne målinger, linjen beregnes over) + SQLInsight:Servers:DiskHistoryDays standard 35 (hvor længe målingerne gemmes i insight.ServerDiskSamples) + Faste fornuftsgrænser (src/SQLInsight.Core/Servers/DiskForecast.cs – DiskForecastSettings): mindst 2 dages historik og + 12 målinger, R² mindst 0,5, vækst mindst 0,01 GB pr. dag, højst 365 dage frem. + + Alvor + Middel; Høj inden for 7 dage; Kritisk inden for 2 dage. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\cimv2 + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetDisksAsync (CimQueries.VolumeQuery), hvert 15. minut fra + src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectDisksAsync, som gemmer målingen og beregner prognosen. + Prognose: src/SQLInsight.Core/Servers/DiskForecast.cs – DiskForecaster.Forecast. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – DiskForecastRule + + Evaluering + Ledig plads pr. drev hver 15. minut gemmes i repositoriet. Prognosen tager timegennemsnit af de seneste + ForecastHistoryDays dage – kun siden drevet sidst skiftede størrelse (et udvidet drev starter en ny tendens) – og + lægger en ret linje (mindste kvadraters metode) gennem den ledige plads. Hælder linjen nedad, passer den rimeligt + (R²), og er der nok historik, er "fuld om ca. N dage" = ledig plads nu / forbrug pr. dag. Svinger pladsen op og ned + (backup skrevet og slettet), er der ingen prognose frem for et skræmmende gæt. + + Reglen bruger ikke SQL mod den overvågede server. Forespørgslen mod Windows står herunder, og den forespørgsel, agenten + bruger mod sit eget repository (ikke den overvågede server), står til sidst. Filen indeholder kun kommentarer. + + CIM/WQL (namespace root\cimv2): + SELECT Name, Label, FileSystem, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3 + + Historikken i SQLInsight-repositoriet (src/SQLInsight.Repository/InsightRepository.WindowsServers.cs – GetServerDiskHistoryAsync): + SELECT Volume, DATEADD(hour, DATEDIFF(hour, 0, SampledAt), 0) AS [Hour], MAX(SizeGb), AVG(FreeGb) + FROM insight.ServerDiskSamples WHERE ServerId = @id AND SampledAt >= @from + GROUP BY Volume, DATEADD(hour, DATEDIFF(hour, 0, SampledAt), 0) + ORDER BY Volume, [Hour]; + + Efterprøv med PowerShell (skrivebeskyttet; ledig plads nu): + Get-CimInstance -ComputerName SERVER -Query "SELECT Name, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3" | + Select-Object Name, @{n='LedigGB';e={[math]::Round($_.FreeSpace / 1GB, 1)}} +*/ diff --git a/SQL Scripts/SQLI-WIN-007.sql b/SQL Scripts/SQLI-WIN-007.sql new file mode 100644 index 0000000..a0a73c5 --- /dev/null +++ b/SQL Scripts/SQLI-WIN-007.sql @@ -0,0 +1,50 @@ +/* + SQLI-WIN-007 – En tjeneste, der skal starte automatisk, kører ikke + =================================================================== + + Hvad og hvorfor + En tjeneste med starttypen Automatisk står ikke som kørende. Det, tjenesten gør, sker ikke, og en automatisk + tjeneste, der er stoppet, er oftest gået ned. SQLInsight starter aldrig selv tjenester. + + Tærskler (agentens appsettings.json og serverens indstillinger i SQLInsight Web) + SQLInsight:Servers:Services:Ignore ekstra tjenester, der må være stoppet (navn eller præfiks*) + SQLInsight:Servers:Services:StartupGraceMinutes standard 15 (ingen fund de første minutter efter en genstart) + Indbygget liste over automatiske tjenester, der stopper af sig selv (StoppedAutomaticServiceRule.StopByDesign), + fx sppsvc, gupdate, edgeupdate, MapsBroker, RemoteRegistry, clr_optimization_*, CDPUserSvc_*. + Pr. server: "Tjenester der ignoreres" (insight.WindowsServers.IgnoredServices). Overvågede tjenester (SQLI-WIN-008) + rapporteres dér og ikke her. + + Alvor + Middel. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\cimv2 + læseret (CC LC RP RC) på Service Control Manager + (over netværket må ellers kun administratorer liste tjenester). + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere (DelayedAutoStart læses fra Windows Server 2012; før det uden). + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetServicesAsync (CimQueries.ServiceQuery, ellers + CimQueries.ServiceQueryWithoutDelayed), hvert 5. minut (SQLInsight:Servers:Intervals:services) fra + src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectServicesAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – StoppedAutomaticServiceRule + + Evaluering + Et fund pr. tjeneste med StartMode = 'Auto' og State <> 'Running', som hverken står på den indbyggede liste, i + Ignore, i serverens ignoreringsliste eller i serverens liste over overvågede tjenester. Ingen fund inden for + StartupGraceMinutes efter LastBootUpTime. Viser serveren slet ingen tjenester, er området "ikke målbar" + (manglende læseret på Service Control Manager). + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT Name, DisplayName, State, StartMode, DelayedAutoStart, ExitCode FROM Win32_Service + SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service (før Windows Server 2012) + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + Get-CimInstance -ComputerName SERVER -Query "SELECT Name, DisplayName, State, StartMode, DelayedAutoStart, ExitCode FROM Win32_Service" | + Where-Object { $_.StartMode -eq 'Auto' -and $_.State -ne 'Running' } | Select-Object Name, DisplayName, State, ExitCode +*/ diff --git a/SQL Scripts/SQLI-WIN-008.sql b/SQL Scripts/SQLI-WIN-008.sql new file mode 100644 index 0000000..3b1ea3b --- /dev/null +++ b/SQL Scripts/SQLI-WIN-008.sql @@ -0,0 +1,41 @@ +/* + SQLI-WIN-008 – En overvåget tjeneste kører ikke + ================================================ + + Hvad og hvorfor + Tjenester, der er valgt for serveren i SQLInsight Web (fx AOS60$01 for Dynamics AX, W3SVC for IIS, MSSQLSERVER), + skal køre uanset starttype. Når de ikke gør, er det, de leverer, ikke tilgængeligt. SQLInsight starter aldrig selv tjenester. + + Tærskler + Listen pr. server: "Overvågede tjenester" (insight.WindowsServers.WatchedServices), sat i SQLInsight Web eller API v1. + SQLInsight:Servers:Services:StartupGraceMinutes standard 15 (ingen fund de første minutter efter en genstart) + + Alvor + Høj når tjenesten ikke kører; Middel når den ikke findes (eller ikke kan ses). + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\cimv2 + læseret (CC LC RP RC) på Service Control Manager + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetServicesAsync (CimQueries.ServiceQuery), hvert 5. minut fra + src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectServicesAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – WatchedServiceRule + + Evaluering + For hvert navn på listen findes tjenesten på navn eller visningsnavn. Findes den ikke: fund (Middel). Er State ikke + 'Running': fund (Høj). Uden liste: "ikke relevant". + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT Name, DisplayName, State, StartMode, DelayedAutoStart, ExitCode FROM Win32_Service + SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service WHERE Name = '' (syntetiske tjek) + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + Get-CimInstance -ComputerName SERVER -Query "SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service WHERE Name = 'AOS60`$01'" +*/ diff --git a/SQL Scripts/SQLI-WIN-009.sql b/SQL Scripts/SQLI-WIN-009.sql new file mode 100644 index 0000000..35d003f --- /dev/null +++ b/SQL Scripts/SQLI-WIN-009.sql @@ -0,0 +1,54 @@ +/* + SQLI-WIN-009 – Fejl i Windows' hændelseslog + ============================================ + + Hvad og hvorfor + Fejl og kritiske hændelser i System- og Application-loggen: disk- og filsystemfejl, opbrugte ressourcer, tjenester + der stopper eller ikke starter, programmer der går ned, fejl fra Dynamics AX' AOS – og almindelige fejl, der gentager sig. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:EventLog:RepeatThreshold standard 5 (en almindelig fejl skal ses så mange gange på 24 timer) + SQLInsight:Servers:EventLog:Ignore ekstra støj: "Kilde:id", "Kilde" eller "Kilde*" + SQLInsight:Servers:EventLog:MaxFindings standard 15 (højst så mange fund pr. server, vigtigste først) + SQLInsight:Servers:EventLog:MaxEventsPerCollection standard 2000 (hændelser pr. log pr. indsamling) + Indbygget støjliste (ServerEventAnalysis.DefaultIgnore): DCOM 10016/10010, Schannel 36874/36887/36888, TPM-WMI 1796/1801, + WMI 10, Security-SPP 8198, og SQL Server's egne kilder (MSSQLSERVER, MSSQL$*, SQLSERVERAGENT, SQLAgent$*, + SQLISPackage*), som SQL Server-fejlloggen allerede dækker. Et fund holdes åbent 24 timer efter hændelsen sidst blev set. + + Alvor + Høj: disk/filsystem, ressourcer, niveau Kritisk, tjeneste stoppet 3+ gange. Middel: tjeneste stoppet, program gik ned, + Dynamics AX. Lav: almindelige fejl der gentager sig. (Uventet nedlukning: se SQLI-WIN-010.) + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + Event Log Readers (System- og Application-loggen; aldrig Security-loggen). + Over RPC (MS-EVEN6): firewallreglerne "Remote Event Log Management". Fallback over CIM: WMI Remote Enable på root\cimv2. + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetEventsAsync: EventLogReader med CimQueries.EventXPath, + ellers CimQueries.EventQuery; hvert 5. minut (SQLInsight:Servers:Intervals:events) fra + src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectEventsAsync. Gruppering og støjfilter: + src/SQLInsight.Core/Servers/ServerEvents.cs – ServerEventAnalysis.Group/Recent/Categorize. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – WindowsEventLogRule + + Evaluering + Hændelser med niveau 1 (kritisk) og 2 (fejl) siden sidste indsamling læses fra System og Application. Støj tælles, + men grupperes ikke. Resten grupperes pr. log, kilde og hændelses-id med antal, første og seneste tidspunkt og den + nyeste tekst som eksempel (følsom: vises kun lokalt, [udeladt] i API'et). Grupperne fra de seneste 24 timer lægges + sammen. Vigtige kategorier giver fund med det samme, almindelige fejl først ved RepeatThreshold gentagelser. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + Event Log (MS-EVEN6), XPath pr. log ('System' og 'Application'): + *[System[(Level=1 or Level=2) and TimeCreated[@SystemTime>'2026-10-02T12:00:00.000Z']]] + CIM/WQL fallback (namespace root\cimv2; EventType 1 = fejl, kritiske hændelser rapporteres som fejl): + SELECT Logfile, SourceName, EventCode, EventType, TimeGenerated, RecordNumber, Message FROM Win32_NTLogEvent + WHERE Logfile = 'System' AND EventType = 1 AND TimeGenerated > '20261002120000.000000+000' + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + Get-WinEvent -ComputerName SERVER -LogName System -FilterXPath "*[System[(Level=1 or Level=2) and TimeCreated[timediff(@SystemTime) <= 86400000]]]" | + Group-Object ProviderName, Id | Sort-Object Count -Descending | Select-Object Count, Name +*/ diff --git a/SQL Scripts/SQLI-WIN-010.sql b/SQL Scripts/SQLI-WIN-010.sql new file mode 100644 index 0000000..61b8c1d --- /dev/null +++ b/SQL Scripts/SQLI-WIN-010.sql @@ -0,0 +1,42 @@ +/* + SQLI-WIN-010 – Serveren er genstartet + ====================================== + + Hvad og hvorfor + Serveren er genstartet det seneste døgn. Uventet (strøm, blå skærm, hård nulstilling) afbryder alt midt i det, og + databaser og AX skal gendanne sig selv; en planlagt genstart (fx Windows-opdateringer) er kun til orientering. + + Tærskler + Fast: 24 timer efter LastBootUpTime (ServerEventAnalysis.RecentWindow), derefter forsvinder fundet af sig selv. + + Alvor + Høj ved uventet genstart; Info ved genstart uden tegn på at den var uventet. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\cimv2 (starttidspunkt); Event Log Readers (hvorfor). + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetOperatingSystemAsync (CimQueries.OperatingSystemQuery) og + Session.GetEventsAsync, fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync og CollectEventsAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – ServerRestartRule + + Evaluering + Er LastBootUpTime inden for 24 timer, er serveren genstartet. Er der i hændelsesloggen (seneste 24 timer) en hændelse i + kategorien "uventet nedlukning" – Microsoft-Windows-Kernel-Power 41, EventLog 6008, BugCheck/WER-SystemErrorReporting 1001 – + senest set tidligst en time før starttidspunktet, er genstarten uventet (Høj), ellers Info. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT Caption, Version, BuildNumber, LastBootUpTime, TotalVisibleMemorySize, CSName FROM Win32_OperatingSystem + Event Log (MS-EVEN6), XPath for System: + *[System[(Level=1 or Level=2) and TimeCreated[@SystemTime>'2026-10-02T12:00:00.000Z']]] + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + (Get-CimInstance -ComputerName SERVER -Query "SELECT LastBootUpTime FROM Win32_OperatingSystem").LastBootUpTime + Get-WinEvent -ComputerName SERVER -FilterHashtable @{ LogName = 'System'; Id = 41, 6008, 1001, 1074; StartTime = (Get-Date).AddDays(-1) } +*/ diff --git a/SQL Scripts/SQLI-WIN-011.sql b/SQL Scripts/SQLI-WIN-011.sql new file mode 100644 index 0000000..ff52f32 --- /dev/null +++ b/SQL Scripts/SQLI-WIN-011.sql @@ -0,0 +1,39 @@ +/* + SQLI-WIN-011 – Serveren er ikke genstartet i lang tid + ====================================================== + + Hvad og hvorfor + De fleste Windows-opdateringer kræver en genstart. En server, der ikke er genstartet i flere måneder, mangler derfor + næsten sikkert sikkerhedsopdateringer. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:UptimeDays standard 0 = slået fra (fx 120 for et fund efter 120 dage uden genstart) + + Alvor + Lav. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\cimv2 + WS-Man: Remote Management Users · DCOM: Distributed COM Users + + Understøttede versioner + Windows Server 2008 R2 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetOperatingSystemAsync (CimQueries.OperatingSystemQuery), + fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – ServerUptimeRule + + Evaluering + Oppetid = nu − LastBootUpTime. Er UptimeDays større end 0, og oppetiden mindst så mange dage, er det et fund. + Med UptimeDays = 0 er reglen "ikke relevant". + + Reglen bruger ikke SQL. Forespørgslen mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\cimv2): + SELECT Caption, Version, BuildNumber, LastBootUpTime, TotalVisibleMemorySize, CSName FROM Win32_OperatingSystem + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + (Get-Date) - (Get-CimInstance -ComputerName SERVER -Query "SELECT LastBootUpTime FROM Win32_OperatingSystem").LastBootUpTime +*/ diff --git a/SQL Scripts/SQLI-WIN-012.sql b/SQL Scripts/SQLI-WIN-012.sql new file mode 100644 index 0000000..56cd68f --- /dev/null +++ b/SQL Scripts/SQLI-WIN-012.sql @@ -0,0 +1,50 @@ +/* + SQLI-WIN-012 – En planlagt opgave fejlede sidste gang, den kørte + ================================================================= + + Hvad og hvorfor + En opgave i Opgavestyring (Task Scheduler) sluttede med en fejlkode. Planlagte opgaver er ofte oprydning, eksport, + integrationer eller filbackup: når de fejler, opdager ingen det, før noget mangler. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Tasks:IncludeMicrosoftTasks standard false (Microsofts egne opgaver under \Microsoft\ overvåges ikke) + SQLInsight:Servers:Tasks:Ignore opgaver der aldrig overvåges (sti\navn eller præfiks*) + SQLInsight:Servers:Tasks:MaxWatched standard 50 (højst så mange opgaver pr. server) + Resultater, der ikke er fejl: 0x0, 0x41300 (klar), 0x41301 (kører), 0x41302 (deaktiveret), 0x41303 (har ikke kørt), + 0x41304 (ingen flere kørsler), 0x41325 (i kø), 0x8004131F (kørte allerede) – src/SQLInsight.Core/Servers/ServerTasks.cs. + + Alvor + Middel. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\Microsoft\Windows\TaskScheduler. Agenten ser kun opgaver, hvis egne + sikkerhedsindstillinger tillader kontoen at læse dem. Seneste resultat læses med Task Schedulers GetInfo (et + skrivebeskyttet CIM-metodekald, som Get-ScheduledTaskInfo); over WinRM kræver metodekald, at kontoen også har + Execute-ret i WinRM – ellers bruges DCOM. + + Understøttede versioner + Windows Server 2012 og nyere (navnerummet TaskScheduler findes ikke på 2008 R2: "ikke målbar"). + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetTasksAsync (CimQueries.TaskQuery og + PS_ScheduledTask.GetInfoByName), hvert 15. minut (SQLInsight:Servers:Intervals:tasks) fra + src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectTasksAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – FailedScheduledTaskRule + + Evaluering + Et fund pr. aktiveret, overvåget opgave, hvis LastTaskResult er en fejl. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\Microsoft\Windows\TaskScheduler): + SELECT TaskName, TaskPath, State FROM MSFT_ScheduledTask + CIM-metode (skrivebeskyttet) pr. overvåget opgave: + PS_ScheduledTask.GetInfoByName(TaskName, TaskPath) -> cmdletOutput: MSFT_TaskDynamicInfo + (LastRunTime, LastTaskResult, NextRunTime, NumberOfMissedRuns) + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + $s = New-CimSession -ComputerName SERVER + Get-ScheduledTask -CimSession $s | Where-Object TaskPath -notlike '\Microsoft\*' | Get-ScheduledTaskInfo -CimSession $s | + Select-Object TaskPath, TaskName, LastRunTime, @{n='Resultat';e={'0x{0:X}' -f $_.LastTaskResult}}, NextRunTime, NumberOfMissedRuns +*/ diff --git a/SQL Scripts/SQLI-WIN-013.sql b/SQL Scripts/SQLI-WIN-013.sql new file mode 100644 index 0000000..a213b4a --- /dev/null +++ b/SQL Scripts/SQLI-WIN-013.sql @@ -0,0 +1,44 @@ +/* + SQLI-WIN-013 – En planlagt opgave kørte ikke, da den skulle + ============================================================ + + Hvad og hvorfor + Opgaven skulle have kørt, men gjorde det ikke: Opgavestyring kørte ikke, betingelserne var ikke opfyldt (fx "kun når + brugeren er logget på"), eller serveren var slukket. Det, opgaven gør, er ikke sket. + + Tærskler (agentens appsettings.json) + SQLInsight:Servers:Tasks:LateMinutes standard 60 (næste kørsel mere end så mange minutter i fortiden) + SQLInsight:Servers:Tasks:IncludeMicrosoftTasks standard false + SQLInsight:Servers:Tasks:Ignore opgaver der aldrig overvåges + + Alvor + Middel. + + Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) + WMI Enable Account/Remote Enable på root\Microsoft\Windows\TaskScheduler (se SQLI-WIN-012 om GetInfo over WinRM). + + Understøttede versioner + Windows Server 2012 og nyere. + + Collector + src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetTasksAsync (CimQueries.TaskQuery og + PS_ScheduledTask.GetInfoByName), hvert 15. minut fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectTasksAsync. + Regel + src/SQLInsight.Rules/Servers/WindowsServerRules.cs – MissedScheduledTaskRule + + Evaluering + Et fund pr. aktiveret, overvåget opgave, der ikke kører nu, og hvor enten NumberOfMissedRuns > 0, eller NextRunTime + ligger mere end LateMinutes i fortiden, uden at LastRunTime er efter det tidspunkt. + + Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet. + + CIM/WQL (namespace root\Microsoft\Windows\TaskScheduler): + SELECT TaskName, TaskPath, State FROM MSFT_ScheduledTask + CIM-metode (skrivebeskyttet) pr. overvåget opgave: + PS_ScheduledTask.GetInfoByName(TaskName, TaskPath) -> cmdletOutput: MSFT_TaskDynamicInfo + + Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): + $s = New-CimSession -ComputerName SERVER + Get-ScheduledTask -CimSession $s | Where-Object { $_.TaskPath -notlike '\Microsoft\*' -and $_.State -ne 'Disabled' } | + Get-ScheduledTaskInfo -CimSession $s | Where-Object { $_.NumberOfMissedRuns -gt 0 -or ($_.NextRunTime -and $_.NextRunTime -lt (Get-Date).AddMinutes(-60)) } +*/ diff --git a/tests/SQLInsight.Rules.Tests/ServerRuleScriptTests.cs b/tests/SQLInsight.Rules.Tests/ServerRuleScriptTests.cs new file mode 100644 index 0000000..776fa40 --- /dev/null +++ b/tests/SQLInsight.Rules.Tests/ServerRuleScriptTests.cs @@ -0,0 +1,37 @@ +using SQLInsight.Rules.Servers; + +namespace SQLInsight.Rules.Tests; + +/// Every Windows server and synthetic check rule has its reviewable script in SQL Scripts/ (named by its id). +public class ServerRuleScriptTests +{ + private static DirectoryInfo Scripts() + { + for (var directory = new DirectoryInfo(AppContext.BaseDirectory); directory is not null; directory = directory.Parent) + { + var candidate = new DirectoryInfo(Path.Combine(directory.FullName, "SQL Scripts")); + if (candidate.Exists) + { + return candidate; + } + } + + throw new DirectoryNotFoundException("SQL Scripts/ blev ikke fundet over testens mappe."); + } + + [Fact] + public void Every_server_and_check_rule_has_a_script_with_its_id_and_title() + { + var folder = Scripts(); + + Assert.All(ServerRuleCatalog.All, rule => + { + var file = Path.Combine(folder.FullName, rule.Id + ".sql"); + Assert.True(File.Exists(file), $"{rule.Id}.sql mangler i SQL Scripts/."); + var text = File.ReadAllText(file); + Assert.Contains($"{rule.Id} – {rule.Title}", text, StringComparison.Ordinal); + Assert.Contains("Evaluering", text, StringComparison.Ordinal); + Assert.DoesNotContain("sysadmin", text, StringComparison.OrdinalIgnoreCase); + }); + } +}