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:
Søren Eggert Lundsteen Olsen 2026-10-02 15:18:24 +02:00
parent 8d092b6a35
commit cb99778a3f
27 changed files with 1021 additions and 733 deletions

View file

@ -40,6 +40,8 @@ Warnings behandles som fejl, og .NET-analyzers kører på niveauet `latest-recom
5. Registrér reglen i `BuiltInRules`. 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. 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 ### 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`). 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`).

View file

@ -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. 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).
--- ---

View file

@ -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 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)). 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 ## Navngivning
| Fil | Indhold | | 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/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/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/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 ## 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 (fx baseline-historikken bag `SQLI-ANOM-001`, som ikke hentes fra den overvågede server) og kundens lokale regler
(`LOCAL-…`). (`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 ## Hold mappen i sync
`tests/SQLInsight.Collectors.Tests/SqlScripts/SqlScriptTests.cs` fejler, hvis mappen og koden ikke stemmer overens: `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 - `Every_registered_rule_has_a_script_and_every_script_a_rule`: hver indbygget regel (`BuiltInRules` og, fra 1.5,
community-regel i regelpakken har en `<id>.sql`, og der er ingen filer for ukendte id'er. `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 - `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å 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 - `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. 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. - `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'…'`. `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 - `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. 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. (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 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 ## 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 | | 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-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-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-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-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-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 | | 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-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-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-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-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-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 | | 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) | | [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 | | [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 | | [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) |

View file

@ -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 -- SQL: Ved et SQL-tjek kører agenten præcis dette på den instans, tjekket peger på (ændrer intet: forespørgslen
Agenten gør det, en bruger eller applikation ville gøre – forbinder til en port, henter en side, logger på SQL Server -- 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
og kører en forespørgsel, slår et navn op, logger på Dynamics AX – og det fejler. Er tjekket knyttet til en tjeneste -- rulles tilbage). Hver GO er en separat kommando på samme forbindelse.
på en Windows-server, og kører tjenesten, siges det direkte: "… svarer ikke, selv om tjenesten kører" – den fejl,
en tjenesteovervågning alene ikke ser.
Tærskler (agentens appsettings.json og tjekkets indstillinger) -- -------------------------------------------------------------------------------------------------------------------
SQLInsight:SyntheticChecks:FailuresBeforeFinding standard 2 (fejl i træk før et fund: ét tabt svar er ingen alarm) -- SyntheticCheckRunner: SQL-tjekket (login, sessionsindstillinger, forespørgslen i en transaktion, der rulles tilbage)
Pr. tjek: interval (standard 300 s, 60–86400) og timeout (standard 15 s, AX 60 s, højst 120). -- -------------------------------------------------------------------------------------------------------------------
Alvor -- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner (også tjekkets)
Høj. -- Kilde: SqlConnectionFactory.SessionSettings
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
Rettigheder
TCP, HTTP(S), DNS: ingen ud over netværksadgang fra agentens server. HTTP med Windows-godkendelse: agentens konto.
SQL: login'et i tjekket (agentens Windows-konto eller et SQL-login, hvis adgangskode krypteres til agenten som i 1.3)
skal kunne logge ind og køre forespørgslen; least-privilege-login'et fra grant-least-privilege.sql er nok til standardforespørgslen.
AX-logon: agentens Windows-konto skal være AX-bruger (i firmaet), og .NET Business Connector skal være installeret på
agentens server; ellers testes kun AOS-porten (og resultatet siger det).
Tjenestens tilstand: WMI Remote Enable på root\cimv2 + læseret på Service Control Manager på tjenestens server.
Understøttede versioner
SQL: SQL Server 2005 og nyere (SqlClient, ODBC-fallback for 2005). AX-logon: AX 2009 (kræver Windows PowerShell
2.0-motoren) og AX 2012. Windows-tjenester: Windows Server 2008 R2 og nyere.
Collector
src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – SyntheticCheckRunner.RunAsync (TcpAsync, HttpAsync, SqlAsync,
DnsAsync, AxAsync), AX-logon: src/SQLInsight.Servers/Synthetic/AxBusinessConnector.cs og ax-logon.ps1. Køres efter
tjekkets interval af src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync, som også slår den tilknyttede
tjenestes tilstand op (CimQueries.SingleServiceQuery).
Regel
src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs – SyntheticCheckFailingRule
Evaluering
Har de seneste FailuresBeforeFinding kørsler alle fejlet, er det et fund. Titlen siger, om den tilknyttede tjeneste
kører, er stoppet, eller om tjekket blot fejler, med fejlteksten som måling (følsom).
SQL: Ved et SQL-tjek kører agenten præcis dette på den instans, tjekket peger på (ændrer intet: forespørgslen
valideres som én skrivebeskyttet SELECT, både når den gemmes og før den køres, og køres i en transaktion, der altid
rulles tilbage). Hver GO er en separat kommando på samme forbindelse.
*/
-- Variant: SQL-tjek med standardforespørgslen (alle versioner fra SQL Server 2005)
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
GO 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; BEGIN TRANSACTION;
GO 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 SELECT 1
GO 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; IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
GO GO
/* -- Ikke-SQL-tjek, efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
Ikke-SQL-tjek, efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto): -- TCP: Test-NetConnection -ComputerName aos01 -Port 2712
TCP: Test-NetConnection -ComputerName aos01 -Port 2712 -- HTTP: Invoke-WebRequest -Uri https://ep.firma.local/ -UseDefaultCredentials -UseBasicParsing | Select-Object StatusCode
HTTP: Invoke-WebRequest -Uri https://ep.firma.local/ -UseDefaultCredentials -UseBasicParsing | Select-Object StatusCode -- DNS: Resolve-DnsName aos01.firma.local
DNS: Resolve-DnsName aos01.firma.local -- AX: Test-NetConnection -ComputerName aos01 -Port 2712 (logon: se src/SQLInsight.Servers/Synthetic/ax-logon.ps1)
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'"
Tjeneste: Get-CimInstance -ComputerName aos01 -Query "SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service WHERE Name = 'AOS60`$01'"
*/

View file

@ -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 -- SQL: Et SQL-tjek kører præcis det samme som i SQLI-SYN-001 (svartiden er login plus forespørgsel):
Tjekket lykkes, men svaret har de seneste gange taget længere end tjekkets grænse. Brugerne oplever det som en langsom
applikation, længe før den holder op med at svare.
Tærskler (agentens appsettings.json og tjekkets indstillinger) -- -------------------------------------------------------------------------------------------------------------------
Pr. tjek: "Langsomt svar over (ms)" (insight.SyntheticChecks.SettingsJson: warnMilliseconds). Uden grænse: "ikke relevant". -- SyntheticCheckRunner: SQL-tjekket (login, sessionsindstillinger, forespørgslen i en transaktion, der rulles tilbage)
SQLInsight:SyntheticChecks:SlowRunsBeforeFinding standard 3 (langsomme svar i træk før et fund) -- -------------------------------------------------------------------------------------------------------------------
Alvor -- Variant: Alle versioner: sættes på hver forbindelse, agenten åbner (også tjekkets)
Middel. -- Kilde: SqlConnectionFactory.SessionSettings
-- Kode: src/SQLInsight.Connectivity/SqlConnectionFactory.cs : SqlConnectionFactory.SessionSettings
Rettigheder
Som SQLI-SYN-001.
Understøttede versioner
Som SQLI-SYN-001.
Collector
src/SQLInsight.Servers/Synthetic/SyntheticCheckRunner.cs – SyntheticCheckRunner.RunAsync (DurationMs: hele tjekket, for
SQL login + forespørgsel), fra src/SQLInsight.Agent/Servers/SyntheticCheckService.cs – RunCheckAsync.
Regel
src/SQLInsight.Rules/Servers/SyntheticCheckRules.cs – SyntheticCheckSlowRule
Evaluering
Er de seneste SlowRunsBeforeFinding kørsler alle lykkedes og alle langsommere end grænsen, er det et fund.
SQL: Et SQL-tjek kører præcis det samme som i SQLI-SYN-001 (svartiden er login plus forespørgsel):
*/
-- Variant: SQL-tjek med standardforespørgslen (alle versioner fra SQL Server 2005)
SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; SET LOCK_TIMEOUT 5000; SET DEADLOCK_PRIORITY LOW; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
GO 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; BEGIN TRANSACTION;
GO 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 SELECT 1
GO 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; IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION;
GO GO
/* -- Ikke-SQL-tjek, efterprøv svartiden med PowerShell (skrivebeskyttet):
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 { Invoke-WebRequest -Uri https://ep.firma.local/ -UseDefaultCredentials -UseBasicParsing } | Select-Object TotalMilliseconds -- Measure-Command { Test-NetConnection -ComputerName aos01 -Port 2712 } | Select-Object TotalMilliseconds
Measure-Command { Test-NetConnection -ComputerName aos01 -Port 2712 } | Select-Object TotalMilliseconds
*/

View file

@ -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 -- Reglen bruger ikke SQL. Tjekket er en HTTPS GET; filen indeholder kun kommentarer og ændrer intet.
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 -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server):
afvises (fx selvsigneret). -- $c = New-Object System.Net.Sockets.TcpClient('ep.firma.local', 443)
-- $s = New-Object System.Net.Security.SslStream($c.GetStream(), $false, { $true })
Tærskler (agentens appsettings.json) -- $s.AuthenticateAsClient('ep.firma.local'); $s.RemoteCertificate.GetExpirationDateString(); $c.Close()
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()
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT PercentProcessorTime, Timestamp_Sys100NS FROM Win32_PerfRawData_PerfOS_Processor WHERE Name = '_Total'
Tærskler (agentens appsettings.json) -- SELECT NumberOfLogicalProcessors FROM Win32_ComputerSystem
SQLInsight:Servers:Cpu:HighPercent standard 90 (gennemsnitlig CPU i procent) --
SQLInsight:Servers:Cpu:SustainedMinutes standard 15 (perioden gennemsnittet tages over) -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
Målingerne skal dække mindst 80 % af perioden (en kort top efter et hul tæller ikke). -- $s = New-CimSession -ComputerName SERVER # DCOM: -SessionOption (New-CimSessionOption -Protocol Dcom)
-- $q = "SELECT PercentProcessorTime, Timestamp_Sys100NS FROM Win32_PerfRawData_PerfOS_Processor WHERE Name = '_Total'"
Alvor -- $a = Get-CimInstance -CimSession $s -Query $q; Start-Sleep -Seconds 60; $b = Get-CimInstance -CimSession $s -Query $q
Høj; Kritisk når gennemsnittet er 98 % eller derover. -- 100 * (1 - ($b.PercentProcessorTime - $a.PercentProcessorTime) / ($b.Timestamp_Sys100NS - $a.Timestamp_Sys100NS))
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))
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT AvailableMBytes, PagesPersec, CommittedBytes, CommitLimit, Timestamp_PerfTime, Frequency_PerfTime FROM Win32_PerfRawData_PerfOS_Memory
Tærskler (agentens appsettings.json) -- SELECT Caption, Version, BuildNumber, LastBootUpTime, TotalVisibleMemorySize, CSName FROM Win32_OperatingSystem
SQLInsight:Servers:Memory:AvailablePercent standard 5 (andel ledig af den samlede hukommelse) --
SQLInsight:Servers:Memory:AvailableMegabytes standard 1024 (ledig hukommelse i MB) -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
Begge skal være under grænsen (gennemsnit over 5 minutter), så store SQL Server-hosts, der bevidst har lidt -- $s = New-CimSession -ComputerName SERVER
tilbage, men stadig flere GB, ikke giver fund. -- $m = Get-CimInstance -CimSession $s -Query "SELECT AvailableMBytes FROM Win32_PerfRawData_PerfOS_Memory"
-- $o = Get-CimInstance -CimSession $s -Query "SELECT TotalVisibleMemorySize FROM Win32_OperatingSystem"
Alvor -- "{0} MB ledig ({1:N1} %)" -f $m.AvailableMBytes, (100 * $m.AvailableMBytes * 1024 / $o.TotalVisibleMemorySize)
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)
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT AvailableMBytes, PagesPersec, CommittedBytes, CommitLimit, Timestamp_PerfTime, Frequency_PerfTime FROM Win32_PerfRawData_PerfOS_Memory
Tærskler (agentens appsettings.json) --
SQLInsight:Servers:Memory:PagesPerSecond standard 1000 (Memory\Pages/sec, gennemsnit over 15 minutter) -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
Kun sammen med lidt ledig hukommelse (under 10 % i samme periode): Pages/sec alene er også fil-I/O gennem -- $s = New-CimSession -ComputerName SERVER
memory-mapped filer og er ikke i sig selv et problem. -- $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
Alvor -- ($b.PagesPersec - $a.PagesPersec) / (($b.Timestamp_PerfTime - $a.Timestamp_PerfTime) / $b.Frequency_PerfTime)
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)
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT AvailableMBytes, PagesPersec, CommittedBytes, CommitLimit, Timestamp_PerfTime, Frequency_PerfTime FROM Win32_PerfRawData_PerfOS_Memory
Tærskler (agentens appsettings.json) --
SQLInsight:Servers:Memory:CommitPercent standard 90 (CommittedBytes / CommitLimit, gennemsnit over 5 minutter) -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
-- $s = New-CimSession -ComputerName SERVER
Alvor -- $m = Get-CimInstance -CimSession $s -Query "SELECT CommittedBytes, CommitLimit FROM Win32_PerfRawData_PerfOS_Memory"
Middel; Høj ved 97 % eller derover. -- 100 * $m.CommittedBytes / $m.CommitLimit
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
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT Name, Label, FileSystem, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3
Tærskler (agentens appsettings.json) -- SELECT DeviceID, VolumeName, FileSystem, Size, FreeSpace FROM Win32_LogicalDisk WHERE DriveType = 3 (fallback)
SQLInsight:Servers:Disks:FreePercent standard 10 (ledig andel, under: Middel) --
SQLInsight:Servers:Disks:CriticalFreePercent standard 5 (under: Høj) -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
SQLInsight:Servers:Disks:EnoughFreeGigabytes standard 50 (er der mindst så mange GB ledige, er der intet fund, -- $s = New-CimSession -ComputerName SERVER
uanset andelen: store drev med lille andel ledig kan være fine) -- Get-CimInstance -CimSession $s -Query "SELECT Name, Label, FileSystem, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3" |
-- Where-Object { $_.Name -notlike '\\?\*' } |
Alvor -- Select-Object Name, Label, @{n='LedigGB';e={[math]::Round($_.FreeSpace / 1GB, 1)}}, @{n='Ledig%';e={[math]::Round(100 * $_.FreeSpace / $_.Capacity, 1)}}
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)}}
*/

View file

@ -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 -- Reglen bruger ikke SQL mod den overvågede server. Forespørgslen mod Windows står herunder, og den forespørgsel, agenten
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 -- bruger mod sit eget repository (ikke den overvågede server), står til sidst. Filen indeholder kun kommentarer.
tempo, og fortsætter det, er drevet fuldt inden for prognosegrænsen. --
-- CIM/WQL (namespace root\cimv2):
Tærskler (agentens appsettings.json) -- SELECT Name, Label, FileSystem, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3
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) -- Historikken i SQLInsight-repositoriet (src/SQLInsight.Repository/InsightRepository.WindowsServers.cs – GetServerDiskHistoryAsync):
SQLInsight:Servers:DiskHistoryDays standard 35 (hvor længe målingerne gemmes i insight.ServerDiskSamples) -- SELECT Volume, DATEADD(hour, DATEDIFF(hour, 0, SampledAt), 0) AS [Hour], MAX(SizeGb), AVG(FreeGb)
Faste fornuftsgrænser (src/SQLInsight.Core/Servers/DiskForecast.cs – DiskForecastSettings): mindst 2 dages historik og -- FROM insight.ServerDiskSamples WHERE ServerId = @id AND SampledAt >= @from
12 målinger, R² mindst 0,5, vækst mindst 0,01 GB pr. dag, højst 365 dage frem. -- GROUP BY Volume, DATEADD(hour, DATEDIFF(hour, 0, SampledAt), 0)
-- ORDER BY Volume, [Hour];
Alvor --
Middel; Høj inden for 7 dage; Kritisk inden for 2 dage. -- Efterprøv med PowerShell (skrivebeskyttet; ledig plads nu):
-- Get-CimInstance -ComputerName SERVER -Query "SELECT Name, Capacity, FreeSpace FROM Win32_Volume WHERE DriveType = 3" |
Rettigheder på den overvågede server (db/permissions/grant-windows-server.ps1, aldrig lokal administrator) -- Select-Object Name, @{n='LedigGB';e={[math]::Round($_.FreeSpace / 1GB, 1)}}
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)}}
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT Name, DisplayName, State, StartMode, DelayedAutoStart, ExitCode FROM Win32_Service
Tærskler (agentens appsettings.json og serverens indstillinger i SQLInsight Web) -- SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service (før Windows Server 2012)
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) -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
Indbygget liste over automatiske tjenester, der stopper af sig selv (StoppedAutomaticServiceRule.StopByDesign), -- Get-CimInstance -ComputerName SERVER -Query "SELECT Name, DisplayName, State, StartMode, DelayedAutoStart, ExitCode FROM Win32_Service" |
fx sppsvc, gupdate, edgeupdate, MapsBroker, RemoteRegistry, clr_optimization_*, CDPUserSvc_*. -- Where-Object { $_.StartMode -eq 'Auto' -and $_.State -ne 'Running' } | Select-Object Name, DisplayName, State, ExitCode
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
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT Name, DisplayName, State, StartMode, DelayedAutoStart, ExitCode FROM Win32_Service
Tærskler -- SELECT Name, DisplayName, State, StartMode, ExitCode FROM Win32_Service WHERE Name = '<tjeneste>' (syntetiske tjek)
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) -- 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'"
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'"
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- 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']]]
Tærskler (agentens appsettings.json) -- CIM/WQL fallback (namespace root\cimv2; EventType 1 = fejl, kritiske hændelser rapporteres som fejl):
SQLInsight:Servers:EventLog:RepeatThreshold standard 5 (en almindelig fejl skal ses så mange gange på 24 timer) -- SELECT Logfile, SourceName, EventCode, EventType, TimeGenerated, RecordNumber, Message FROM Win32_NTLogEvent
SQLInsight:Servers:EventLog:Ignore ekstra støj: "Kilde:id", "Kilde" eller "Kilde*" -- WHERE Logfile = 'System' AND EventType = 1 AND TimeGenerated > '20261002120000.000000+000'
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) -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
Indbygget støjliste (ServerEventAnalysis.DefaultIgnore): DCOM 10016/10010, Schannel 36874/36887/36888, TPM-WMI 1796/1801, -- Get-WinEvent -ComputerName SERVER -LogName System -FilterXPath "*[System[(Level=1 or Level=2) and TimeCreated[timediff(@SystemTime) <= 86400000]]]" |
WMI 10, Security-SPP 8198, og SQL Server's egne kilder (MSSQLSERVER, MSSQL$*, SQLSERVERAGENT, SQLAgent$*, -- Group-Object ProviderName, Id | Sort-Object Count -Descending | Select-Object Count, Name
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
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\cimv2):
-- SELECT Caption, Version, BuildNumber, LastBootUpTime, TotalVisibleMemorySize, CSName FROM Win32_OperatingSystem
Tærskler -- Event Log (MS-EVEN6), XPath for System:
Fast: 24 timer efter LastBootUpTime (ServerEventAnalysis.RecentWindow), derefter forsvinder fundet af sig selv. -- *[System[(Level=1 or Level=2) and TimeCreated[@SystemTime>'2026-10-02T12:00:00.000Z']]]
--
Alvor -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
Høj ved uventet genstart; Info ved genstart uden tegn på at den var uventet. -- (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) }
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) }
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslen mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
De fleste Windows-opdateringer kræver en genstart. En server, der ikke er genstartet i flere måneder, mangler derfor --
næsten sikkert sikkerhedsopdateringer. -- CIM/WQL (namespace root\cimv2):
-- SELECT Caption, Version, BuildNumber, LastBootUpTime, TotalVisibleMemorySize, CSName FROM Win32_OperatingSystem
Tærskler (agentens appsettings.json) --
SQLInsight:Servers:UptimeDays standard 0 = slået fra (fx 120 for et fund efter 120 dage uden genstart) -- 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
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
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\Microsoft\Windows\TaskScheduler):
-- SELECT TaskName, TaskPath, State FROM MSFT_ScheduledTask
Tærskler (agentens appsettings.json) -- CIM-metode (skrivebeskyttet) pr. overvåget opgave:
SQLInsight:Servers:Tasks:IncludeMicrosoftTasks standard false (Microsofts egne opgaver under \Microsoft\ overvåges ikke) -- PS_ScheduledTask.GetInfoByName(TaskName, TaskPath) -> cmdletOutput: MSFT_TaskDynamicInfo
SQLInsight:Servers:Tasks:Ignore opgaver der aldrig overvåges (sti\navn eller præfiks*) -- (LastRunTime, LastTaskResult, NextRunTime, NumberOfMissedRuns)
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), -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
0x41304 (ingen flere kørsler), 0x41325 (i kø), 0x8004131F (kørte allerede) – src/SQLInsight.Core/Servers/ServerTasks.cs. -- $s = New-CimSession -ComputerName SERVER
-- Get-ScheduledTask -CimSession $s | Where-Object TaskPath -notlike '\Microsoft\*' | Get-ScheduledTaskInfo -CimSession $s |
Alvor -- Select-Object TaskPath, TaskName, LastRunTime, @{n='Resultat';e={'0x{0:X}' -f $_.LastTaskResult}}, NextRunTime, NumberOfMissedRuns
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
*/

View file

@ -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 -- Reglen bruger ikke SQL. Forespørgslerne mod Windows står herunder; filen indeholder kun kommentarer og ændrer intet.
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. -- CIM/WQL (namespace root\Microsoft\Windows\TaskScheduler):
-- SELECT TaskName, TaskPath, State FROM MSFT_ScheduledTask
Tærskler (agentens appsettings.json) -- CIM-metode (skrivebeskyttet) pr. overvåget opgave:
SQLInsight:Servers:Tasks:LateMinutes standard 60 (næste kørsel mere end så mange minutter i fortiden) -- PS_ScheduledTask.GetInfoByName(TaskName, TaskPath) -> cmdletOutput: MSFT_TaskDynamicInfo
SQLInsight:Servers:Tasks:IncludeMicrosoftTasks standard false --
SQLInsight:Servers:Tasks:Ignore opgaver der aldrig overvåges -- Efterprøv med PowerShell (skrivebeskyttet; kør på agentens server som agentens konto):
-- $s = New-CimSession -ComputerName SERVER
Alvor -- Get-ScheduledTask -CimSession $s | Where-Object { $_.TaskPath -notlike '\Microsoft\*' -and $_.State -ne 'Disabled' } |
Middel. -- Get-ScheduledTaskInfo -CimSession $s | Where-Object { $_.NumberOfMissedRuns -gt 0 -or ($_.NextRunTime -and $_.NextRunTime -lt (Get-Date).AddMinutes(-60)) }
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)) }
*/

View 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

View file

@ -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> /// <summary>At most this much of an HTTP answer is read when looking for the expected text.</summary>
public const int MaxBodyBytes = 1024 * 1024; 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) public async Task<SyntheticCheckResult> RunAsync(SyntheticCheckRun run, CancellationToken cancellationToken)
{ {
ArgumentNullException.ThrowIfNull(run); 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)); var timeoutSeconds = Math.Max(1, (int)Math.Ceiling(run.Timeout.TotalSeconds));
if (!string.IsNullOrWhiteSpace(settings.Database)) 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. // 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 queryStarted = time.GetTimestamp();
var rows = 0; var rows = 0;
try try
@ -313,15 +326,35 @@ public sealed class SyntheticCheckRunner(ISqlConnectionFactory sqlConnections, I
await using var command = opened.Connection.CreateCommand(); await using var command = opened.Connection.CreateCommand();
command.CommandText = query; command.CommandText = query;
command.CommandTimeout = timeoutSeconds; command.CommandTimeout = timeoutSeconds;
await using var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
while (rows < 10000 && await reader.ReadAsync(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 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; var queryMs = (int)time.GetElapsedTime(queryStarted).TotalMilliseconds;

View file

@ -10,6 +10,8 @@
<!-- SqlScriptTests: rule ids, and the SQL the connection itself sends. --> <!-- SqlScriptTests: rule ids, and the SQL the connection itself sends. -->
<ProjectReference Include="..\..\src\SQLInsight.Rules\SQLInsight.Rules.csproj" /> <ProjectReference Include="..\..\src\SQLInsight.Rules\SQLInsight.Rules.csproj" />
<ProjectReference Include="..\..\src\SQLInsight.Connectivity\SQLInsight.Connectivity.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>
<ItemGroup> <ItemGroup>
<!-- Dynamics AX schemas (real and documented): the AX collectors' SQL is checked for every version adapter. --> <!-- Dynamics AX schemas (real and documented): the AX collectors' SQL is checked for every version adapter. -->

View file

@ -7,6 +7,8 @@ using SQLInsight.Collectors.Discovery;
using SQLInsight.Collectors.Instance; using SQLInsight.Collectors.Instance;
using SQLInsight.Collectors.Performance; using SQLInsight.Collectors.Performance;
using SQLInsight.Core.Instances; using SQLInsight.Core.Instances;
using SQLInsight.Core.SyntheticChecks;
using SQLInsight.Servers.Synthetic;
namespace SQLInsight.Collectors.Tests.SqlScripts; namespace SQLInsight.Collectors.Tests.SqlScripts;
@ -346,9 +348,27 @@ internal static class SqlScriptSources
}; };
sources.AddRange(DynamicsAx()); sources.AddRange(DynamicsAx());
sources.AddRange(SyntheticCheck());
return sources; 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> /// <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"; public const string AxExampleDatabase = "AXDB";

View file

@ -2,6 +2,7 @@ using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using SQLInsight.Rules; using SQLInsight.Rules;
using SQLInsight.Rules.Lifecycle; using SQLInsight.Rules.Lifecycle;
using SQLInsight.Rules.Servers;
namespace SQLInsight.Collectors.Tests.SqlScripts; namespace SQLInsight.Collectors.Tests.SqlScripts;
@ -13,10 +14,14 @@ public sealed partial class SqlScriptTests
{ {
private static readonly string Folder = Path.Combine(RepositoryRoot(), "SQL Scripts"); 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] [Fact]
public void Every_registered_rule_has_a_script_and_every_script_a_rule() public void Every_registered_rule_has_a_script_and_every_script_a_rule()
{ {
var ids = BuiltInRules.Create().Select(r => r.Id) var ids = BuiltInRules.Create().Select(r => r.Id)
.Concat(ServerRuleIds)
.Concat(RulePack.Embedded().CommunityRules.Select(r => r.Id)) .Concat(RulePack.Embedded().CommunityRules.Select(r => r.Id))
.ToHashSet(StringComparer.Ordinal); .ToHashSet(StringComparer.Ordinal);
var files = Directory.EnumerateFiles(Folder, "*.sql", SearchOption.TopDirectoryOnly) var files = Directory.EnumerateFiles(Folder, "*.sql", SearchOption.TopDirectoryOnly)
@ -66,7 +71,7 @@ public sealed partial class SqlScriptTests
} }
var blocks = Blocks(Read(file)).ToList(); 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"); problems.Add($"{name}: ingen '-- Kilde:'-blokke");
} }

View file

@ -19,5 +19,18 @@ public class RuleCatalogTests
public void Rule_count() public void Rule_count()
{ {
Assert.Equal(92, BuiltInRules.Create().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)));
} }
} }

View file

@ -28,9 +28,10 @@ public class ServerRuleScriptTests
{ {
var file = Path.Combine(folder.FullName, rule.Id + ".sql"); var file = Path.Combine(folder.FullName, rule.Id + ".sql");
Assert.True(File.Exists(file), $"{rule.Id}.sql mangler i SQL Scripts/."); Assert.True(File.Exists(file), $"{rule.Id}.sql mangler i SQL Scripts/.");
var text = File.ReadAllText(file); var text = File.ReadAllText(file).Replace("\r\n", "\n", StringComparison.Ordinal);
Assert.Contains($"{rule.Id} – {rule.Title}", text, StringComparison.Ordinal); Assert.Contains($"-- Regel-id: {rule.Id}\n", text, StringComparison.Ordinal);
Assert.Contains("Evaluering", text, StringComparison.Ordinal); Assert.Contains($"-- Titel: {rule.Title}\n", text, StringComparison.Ordinal);
Assert.Contains("-- Vurdering", text, StringComparison.Ordinal);
Assert.DoesNotContain("sysadmin", text, StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("sysadmin", text, StringComparison.OrdinalIgnoreCase);
}); });
} }

View 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();
}