Review 1.5: SQL Scripts for Windows servers and synthetic checks follow main's structure and registry
After the rebase onto 1.4 the 16 SQLI-WIN/SQLI-SYN scripts had their own /* */ format, so SqlScriptTests (rule ids, review header, -- Kilde: blocks) failed. - The scripts have main's header (Regel-id, Titel, Alvor, Versioner, Vurdering, Grænseværdier, Rettigheder, Data kommer fra, Regelkode, Read-only); the Windows WQL/XPath stays word for word in comments. - The synthetic SQL check's SQL is registered (SyntheticCheckRunner.UseDatabaseSql, BeginTransactionSql, RollbackSql, SyntheticCheckSettings.DefaultQuery) and shown as -- Kilde: blocks in SQLI-SYN-001/002 and _collectors/SyntheticCheckRunner.sql. - SqlScriptTests know ServerRuleCatalog; only those rules may be without SQL blocks. - ServerScriptTests: every CimQueries query/filter is in a SQLI-WIN script word for word. - The SQL check cancels the rest of a large answer instead of draining it on close. - Rule counts: README (108 built-in: 92 SQL Server + 13 Windows + 3 synthetic), SQL Scripts/README (rule table, 124 rules, Windows/synthetic section), RuleCatalogTests, CONTRIBUTING (how to add a server rule). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8d092b6a35
commit
cb99778a3f
27 changed files with 1021 additions and 733 deletions
|
|
@ -40,6 +40,8 @@ Warnings behandles som fejl, og .NET-analyzers kører på niveauet `latest-recom
|
|||
5. Registrér reglen i `BuiltInRules`.
|
||||
6. Tilføj `SQL Scripts/<id>.sql` med den danske header (hvad, vurdering, grænser, alvor, rettigheder, versioner, collector) og collectorens SQL, ordret og med en `-- Kilde:`-linje pr. variant. Brug en eksisterende fil som skabelon. `SqlScriptTests` fejler, hvis filen mangler, eller hvis SQL'en ikke længere er den, koden sender.
|
||||
|
||||
En regel om en Windows-server eller et syntetisk tjek (fra 1.5, `SQLI-WIN-…`/`SQLI-SYN-…`) implementerer `IScopedRule<TContext>` i `src/SQLInsight.Rules/Servers/` og registreres i `WindowsServerRules.Create()` eller `SyntheticCheckRules.Create()` (dermed i `ServerRuleCatalog`). Dens `SQL Scripts/<id>.sql` har samme header; forespørgslerne mod Windows står ordret i kommentarer og skal stå i `src/SQLInsight.Servers/CimQueries.cs` (`ServerScriptTests` tjekker det). Agenten må kun læse: CIM-`SELECT`, hændelsesloggen og skrivebeskyttede metoder som Task Schedulers `GetInfoByName`, aldrig start/stop eller ændringer.
|
||||
|
||||
### Uden C#: community-regler
|
||||
|
||||
Mange regler kan skrives som en SQL-forespørgsel i en JSON-fil under `rules/community/`. De kræver ingen C# og kan afprøves direkte mod en instans med `SQLInsight.Agent rules test`. Se [docs/regler.md](docs/regler.md). Også en community-regel skal have sin `SQL Scripts/<id>.sql` med forespørgslen ordret (se fx `SQL Scripts/COM-SEC-001.sql`).
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
SQLInsight Pro er et overvågningsværktøj til Microsoft SQL Server, skrevet i C# på .NET. Det kører hos kunden og forlader ikke netværket, medmindre kunden selv vælger det. Værktøjet nøjes ikke med at vise tal. Det forklarer, hvad der er galt, hvorfor det er et problem, og hvordan det løses. Rådene har samme niveau som dem, man får fra en erfaren DBA.
|
||||
|
||||
> **Status:** Fase 1–4 er implementeret: agent, 92 indbyggede regler plus community-regler, notifikationer, lokalt repository og web-UI, licenser, signerede opdateringer, SQLInsight Hub med portal, erfaring på tværs af kunder, PDF-rapporter og integration med Prometheus, Grafana og SCOM, plus MSI-installer, community-websted og Discourse-forum. Se [installation](docs/installation.md), [opdateringer](docs/opdatering.md), [integration](docs/integration.md), [rapporter](docs/rapporter.md), [egne regler](docs/regler.md), [Dynamics AX](docs/dynamics-ax.md), [databehandling](docs/databehandling.md), [community](docs/community.md), [Roadmap](#roadmap) og [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
> **Status:** Fase 1–4 er implementeret: agent, 108 indbyggede regler (92 for SQL Server; fra 1.5 også 13 for Windows-servere og 3 for syntetiske tjek) plus community-regler, notifikationer, lokalt repository og web-UI, licenser, signerede opdateringer, SQLInsight Hub med portal, erfaring på tværs af kunder, PDF-rapporter og integration med Prometheus, Grafana og SCOM, plus MSI-installer, community-websted og Discourse-forum. Se [installation](docs/installation.md), [opdateringer](docs/opdatering.md), [integration](docs/integration.md), [rapporter](docs/rapporter.md), [egne regler](docs/regler.md), [Dynamics AX](docs/dynamics-ax.md), [Windows-servere](docs/windows-servere.md), [syntetiske tjek](docs/syntetiske-tjek.md), [databehandling](docs/databehandling.md), [community](docs/community.md), [Roadmap](#roadmap) og [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ rettigheder, på hvilke versioner, og hvordan reglen bagefter vurderer data.
|
|||
Agenten kører **ikke** filerne her. De er en læsbar kopi af SQL'en i koden, og unit tests sikrer, at kopien er
|
||||
identisk med koden (se [Hold mappen i sync](#hold-mappen-i-sync)).
|
||||
|
||||
Fra 1.5 har også reglerne for Windows-servere (`SQLI-WIN-…`) og syntetiske tjek (`SQLI-SYN-…`) en fil her, med samme
|
||||
header. De fleste af dem sender ingen SQL: forespørgslerne mod Windows (CIM/WQL og hændelseslogsfilteret) står ordret i
|
||||
kommentarer, så de kan gennemgås på samme måde (se [Windows-servere og syntetiske tjek](#windows-servere-og-syntetiske-tjek-fra-15)).
|
||||
|
||||
## Navngivning
|
||||
|
||||
| Fil | Indhold |
|
||||
|
|
@ -16,6 +20,7 @@ identisk med koden (se [Hold mappen i sync](#hold-mappen-i-sync)).
|
|||
| `_collectors/InstanceProbe.sql` | Registreringen af instansen (version, udgave, Always On) og de sessionsindstillinger, agenten sætter på hver forbindelse. |
|
||||
| `_collectors/AxDatabaseDetector.sql`, `_collectors/AxBatchCollector.sql`, `_collectors/AxSequenceCollector.sql` | Dynamics AX (fra 1.4): den fælles AX-genkendelse og læsningen af batchjob, nummerserier og RecId i AX-databasen. AX-forespørgslerne er vist for hver AX-version, SQLInsight har et skema for (Axapta 3.0, AX 4.0, AX 2009 og AX 2012), og for databasen `AXDB`. |
|
||||
| `_collectors/DatabaseDiscovery.sql`, `_collectors/PermissionCheck.sql` | Søgningen efter databaser (med Dynamics AX-genkendelse) og forbindelsestesten med rettighedstjek under *Servere og databaser* (fra 1.3). De køres kun, når der bedes om dem i webbrugerfladen, og søgningen desuden hver time. |
|
||||
| `_collectors/SyntheticCheckRunner.sql` | Det syntetiske SQL-tjek (fra 1.5): sessionsindstillingerne, `USE`, transaktionen og standardforespørgslen. Tjekkets egen forespørgsel køres i stedet for `SELECT 1`, og transaktionen rulles altid tilbage. |
|
||||
|
||||
## Opbygning af en regelfil
|
||||
|
||||
|
|
@ -75,15 +80,28 @@ Bemærk:
|
|||
(fx baseline-historikken bag `SQLI-ANOM-001`, som ikke hentes fra den overvågede server) og kundens lokale regler
|
||||
(`LOCAL-…`).
|
||||
|
||||
## Windows-servere og syntetiske tjek (fra 1.5)
|
||||
|
||||
- **`SQLI-WIN-…`** sender ingen SQL. Filen har samme header som de andre regler (rettighederne er dem, som
|
||||
`db/permissions/grant-windows-server.ps1` giver agentens konto, aldrig lokal administrator) og viser derefter, i
|
||||
kommentarer, de præcise CIM/WQL-forespørgsler (kun `SELECT`), XPath-filteret til hændelsesloggen og det eneste
|
||||
metodekald, Task Schedulers skrivebeskyttede `GetInfoByName`, samt PowerShell til at efterprøve dem. Agenten starter,
|
||||
stopper eller ændrer intet på serveren. Filerne kan åbnes i SSMS, men gør intet.
|
||||
- **`SQLI-SYN-001` og `SQLI-SYN-002`** viser præcis det, et syntetisk SQL-tjek sender: sessionsindstillingerne, `USE`
|
||||
(kun med en database), `BEGIN TRANSACTION`, forespørgslen (standard `SELECT 1`) og `IF @@TRANCOUNT > 0 ROLLBACK
|
||||
TRANSACTION`, der altid køres bagefter. En egen forespørgsel skal være én skrivebeskyttet SELECT
|
||||
(`src/SQLInsight.Core/CustomRules/ReadOnlyQuery.cs`). TCP-, HTTP-, DNS- og AX-tjek sender ingen SQL.
|
||||
- **`SQLI-SYN-003`** (TLS-certifikatet) sender ingen SQL.
|
||||
|
||||
## Hold mappen i sync
|
||||
|
||||
`tests/SQLInsight.Collectors.Tests/SqlScripts/SqlScriptTests.cs` fejler, hvis mappen og koden ikke stemmer overens:
|
||||
|
||||
- `Every_registered_rule_has_a_script_and_every_script_a_rule`: hver indbygget regel (`BuiltInRules`) og hver
|
||||
community-regel i regelpakken har en `<id>.sql`, og der er ingen filer for ukendte id'er.
|
||||
- `Every_registered_rule_has_a_script_and_every_script_a_rule`: hver indbygget regel (`BuiltInRules` og, fra 1.5,
|
||||
`ServerRuleCatalog`) og hver community-regel i regelpakken har en `<id>.sql`, og der er ingen filer for ukendte id'er.
|
||||
- `Scripts_contain_the_current_sql_from_the_code`: hver blok med `-- Kilde: <nøgle>` indeholder SQL'en, som koden
|
||||
bygger den i dag, ordret (nøglerne står i `SqlScriptSources.cs`). Kun værdier, agenten beregner ved kørsel, må stå
|
||||
anderledes.
|
||||
anderledes. Kun Windows-server- og syntetiske-tjek-reglerne må være uden SQL-blokke.
|
||||
- `Every_collector_query_is_registered_and_in_a_collector_script`: hver SQL-konstant og hver `Build…Sql`-metode i
|
||||
collectorerne er registreret, og hver registreret forespørgsel står i et `_collectors/`-script.
|
||||
- `Community_rule_scripts_contain_the_rule_query_verbatim`: community-reglens `query` fra JSON står ordret i filen.
|
||||
|
|
@ -91,7 +109,11 @@ Bemærk:
|
|||
`EXEC [db].sys.sp_executesql N'…'`.
|
||||
- `tests/SQLInsight.Collectors.Tests/SqlScriptTests.cs` (Dynamics AX): hver AX-regel og AX-collector viser SQL'en for alle
|
||||
AX-versioner, og headeren siger, hvad der ikke er verificeret mod kundedata.
|
||||
en collectors SQL ændret, kan blokkene skrives om fra koden: kør testene med `SQLINSIGHT_UPDATE_SQL_SCRIPTS=1`
|
||||
- `tests/SQLInsight.Servers.Tests/ServerScriptTests.cs` (fra 1.5): hver CIM/WQL-forespørgsel og hvert
|
||||
hændelseslogsfilter i `src/SQLInsight.Servers/CimQueries.cs` står ordret i en `SQLI-WIN-…`-fil, og hver af filerne viser
|
||||
mindst én af dem. `tests/SQLInsight.Rules.Tests/ServerRuleScriptTests.cs`: regel-id og titel i headeren er reglens.
|
||||
|
||||
Er en collectors SQL ændret, kan blokkene skrives om fra koden: kør testene med `SQLINSIGHT_UPDATE_SQL_SCRIPTS=1`
|
||||
(kommentarlinjerne bevares). Blokke med værdier, agenten beregner ved kørsel (⟪…⟫), udfyldes kun, når de er nye; værdien så sættes ind i hånden.
|
||||
|
||||
En ny regel skal derfor have sin `SQL Scripts/<id>.sql` (se `CONTRIBUTING.md`). Ændres en collectors SQL, peger
|
||||
|
|
@ -99,7 +121,7 @@ testen på de filer, der skal opdateres.
|
|||
|
||||
## Regler
|
||||
|
||||
108 regler: 92 indbyggede (C#) og 16 community-regler (JSON).
|
||||
124 regler: 108 indbyggede (C#: 92 for SQL Server, 13 for Windows-servere og 3 for syntetiske tjek, fra 1.5) og 16 community-regler (JSON).
|
||||
|
||||
| Regel-id | Fil | Titel | Collector(s) | Alvor |
|
||||
|---|---|---|---|---|
|
||||
|
|
@ -181,6 +203,9 @@ testen på de filer, der skal opdateres.
|
|||
| SQLI-STAT-001 | [SQLI-STAT-001.sql](SQLI-STAT-001.sql) | Forældede statistikker på store tabeller | IndexCollector | Low |
|
||||
| SQLI-STAT-002 | [SQLI-STAT-002.sql](SQLI-STAT-002.sql) | Automatisk statistik er slået fra | DatabaseCollector | Medium |
|
||||
| SQLI-SVC-001 | [SQLI-SVC-001.sql](SQLI-SVC-001.sql) | En SQL Server-tjeneste, der skal starte automatisk, kører ikke | InstanceConfigurationCollector | High |
|
||||
| SQLI-SYN-001 | [SQLI-SYN-001.sql](SQLI-SYN-001.sql) | Et syntetisk tjek fejler | SyntheticCheckRunner | High. |
|
||||
| SQLI-SYN-002 | [SQLI-SYN-002.sql](SQLI-SYN-002.sql) | Et syntetisk tjek svarer langsomt | SyntheticCheckRunner | Medium. |
|
||||
| SQLI-SYN-003 | [SQLI-SYN-003.sql](SQLI-SYN-003.sql) | TLS-certifikatet udløber snart | SyntheticCheckRunner (HTTPS, ingen SQL) | Medium; High inden for CertificateCriticalDays; Critical når det er udløbet. |
|
||||
| SQLI-TEMP-001 | [SQLI-TEMP-001.sql](SQLI-TEMP-001.sql) | Version store i tempdb er stor eller vokser | TempdbCollector | Medium |
|
||||
| SQLI-TEMP-002 | [SQLI-TEMP-002.sql](SQLI-TEMP-002.sql) | tempdb er næsten fuld | TempdbCollector | High |
|
||||
| SQLI-TEMP-003 | [SQLI-TEMP-003.sql](SQLI-TEMP-003.sql) | Session bruger meget tempdb i lang tid | TempdbCollector | Medium |
|
||||
|
|
@ -195,6 +220,19 @@ testen på de filer, der skal opdateres.
|
|||
| SQLI-WAIT-005 | [SQLI-WAIT-005.sql](SQLI-WAIT-005.sql) | Commits venter på langsom skrivning til transaktionsloggen | WaitStatsCollector | Medium; High fra 15 ms i gennemsnit. |
|
||||
| SQLI-WAIT-006 | [SQLI-WAIT-006.sql](SQLI-WAIT-006.sql) | Parallelle forespørgsler venter meget på hinanden | WaitStatsCollector | Medium; High fra 16 ventende tasks i gennemsnit. |
|
||||
| SQLI-WAIT-007 | [SQLI-WAIT-007.sql](SQLI-WAIT-007.sql) | Contention på sider i hukommelsen (PAGELATCH) | WaitStatsCollector | Medium; High fra 4 ventende tasks i gennemsnit. |
|
||||
| SQLI-WIN-001 | [SQLI-WIN-001.sql](SQLI-WIN-001.sql) | CPU-forbruget er højt i længere tid | CimWindowsServerSource (Windows, ingen SQL) | High; Critical når gennemsnittet er 98 % eller derover. |
|
||||
| SQLI-WIN-002 | [SQLI-WIN-002.sql](SQLI-WIN-002.sql) | Serveren har næsten ingen ledig hukommelse | CimWindowsServerSource (Windows, ingen SQL) | Medium; High under 2 % og under 256 MB. |
|
||||
| SQLI-WIN-003 | [SQLI-WIN-003.sql](SQLI-WIN-003.sql) | Serveren pager hukommelse til disk | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| SQLI-WIN-004 | [SQLI-WIN-004.sql](SQLI-WIN-004.sql) | Den reserverede hukommelse (commit) er tæt på grænsen | CimWindowsServerSource (Windows, ingen SQL) | Medium; High ved 97 % eller derover. |
|
||||
| SQLI-WIN-005 | [SQLI-WIN-005.sql](SQLI-WIN-005.sql) | Lidt ledig plads på et drev | CimWindowsServerSource (Windows, ingen SQL) | Medium under FreePercent, High under CriticalFreePercent, Critical under 1 GB eller 1 %. |
|
||||
| SQLI-WIN-006 | [SQLI-WIN-006.sql](SQLI-WIN-006.sql) | Et drev bliver fuldt om få dage | CimWindowsServerSource (Windows, ingen SQL) | Medium; High inden for 7 dage; Critical inden for 2 dage. |
|
||||
| SQLI-WIN-007 | [SQLI-WIN-007.sql](SQLI-WIN-007.sql) | En tjeneste, der skal starte automatisk, kører ikke | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| SQLI-WIN-008 | [SQLI-WIN-008.sql](SQLI-WIN-008.sql) | En overvåget tjeneste kører ikke | CimWindowsServerSource (Windows, ingen SQL) | High når tjenesten ikke kører; Medium når den ikke findes (eller ikke kan ses). |
|
||||
| SQLI-WIN-009 | [SQLI-WIN-009.sql](SQLI-WIN-009.sql) | Fejl i Windows' hændelseslog | CimWindowsServerSource (Windows, ingen SQL) | High: disk/filsystem, ressourcer, niveau Critical, tjeneste stoppet 3+ gange. Medium: tjeneste stoppet, program gik ned, Dynamics AX. Low: almindelige fejl der gentager sig. (Uventet nedlukning: se SQLI-WIN-010.) |
|
||||
| SQLI-WIN-010 | [SQLI-WIN-010.sql](SQLI-WIN-010.sql) | Serveren er genstartet | CimWindowsServerSource (Windows, ingen SQL) | High ved uventet genstart; Info ved genstart uden tegn på at den var uventet. |
|
||||
| SQLI-WIN-011 | [SQLI-WIN-011.sql](SQLI-WIN-011.sql) | Serveren er ikke genstartet i lang tid | CimWindowsServerSource (Windows, ingen SQL) | Low. |
|
||||
| SQLI-WIN-012 | [SQLI-WIN-012.sql](SQLI-WIN-012.sql) | En planlagt opgave fejlede sidste gang, den kørte | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| SQLI-WIN-013 | [SQLI-WIN-013.sql](SQLI-WIN-013.sql) | En planlagt opgave kørte ikke, da den skulle | CimWindowsServerSource (Windows, ingen SQL) | Medium. |
|
||||
| COM-AX-001 | [COM-AX-001.sql](COM-AX-001.sql) | Dynamics AX 3.0 er uden support fra Microsoft | CustomQueryCollector | Medium |
|
||||
| COM-AX-002 | [COM-AX-002.sql](COM-AX-002.sql) | Dynamics AX 3.0 kører på en SQL Server-version, der ikke var understøttet til AX 3.0 | CustomQueryCollector | Medium |
|
||||
| COM-AX-003 | [COM-AX-003.sql](COM-AX-003.sql) | Dynamics AX-database på en instans, hvor MAXDOP ikke er 1 (SQL Server 2005-2014) | CustomQueryCollector | Medium |
|
||||
|
|
@ -247,3 +285,4 @@ testen på de filer, der skal opdateres.
|
|||
| [AxDatabaseDetector](_collectors/AxDatabaseDetector.sql) | `src/SQLInsight.Collectors/DynamicsAx/AxDatabaseDetector.cs` | 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax); uden AX-læseadgang hvert 5. minut | SQL Server 2005 og nyere | 17 regler (alle AX-regler) |
|
||||
| [AxBatchCollector](_collectors/AxBatchCollector.sql) | `src/SQLInsight.Collectors/DynamicsAx/AxBatchCollector.cs` | 5 min som standard (SQLInsight:CollectorIntervals:dynamics-ax-batch) | SQL Server 2005 og nyere; kræver valgfri AX-læseadgang | 4 regler |
|
||||
| [AxSequenceCollector](_collectors/AxSequenceCollector.sql) | `src/SQLInsight.Collectors/DynamicsAx/AxSequenceCollector.cs` | 1 time som standard (SQLInsight:CollectorIntervals:dynamics-ax-sequences) | SQL Server 2005 og nyere; kræver valgfri AX-læseadgang | 5 regler |
|
||||
| [SyntheticCheckRunner](_collectors/SyntheticCheckRunner.sql) | `src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs` | tjekkets eget interval (standard 300 sek, mindst 60) og "Kør nu" | SQL Server 2005 og nyere | 2 regler (SQLI-SYN-001, SQLI-SYN-002) |
|
||||
|
|
|
|||
|
|
@ -1,65 +1,89 @@
|
|||
/*
|
||||
SQLI-SYN-001 – Et syntetisk tjek fejler
|
||||
========================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-SYN-001: Et syntetisk tjek fejler
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-SYN-001
|
||||
-- Titel: Et syntetisk tjek fejler
|
||||
-- Alvor: High.
|
||||
-- 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.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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).
|
||||
--
|
||||
-- Grænseværdier (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).
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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).
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs : SyntheticCheckFailingRule
|
||||
--
|
||||
-- Read-only: Ja. Ved et SQL-tjek valideres forespørgslen som én skrivebeskyttet SELECT, både når tjekket gemmes og
|
||||
-- før hver kørsel (src/SQLInsight.Core/CustomRules/ReadOnlyQuery.cs), og den køres i en transaktion, der
|
||||
-- altid rulles tilbage. Andre typer tjek sender ingen SQL og ændrer intet.
|
||||
-- Kørsel: Kør i SSMS som tjekkets login. Hver GO er en separat kommando på samme forbindelse; ret [msdb] til
|
||||
-- tjekkets database, eller udelad USE, hvis tjekket ingen database har.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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.
|
||||
-- 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.
|
||||
|
||||
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).
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- SyntheticCheckRunner: SQL-tjekket (login, sessionsindstillinger, forespørgslen i en transaktion, der rulles tilbage)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner (også tjekkets)
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
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 [<database>];
|
||||
|
||||
-- Variant: Kun når tjekket har en database (vist for msdb)
|
||||
-- Kilde: SyntheticCheckRunner.UseDatabaseSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.UseDatabaseSql(database)
|
||||
USE [msdb];
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: før forespørgslen
|
||||
-- Kilde: SyntheticCheckRunner.BeginTransactionSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.BeginTransactionSql
|
||||
BEGIN TRANSACTION;
|
||||
GO
|
||||
|
||||
-- Variant: Standardforespørgslen, når tjekket ikke har sin egen (en egen forespørgsel køres her i stedet, højst 10.000 rækker læses)
|
||||
-- Kilde: SyntheticCheckSettings.DefaultQuery
|
||||
-- Kode: src/SQLInsight.Core/SyntheticChecks/SyntheticCheckDefinitions.cs : SyntheticCheckSettings.DefaultQuery
|
||||
SELECT 1
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: altid efter forespørgslen, også når den fejler
|
||||
-- Kilde: SyntheticCheckRunner.RollbackSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.RollbackSql
|
||||
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'"
|
||||
*/
|
||||
-- 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'"
|
||||
|
|
|
|||
|
|
@ -1,48 +1,73 @@
|
|||
/*
|
||||
SQLI-SYN-002 – Et syntetisk tjek svarer langsomt
|
||||
=================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-SYN-002: Et syntetisk tjek svarer langsomt
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-SYN-002
|
||||
-- Titel: Et syntetisk tjek svarer langsomt
|
||||
-- Alvor: Medium.
|
||||
-- Versioner: Som SQLI-SYN-001.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- Er de seneste SlowRunsBeforeFinding kørsler alle lykkedes og alle langsommere end grænsen, er det et fund.
|
||||
--
|
||||
-- Grænseværdier (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)
|
||||
--
|
||||
-- Rettigheder:
|
||||
-- Som SQLI-SYN-001.
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – SyntheticCheckRunner.RunAsync (DurationMs: hele tjekket, for
|
||||
-- SQL login + forespørgsel), fra src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs : SyntheticCheckSlowRule
|
||||
--
|
||||
-- Read-only: Ja. Ved et SQL-tjek valideres forespørgslen som én skrivebeskyttet SELECT, både når tjekket gemmes og
|
||||
-- før hver kørsel (src/SQLInsight.Core/CustomRules/ReadOnlyQuery.cs), og den køres i en transaktion, der
|
||||
-- altid rulles tilbage. Andre typer tjek sender ingen SQL og ændrer intet.
|
||||
-- Kørsel: Kør i SSMS som tjekkets login. Hver GO er en separat kommando på samme forbindelse; ret [msdb] til
|
||||
-- tjekkets database, eller udelad USE, hvis tjekket ingen database har.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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.
|
||||
-- SQL: Et SQL-tjek kører præcis det samme som i SQLI-SYN-001 (svartiden er login plus forespørgsel):
|
||||
|
||||
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)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
-- SyntheticCheckRunner: SQL-tjekket (login, sessionsindstillinger, forespørgslen i en transaktion, der rulles tilbage)
|
||||
-- -------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner (også tjekkets)
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: Kun når tjekket har en database (vist for msdb)
|
||||
-- Kilde: SyntheticCheckRunner.UseDatabaseSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.UseDatabaseSql(database)
|
||||
USE [msdb];
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: før forespørgslen
|
||||
-- Kilde: SyntheticCheckRunner.BeginTransactionSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.BeginTransactionSql
|
||||
BEGIN TRANSACTION;
|
||||
GO
|
||||
|
||||
-- Variant: Standardforespørgslen, når tjekket ikke har sin egen (en egen forespørgsel køres her i stedet, højst 10.000 rækker læses)
|
||||
-- Kilde: SyntheticCheckSettings.DefaultQuery
|
||||
-- Kode: src/SQLInsight.Core/SyntheticChecks/SyntheticCheckDefinitions.cs : SyntheticCheckSettings.DefaultQuery
|
||||
SELECT 1
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: altid efter forespørgslen, også når den fejler
|
||||
-- Kilde: SyntheticCheckRunner.RollbackSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.RollbackSql
|
||||
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
|
||||
*/
|
||||
-- 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
|
||||
|
|
|
|||
|
|
@ -1,39 +1,38 @@
|
|||
/*
|
||||
SQLI-SYN-003 – TLS-certifikatet udløber snart
|
||||
==============================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-SYN-003: TLS-certifikatet udløber snart
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-SYN-003
|
||||
-- Titel: TLS-certifikatet udløber snart
|
||||
-- Alvor: Medium; High inden for CertificateCriticalDays; Critical når det er udløbet.
|
||||
-- Versioner: Alle HTTPS-servere (TLS 1.2 og nyere fra agentens server).
|
||||
--
|
||||
-- Hvad tjekkes, 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).
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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".
|
||||
--
|
||||
-- Grænseværdier (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)
|
||||
--
|
||||
-- Rettigheder:
|
||||
-- Ingen ud over netværksadgang fra agentens server til adressen.
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – HttpAsync (RemoteCertificateValidationCallback gemmer
|
||||
-- certifikatets NotAfter og Subject), fra src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs : CertificateExpiryRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL og ændrer intet; filen indeholder kun kommentarer.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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()
|
||||
*/
|
||||
-- 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()
|
||||
|
|
|
|||
|
|
@ -1,48 +1,49 @@
|
|||
/*
|
||||
SQLI-WIN-001 – CPU-forbruget er højt i længere tid
|
||||
===================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-001: CPU-forbruget er højt i længere tid
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-001
|
||||
-- Titel: CPU-forbruget er højt i længere tid
|
||||
-- Alvor: High; Critical når gennemsnittet er 98 % eller derover.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere (WS-Man fra Windows Server 2012 / WinRM 3.0; DCOM på alle).
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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".
|
||||
--
|
||||
-- Grænseværdier (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).
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : ServerCpuRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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))
|
||||
*/
|
||||
-- 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))
|
||||
|
|
|
|||
|
|
@ -1,47 +1,48 @@
|
|||
/*
|
||||
SQLI-WIN-002 – Serveren har næsten ingen ledig hukommelse
|
||||
==========================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-002: Serveren har næsten ingen ledig hukommelse
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-002
|
||||
-- Titel: Serveren har næsten ingen ledig hukommelse
|
||||
-- Alvor: Medium; High under 2 % og under 256 MB.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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.
|
||||
--
|
||||
-- Grænseværdier (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.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetPerformanceAsync (CimQueries.MemoryQuery) og
|
||||
-- Session.GetOperatingSystemAsync (CimQueries.OperatingSystemQuery), hvert minut fra
|
||||
-- src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : ServerMemoryRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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)
|
||||
*/
|
||||
-- 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)
|
||||
|
|
|
|||
|
|
@ -1,45 +1,46 @@
|
|||
/*
|
||||
SQLI-WIN-003 – Serveren pager hukommelse til disk
|
||||
==================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-003: Serveren pager hukommelse til disk
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-003
|
||||
-- Titel: Serveren pager hukommelse til disk
|
||||
-- Alvor: Medium.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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.
|
||||
--
|
||||
-- Grænseværdier (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.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : ServerPagingRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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)
|
||||
*/
|
||||
-- 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)
|
||||
|
|
|
|||
|
|
@ -1,40 +1,41 @@
|
|||
/*
|
||||
SQLI-WIN-004 – Den reserverede hukommelse (commit) er tæt på grænsen
|
||||
=====================================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-004: Den reserverede hukommelse (commit) er tæt på grænsen
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-004
|
||||
-- Titel: Den reserverede hukommelse (commit) er tæt på grænsen
|
||||
-- Alvor: Medium; High ved 97 % eller derover.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 100 × CommittedBytes / CommitLimit pr. minut; gennemsnittet over 5 minutter (mindst 80 % dækket) mod grænsen.
|
||||
--
|
||||
-- Grænseværdier (agentens appsettings.json):
|
||||
-- SQLInsight:Servers:Memory:CommitPercent standard 90 (CommittedBytes / CommitLimit, gennemsnit over 5 minutter)
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetPerformanceAsync (CimQueries.MemoryQuery), hvert minut
|
||||
-- fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : ServerCommitRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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
|
||||
*/
|
||||
-- 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
|
||||
|
|
|
|||
|
|
@ -1,48 +1,49 @@
|
|||
/*
|
||||
SQLI-WIN-005 – Lidt ledig plads på et drev
|
||||
===========================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-005: Lidt ledig plads på et drev
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-005
|
||||
-- Titel: Lidt ledig plads på et drev
|
||||
-- Alvor: Medium under FreePercent, High under CriticalFreePercent, Critical under 1 GB eller 1 %.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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.
|
||||
--
|
||||
-- Grænseværdier (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)
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : DiskFreeSpaceRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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)}}
|
||||
*/
|
||||
-- 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)}}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,56 @@
|
|||
/*
|
||||
SQLI-WIN-006 – Et drev bliver fuldt om få dage
|
||||
===============================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-006: Et drev bliver fuldt om få dage
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-006
|
||||
-- Titel: Et drev bliver fuldt om få dage
|
||||
-- Alvor: Medium; High inden for 7 dage; Critical inden for 2 dage.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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.
|
||||
--
|
||||
-- Grænseværdier (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.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : DiskForecastRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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)}}
|
||||
*/
|
||||
-- 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)}}
|
||||
|
|
|
|||
|
|
@ -1,50 +1,51 @@
|
|||
/*
|
||||
SQLI-WIN-007 – En tjeneste, der skal starte automatisk, kører ikke
|
||||
===================================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-007: En tjeneste, der skal starte automatisk, kører ikke
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-007
|
||||
-- Titel: En tjeneste, der skal starte automatisk, kører ikke
|
||||
-- Alvor: Medium.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere (DelayedAutoStart læses fra Windows Server 2012; før det uden).
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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).
|
||||
--
|
||||
-- Grænseværdier (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.
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : StoppedAutomaticServiceRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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
|
||||
*/
|
||||
-- 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
|
||||
|
|
|
|||
|
|
@ -1,41 +1,42 @@
|
|||
/*
|
||||
SQLI-WIN-008 – En overvåget tjeneste kører ikke
|
||||
================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-008: En overvåget tjeneste kører ikke
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-008
|
||||
-- Titel: En overvåget tjeneste kører ikke
|
||||
-- Alvor: High når tjenesten ikke kører; Medium når den ikke findes (eller ikke kan ses).
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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".
|
||||
--
|
||||
-- Grænseværdier (fast i koden):
|
||||
-- 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)
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetServicesAsync (CimQueries.ServiceQuery), hvert 5. minut fra
|
||||
-- src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectServicesAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : WatchedServiceRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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 = '<tjeneste>' (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'"
|
||||
*/
|
||||
-- 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 = '<tjeneste>' (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'"
|
||||
|
|
|
|||
|
|
@ -1,54 +1,55 @@
|
|||
/*
|
||||
SQLI-WIN-009 – Fejl i Windows' hændelseslog
|
||||
============================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-009: Fejl i Windows' hændelseslog
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-009
|
||||
-- Titel: Fejl i Windows' hændelseslog
|
||||
-- Alvor: High: disk/filsystem, ressourcer, niveau Critical, tjeneste stoppet 3+ gange. Medium: tjeneste stoppet, program gik ned,
|
||||
-- Dynamics AX. Low: almindelige fejl der gentager sig. (Uventet nedlukning: se SQLI-WIN-010.)
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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.
|
||||
--
|
||||
-- Grænseværdier (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.
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : WindowsEventLogRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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
|
||||
*/
|
||||
-- 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
|
||||
|
|
|
|||
|
|
@ -1,42 +1,43 @@
|
|||
/*
|
||||
SQLI-WIN-010 – Serveren er genstartet
|
||||
======================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-010: Serveren er genstartet
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-010
|
||||
-- Titel: Serveren er genstartet
|
||||
-- Alvor: High ved uventet genstart; Info ved genstart uden tegn på at den var uventet.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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.
|
||||
--
|
||||
-- Grænseværdier (fast i koden):
|
||||
-- Fast: 24 timer efter LastBootUpTime (ServerEventAnalysis.RecentWindow), derefter forsvinder fundet af sig selv.
|
||||
--
|
||||
-- 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).
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetOperatingSystemAsync (CimQueries.OperatingSystemQuery) og
|
||||
-- Session.GetEventsAsync, fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync og CollectEventsAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : ServerRestartRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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) }
|
||||
*/
|
||||
-- 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) }
|
||||
|
|
|
|||
|
|
@ -1,39 +1,40 @@
|
|||
/*
|
||||
SQLI-WIN-011 – Serveren er ikke genstartet i lang tid
|
||||
======================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-011: Serveren er ikke genstartet i lang tid
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-011
|
||||
-- Titel: Serveren er ikke genstartet i lang tid
|
||||
-- Alvor: Low.
|
||||
-- Versioner: Windows Server 2008 R2 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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".
|
||||
--
|
||||
-- Grænseværdier (agentens appsettings.json):
|
||||
-- SQLInsight:Servers:UptimeDays standard 0 = slået fra (fx 120 for et fund efter 120 dage uden genstart)
|
||||
--
|
||||
-- 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
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetOperatingSystemAsync (CimQueries.OperatingSystemQuery),
|
||||
-- fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectPerformanceAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : ServerUptimeRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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
|
||||
*/
|
||||
-- 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
|
||||
|
|
|
|||
|
|
@ -1,50 +1,51 @@
|
|||
/*
|
||||
SQLI-WIN-012 – En planlagt opgave fejlede sidste gang, den kørte
|
||||
=================================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-012: En planlagt opgave fejlede sidste gang, den kørte
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-012
|
||||
-- Titel: En planlagt opgave fejlede sidste gang, den kørte
|
||||
-- Alvor: Medium.
|
||||
-- Versioner: Windows Server 2012 og nyere (navnerummet TaskScheduler findes ikke på 2008 R2: "ikke målbar").
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- Et fund pr. aktiveret, overvåget opgave, hvis LastTaskResult er en fejl.
|
||||
--
|
||||
-- Grænseværdier (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.
|
||||
--
|
||||
-- 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.
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- 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.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : FailedScheduledTaskRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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
|
||||
*/
|
||||
-- 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
|
||||
|
|
|
|||
|
|
@ -1,44 +1,45 @@
|
|||
/*
|
||||
SQLI-WIN-013 – En planlagt opgave kørte ikke, da den skulle
|
||||
============================================================
|
||||
-- ===================================================================================================================
|
||||
-- SQLI-WIN-013: En planlagt opgave kørte ikke, da den skulle
|
||||
-- ===================================================================================================================
|
||||
-- Regel-id: SQLI-WIN-013
|
||||
-- Titel: En planlagt opgave kørte ikke, da den skulle
|
||||
-- Alvor: Medium.
|
||||
-- Versioner: Windows Server 2012 og nyere.
|
||||
--
|
||||
-- Hvad tjekkes, 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.
|
||||
--
|
||||
-- Vurdering (sker i C# ud fra de indsamlede data, ikke på den overvågede server):
|
||||
-- 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.
|
||||
--
|
||||
-- Grænseværdier (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
|
||||
--
|
||||
-- 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).
|
||||
--
|
||||
-- Data kommer fra (collector, fil – medlemmer, interval):
|
||||
-- src/SQLInsight.Servers/CimWindowsServerSource.cs – Session.GetTasksAsync (CimQueries.TaskQuery og
|
||||
-- PS_ScheduledTask.GetInfoByName), hvert 15. minut fra src/SQLInsight.Agent/Servers/ServerMonitor.cs – CollectTasksAsync.
|
||||
-- Regelkode: src/SQLInsight.Rules/Servers/WindowsServerRules.cs : MissedScheduledTaskRule
|
||||
--
|
||||
-- Read-only: Ja. Reglen sender ingen SQL. Agenten læser kun fra Windows: CIM/WQL-forespørgsler (SELECT),
|
||||
-- hændelsesloggen og for planlagte opgaver Task Schedulers skrivebeskyttede GetInfo. Den starter, stopper
|
||||
-- eller ændrer intet på serveren. Filen indeholder kun kommentarer; forespørgslerne mod Windows står herunder.
|
||||
-- ===================================================================================================================
|
||||
|
||||
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)) }
|
||||
*/
|
||||
-- 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)) }
|
||||
|
|
|
|||
50
SQL Scripts/_collectors/SyntheticCheckRunner.sql
Normal file
50
SQL Scripts/_collectors/SyntheticCheckRunner.sql
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
-- ===================================================================================================================
|
||||
-- Collector: SyntheticCheckRunner (syntetiske SQL-tjek, fra 1.5)
|
||||
-- ===================================================================================================================
|
||||
-- Hvad: Et syntetisk SQL-tjek logger på den instans, tjekket peger på, som tjekkets login (agentens Windows-konto
|
||||
-- eller et SQL-login, hvis adgangskode er krypteret til agenten), og kører tjekkets forespørgsel i en
|
||||
-- transaktion, der altid rulles tilbage. Svartiden og om det lykkedes bruges af SQLI-SYN-001 og SQLI-SYN-002.
|
||||
-- Fil: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs (kaldt af src/SQLInsight.Agent/Servers/SyntheticCheckService.cs)
|
||||
-- Interval: Tjekkets eget interval (standard 300 sek, mindst 60), og når der bedes om "Kør nu"
|
||||
-- Versioner: SQL Server 2005 og nyere.
|
||||
--
|
||||
-- Rettigheder: Login'et i tjekket skal kunne logge ind og køre forespørgslen. Til standardforespørgslen (SELECT 1) er
|
||||
-- det nok at kunne logge ind (og CONNECT til databasen, hvis tjekket har en).
|
||||
--
|
||||
-- Bruges af: SQLI-SYN-001, SQLI-SYN-002.
|
||||
-- Read-only: Ja. Forespørgslen valideres som én skrivebeskyttet SELECT, når tjekket gemmes og før hver kørsel
|
||||
-- (src/SQLInsight.Core/CustomRules/ReadOnlyQuery.cs: ingen andre sætninger, ingen INTO, EXEC, sekvenser
|
||||
-- eller låse-hints), og køres i en transaktion, der altid rulles tilbage. Højst 10.000 rækker læses.
|
||||
-- Kørsel: Kør i SSMS som tjekkets login. Hver GO er en separat kommando på samme forbindelse; ret [msdb] til
|
||||
-- tjekkets database, eller udelad USE, hvis tjekket ingen database har.
|
||||
-- ===================================================================================================================
|
||||
|
||||
-- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner (også tjekkets)
|
||||
-- Kilde: SqlConnectionFactory.SessionSettings
|
||||
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
|
||||
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
|
||||
GO
|
||||
|
||||
-- Variant: Kun når tjekket har en database (vist for msdb)
|
||||
-- Kilde: SyntheticCheckRunner.UseDatabaseSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.UseDatabaseSql(database)
|
||||
USE [msdb];
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: før forespørgslen
|
||||
-- Kilde: SyntheticCheckRunner.BeginTransactionSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.BeginTransactionSql
|
||||
BEGIN TRANSACTION;
|
||||
GO
|
||||
|
||||
-- Variant: Standardforespørgslen, når tjekket ikke har sin egen (en egen forespørgsel køres her i stedet, højst 10.000 rækker læses)
|
||||
-- Kilde: SyntheticCheckSettings.DefaultQuery
|
||||
-- Kode: src/SQLInsight.Core/SyntheticChecks/SyntheticCheckDefinitions.cs : SyntheticCheckSettings.DefaultQuery
|
||||
SELECT 1
|
||||
GO
|
||||
|
||||
-- Variant: Alle versioner fra SQL Server 2005: altid efter forespørgslen, også når den fejler
|
||||
-- Kilde: SyntheticCheckRunner.RollbackSql
|
||||
-- Kode: src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs : SyntheticCheckRunner.RollbackSql
|
||||
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
|
||||
GO
|
||||
|
|
@ -28,6 +28,19 @@ public sealed class SyntheticCheckRunner(ISqlConnectionFactory sqlConnections, I
|
|||
/// <summary>At most this much of an HTTP answer is read when looking for the expected text.</summary>
|
||||
public const int MaxBodyBytes = 1024 * 1024;
|
||||
|
||||
/// <summary>At most this many rows of a SQL check's answer are read.</summary>
|
||||
public const int MaxRows = 10000;
|
||||
|
||||
// What a SQL check sends besides the session settings of every connection and its query (SQL Scripts/SQLI-SYN-001.sql).
|
||||
public const string BeginTransactionSql = "BEGIN TRANSACTION;";
|
||||
public const string RollbackSql = "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;";
|
||||
|
||||
public static string UseDatabaseSql(string database)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(database);
|
||||
return "USE [" + database.Replace("]", "]]", StringComparison.Ordinal) + "];";
|
||||
}
|
||||
|
||||
public async Task<SyntheticCheckResult> RunAsync(SyntheticCheckRun run, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(run);
|
||||
|
|
@ -301,11 +314,11 @@ public sealed class SyntheticCheckRunner(ISqlConnectionFactory sqlConnections, I
|
|||
var timeoutSeconds = Math.Max(1, (int)Math.Ceiling(run.Timeout.TotalSeconds));
|
||||
if (!string.IsNullOrWhiteSpace(settings.Database))
|
||||
{
|
||||
await ExecuteAsync(opened.Connection, "USE [" + settings.Database.Replace("]", "]]", StringComparison.Ordinal) + "];", timeoutSeconds, cancellationToken).ConfigureAwait(false);
|
||||
await ExecuteAsync(opened.Connection, UseDatabaseSql(settings.Database), timeoutSeconds, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// A transaction that is always rolled back: a second guard on top of the read-only check of the query.
|
||||
await ExecuteAsync(opened.Connection, "BEGIN TRANSACTION;", timeoutSeconds, cancellationToken).ConfigureAwait(false);
|
||||
await ExecuteAsync(opened.Connection, BeginTransactionSql, timeoutSeconds, cancellationToken).ConfigureAwait(false);
|
||||
var queryStarted = time.GetTimestamp();
|
||||
var rows = 0;
|
||||
try
|
||||
|
|
@ -313,15 +326,35 @@ public sealed class SyntheticCheckRunner(ISqlConnectionFactory sqlConnections, I
|
|||
await using var command = opened.Connection.CreateCommand();
|
||||
command.CommandText = query;
|
||||
command.CommandTimeout = timeoutSeconds;
|
||||
await using var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
|
||||
while (rows < 10000 && await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
|
||||
var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
rows++;
|
||||
while (rows < MaxRows && await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
rows++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Closing a reader fetches the rest of the answer; past the limit it is cancelled instead.
|
||||
if (rows == MaxRows)
|
||||
{
|
||||
command.Cancel();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await reader.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (DbException) when (rows == MaxRows)
|
||||
{
|
||||
// The cancelled rest of the answer.
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await ExecuteAsync(opened.Connection, "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;", timeoutSeconds, CancellationToken.None).ConfigureAwait(false);
|
||||
await ExecuteAsync(opened.Connection, RollbackSql, timeoutSeconds, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
var queryMs = (int)time.GetElapsedTime(queryStarted).TotalMilliseconds;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
<!-- SqlScriptTests: rule ids, and the SQL the connection itself sends. -->
|
||||
<ProjectReference Include="..\..\src\SQLInsight.Rules\SQLInsight.Rules.csproj" />
|
||||
<ProjectReference Include="..\..\src\SQLInsight.Connectivity\SQLInsight.Connectivity.csproj" />
|
||||
<!-- SqlScriptTests: the SQL of the synthetic SQL check (SQLI-SYN-001/002). -->
|
||||
<ProjectReference Include="..\..\src\SQLInsight.Servers\SQLInsight.Servers.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- Dynamics AX schemas (real and documented): the AX collectors' SQL is checked for every version adapter. -->
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ using SQLInsight.Collectors.Discovery;
|
|||
using SQLInsight.Collectors.Instance;
|
||||
using SQLInsight.Collectors.Performance;
|
||||
using SQLInsight.Core.Instances;
|
||||
using SQLInsight.Core.SyntheticChecks;
|
||||
using SQLInsight.Servers.Synthetic;
|
||||
|
||||
namespace SQLInsight.Collectors.Tests.SqlScripts;
|
||||
|
||||
|
|
@ -346,9 +348,27 @@ internal static class SqlScriptSources
|
|||
};
|
||||
|
||||
sources.AddRange(DynamicsAx());
|
||||
sources.AddRange(SyntheticCheck());
|
||||
return sources;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The synthetic SQL check (1.5): the agent logs on as the check says, sets the session settings above, and runs the
|
||||
/// check's query in a transaction that is always rolled back. Not a collector; registered so SQLI-SYN-001/002 show it.
|
||||
/// </summary>
|
||||
private static IEnumerable<Source> SyntheticCheck()
|
||||
{
|
||||
const string File = "src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs";
|
||||
yield return new("SyntheticCheckRunner.UseDatabaseSql", "SyntheticCheckRunner", "Kun når tjekket har en database (vist for " + ExampleDatabase + ")",
|
||||
File, "SyntheticCheckRunner.UseDatabaseSql(database)", () => SyntheticCheckRunner.UseDatabaseSql(ExampleDatabase));
|
||||
yield return new("SyntheticCheckRunner.BeginTransactionSql", "SyntheticCheckRunner", "Alle versioner fra SQL Server 2005: før forespørgslen",
|
||||
File, "SyntheticCheckRunner.BeginTransactionSql", () => SyntheticCheckRunner.BeginTransactionSql);
|
||||
yield return new("SyntheticCheckSettings.DefaultQuery", "SyntheticCheckRunner", "Standardforespørgslen, når tjekket ikke har sin egen",
|
||||
"src/SQLInsight.Core/SyntheticChecks/SyntheticCheckDefinitions.cs", "SyntheticCheckSettings.DefaultQuery", () => SyntheticCheckSettings.DefaultQuery);
|
||||
yield return new("SyntheticCheckRunner.RollbackSql", "SyntheticCheckRunner", "Alle versioner fra SQL Server 2005: altid efter forespørgslen, også når den fejler",
|
||||
File, "SyntheticCheckRunner.RollbackSql", () => SyntheticCheckRunner.RollbackSql);
|
||||
}
|
||||
|
||||
/// <summary>The AX database the Dynamics AX scripts are shown for: there is no AX database on every instance, so the reader changes it.</summary>
|
||||
public const string AxExampleDatabase = "AXDB";
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System.Reflection;
|
|||
using System.Text.RegularExpressions;
|
||||
using SQLInsight.Rules;
|
||||
using SQLInsight.Rules.Lifecycle;
|
||||
using SQLInsight.Rules.Servers;
|
||||
|
||||
namespace SQLInsight.Collectors.Tests.SqlScripts;
|
||||
|
||||
|
|
@ -13,10 +14,14 @@ public sealed partial class SqlScriptTests
|
|||
{
|
||||
private static readonly string Folder = Path.Combine(RepositoryRoot(), "SQL Scripts");
|
||||
|
||||
/// <summary>The Windows server and synthetic check rules (1.5): most send no SQL; their Windows queries are comments (see SQLInsight.Servers.Tests).</summary>
|
||||
private static readonly HashSet<string> ServerRuleIds = ServerRuleCatalog.All.Select(r => r.Id).ToHashSet(StringComparer.Ordinal);
|
||||
|
||||
[Fact]
|
||||
public void Every_registered_rule_has_a_script_and_every_script_a_rule()
|
||||
{
|
||||
var ids = BuiltInRules.Create().Select(r => r.Id)
|
||||
.Concat(ServerRuleIds)
|
||||
.Concat(RulePack.Embedded().CommunityRules.Select(r => r.Id))
|
||||
.ToHashSet(StringComparer.Ordinal);
|
||||
var files = Directory.EnumerateFiles(Folder, "*.sql", SearchOption.TopDirectoryOnly)
|
||||
|
|
@ -66,7 +71,7 @@ public sealed partial class SqlScriptTests
|
|||
}
|
||||
|
||||
var blocks = Blocks(Read(file)).ToList();
|
||||
if (blocks.Count == 0)
|
||||
if (blocks.Count == 0 && !ServerRuleIds.Contains(Path.GetFileNameWithoutExtension(file)))
|
||||
{
|
||||
problems.Add($"{name}: ingen '-- Kilde:'-blokke");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,5 +19,18 @@ public class RuleCatalogTests
|
|||
public void Rule_count()
|
||||
{
|
||||
Assert.Equal(92, BuiltInRules.Create().Count);
|
||||
Assert.Equal(13, Servers.WindowsServerRules.Create().Count);
|
||||
Assert.Equal(3, Servers.SyntheticCheckRules.Create().Count);
|
||||
Assert.Equal(108, BuiltInRules.Create().Count + Servers.ServerRuleCatalog.All.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Server_and_check_rules_have_unique_ids_that_no_instance_rule_has()
|
||||
{
|
||||
var ids = BuiltInRules.Create().Select(r => r.Id).Concat(Servers.ServerRuleCatalog.All.Select(r => r.Id)).ToList();
|
||||
|
||||
Assert.Equal(ids.Count, ids.Distinct(StringComparer.OrdinalIgnoreCase).Count());
|
||||
Assert.All(Servers.ServerRuleCatalog.All, r => Assert.Matches("^SQLI-(WIN|SYN)-[0-9]{3}$", r.Id));
|
||||
Assert.All(Servers.ServerRuleCatalog.All, r => Assert.False(string.IsNullOrWhiteSpace(r.Title)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,10 @@ public class ServerRuleScriptTests
|
|||
{
|
||||
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);
|
||||
var text = File.ReadAllText(file).Replace("\r\n", "\n", StringComparison.Ordinal);
|
||||
Assert.Contains($"-- Regel-id: {rule.Id}\n", text, StringComparison.Ordinal);
|
||||
Assert.Contains($"-- Titel: {rule.Title}\n", text, StringComparison.Ordinal);
|
||||
Assert.Contains("-- Vurdering", text, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("sysadmin", text, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
62
tests/SQLInsight.Servers.Tests/ServerScriptTests.cs
Normal file
62
tests/SQLInsight.Servers.Tests/ServerScriptTests.cs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace SQLInsight.Servers.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// The Windows queries in SQL Scripts/SQLI-WIN-*.sql (comment blocks, for review) are the ones the agent sends, word for
|
||||
/// word: every query in <see cref="CimQueries"/> is shown in a script, and every script shows at least one of them.
|
||||
/// </summary>
|
||||
public sealed partial class ServerScriptTests
|
||||
{
|
||||
private static readonly DateTimeOffset Example = new(2026, 10, 2, 12, 0, 0, TimeSpan.Zero);
|
||||
|
||||
/// <summary>The query texts, the event log ones rendered as the scripts show them.</summary>
|
||||
private static IEnumerable<(string Name, string Text)> Queries()
|
||||
{
|
||||
foreach (var field in typeof(CimQueries).GetFields(BindingFlags.Public | BindingFlags.Static)
|
||||
.Where(f => f.IsLiteral && f.Name.EndsWith("Query", StringComparison.Ordinal)))
|
||||
{
|
||||
yield return ($"CimQueries.{field.Name}", (string)field.GetRawConstantValue()!);
|
||||
}
|
||||
|
||||
yield return ("CimQueries.EventXPath", CimQueries.EventXPath(Example));
|
||||
yield return ("CimQueries.EventQuery", CimQueries.EventQuery("System", Example));
|
||||
yield return ("CimQueries.SingleServiceQuery", CimQueries.SingleServiceQuery("<tjeneste>"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Every_windows_query_is_shown_in_a_script_word_for_word()
|
||||
{
|
||||
var scripts = Scripts().ToDictionary(f => Path.GetFileName(f), f => Flatten(File.ReadAllText(f)));
|
||||
var missing = Queries().Where(q => !scripts.Values.Any(s => s.Contains(Flatten(q.Text), StringComparison.Ordinal))).Select(q => q.Name).ToList();
|
||||
var without = scripts.Where(s => !Queries().Any(q => s.Value.Contains(Flatten(q.Text), StringComparison.Ordinal))).Select(s => s.Key).ToList();
|
||||
|
||||
Assert.True(missing.Count == 0, "Står ikke ordret i SQL Scripts/SQLI-WIN-*.sql: " + string.Join(", ", missing));
|
||||
Assert.True(without.Count == 0, "Viser ingen af agentens forespørgsler: " + string.Join(", ", without));
|
||||
}
|
||||
|
||||
/// <summary>The comment text without the "--" prefixes, with all whitespace as single spaces (a query may wrap).</summary>
|
||||
private static string Flatten(string text) =>
|
||||
Whitespace().Replace(CommentPrefix().Replace(text.Replace("\r\n", "\n", StringComparison.Ordinal), " "), " ");
|
||||
|
||||
private static List<string> Scripts()
|
||||
{
|
||||
for (var directory = new DirectoryInfo(AppContext.BaseDirectory); directory is not null; directory = directory.Parent)
|
||||
{
|
||||
var folder = Path.Combine(directory.FullName, "SQL Scripts");
|
||||
if (Directory.Exists(folder))
|
||||
{
|
||||
return Directory.EnumerateFiles(folder, "SQLI-WIN-*.sql").Order(StringComparer.Ordinal).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
throw new DirectoryNotFoundException("SQL Scripts/ blev ikke fundet over testens mappe.");
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"^--", RegexOptions.Multiline)]
|
||||
private static partial Regex CommentPrefix();
|
||||
|
||||
[GeneratedRegex(@"\s+")]
|
||||
private static partial Regex Whitespace();
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue