# Windows-servere Fra version 1.5 overvåger SQLInsight også selve Windows-serverne: **CPU, hukommelse, diske, tjenester, hændelseslog og planlagte opgaver** på SQL-, applikations-/AOS- og filservere – med varsel om, at en disk løber fuld om et antal dage, før det sker. Det findes under **Servere → Windows-servere** i webbrugerfladen og i API'et (se [nedenfor](#api)). - **SQL Server-hosts kommer med af sig selv.** Serveren bag hver instans under *Servere og databaser* (se [servere-og-databaser.md](servere-og-databaser.md)) bliver en Windows-server med rollen *SQL Server*. Den forsvinder igen, når instansen fjernes, og kan sættes på pause. Azure SQL og LocalDB springes over. Slås fra med `SQLInsight:Servers:IncludeSqlHosts`. - **Andre servere tilføjes** i webbrugerfladen: AOS- og applikationsservere, rapport- og filservere. Angiv servernavnet (uden instans og port), rollen og eventuelt de tjenester, der altid skal køre (fx `AOS60$01`, `W3SVC`). SQLInsight **ændrer aldrig noget** på serverne: agenten læser kun. Den starter, stopper eller genstarter ingen tjenester og rydder ikke op – fundene siger, hvad der bør gøres, og en driftsansvarlig gør det. ## Sådan læser agenten serverne Agenten læser serverne **som sin egen konto** (den samme som til SQL Server) med CIM – det samme, PowerShells `Get-CimInstance` bruger: 1. **WinRM (WS-Man)**, TCP 5985, når kontoen har læseret i WinRM (tildelingsscriptet med `-WinRM`, Windows Server 2012 og nyere). 2. **DCOM (RPC)**, TCP 135 og dynamiske porte, hvis WinRM ikke svarer eller afviser kontoen. Det er standard med tildelingsscriptet. 3. Agentens egen server læses lokalt, uden netværk. `SQLInsight:Servers:Protocol` kan låse det til `WSMan` eller `DCOM` (standard `Auto`). WinRM over HTTPS (TCP 5986) understøttes ikke i 1.5. Hændelsesloggen læses med hændelseslogtjenestens egen protokol (MS-EVEN6, over RPC), som filtrerer på serveren og derfor er hurtig; virker den ikke, bruges CIM (`Win32_NTLogEvent`), som er langsommere. Siden for serveren viser, hvordan den blev læst. Kører agenten som den virtuelle konto `NT SERVICE\SQLInsight Agent` (standard), LocalSystem eller NETWORK SERVICE, kommer den til andre servere som **computerkontoen** `DOMÆNE\AGENTSERVER$`. En gMSA eller domænekonto er den samme overalt. Siden viser den konto, scriptet nedenfor skal give rettigheder til. ## Rettigheder (aldrig lokal administrator) Agenten skal **ikke** være lokal administrator og får ingen ret til at køre kode på serverne. Den har brug for præcis dette, og intet andet: | Rettighed | Bruges til | |---|---| | Lokal gruppe **Performance Monitor Users** | Ydelsestællere: CPU, hukommelse, paging, commit | | Lokal gruppe **Event Log Readers** | Hændelseslogge, der tillader gruppen: System, Application m.fl. (aldrig Security-loggen) | | Lokal gruppe **Distributed COM Users** | CIM over DCOM | | WMI: **Enable Account** + **Remote Enable** på `root\cimv2` | Styresystem, oppetid, diske, tjenester | | WMI: **Enable Account** + **Remote Enable** på `root\Microsoft\Windows\TaskScheduler` | Planlagte opgaver (Windows Server 2012 og nyere) | | **Service Control Manager**: forbinde, liste og læse (`CC LC RP RC`) | Over netværket må ellers kun administratorer liste tjenester. Det er det samme, en lokalt logget på bruger har; ingen ret til at starte eller stoppe | | Kun med `-WinRM`: **læseret i WinRM** (`GENERIC_READ` i RootSDDL, ingen Execute) | CIM over WinRM. Kontoen kommer *ikke* i Remote Management Users, for den gruppe giver også adgang til PowerShell Remoting | Det hele gives af [`grant-windows-server.ps1`](../db/permissions/grant-windows-server.ps1). Webbrugerfladen viser scriptet udfyldt med agentens konto under **Rettigheder og forbindelse** på serverens side (kopiér eller hent som fil; API: `GET /api/v1/windows-servers/{id}/grant-script`). Scriptet ændrer sikkerheden på kundens server, så **afprøv det først på en server, der ikke er i produktion**, og kør det med `-WhatIf` for at se, hvad det vil gøre. En administrator kører det på serveren: ```powershell .\grant-windows-server.ps1 -Account 'DOMÆNE\AGENTSERVER$' -WhatIf # viser planen, ændrer intet .\grant-windows-server.ps1 -Account 'DOMÆNE\AGENTSERVER$' # DCOM (standard) .\grant-windows-server.ps1 -Account 'DOMÆNE\AGENTSERVER$' -WinRM # også læseret i WinRM .\grant-windows-server.ps1 -Account 'DOMÆNE\AGENTSERVER$' -EnableFirewall -AgentAddress 10.0.0.15 # egne firewallregler, kun fra agenten .\grant-windows-server.ps1 -Account 'DOMÆNE\AGENTSERVER$' -Remove # fjerner præcis det, scriptet gav ``` Scriptet virker på Windows PowerShell 2.0 og nyere og skal køres som administrator. Grupperne findes via deres SID, så det virker på dansk og engelsk Windows. Sikkerhedsnettet: - **Intet ændres, før alt er kontrolleret:** kontoen skal kunne slås op (brede grupper som Everyone, Authenticated Users eller Domain Users afvises), og har kontoen en *Nægt*-regel på WMI, Service Control Manager eller WinRM, stopper scriptet uden at ændre noget. - **Kun det nødvendige:** har kontoen allerede en rettighed, røres den ikke. Hver ændring er præcis én ny regel (kontrolleret, før den skrives), og hvert skridt kontrolleres bagefter. - **Backup:** før første ændring gemmes de oprindelige indstillinger (SDDL for Service Control Manager, WMI-navnerummene og WinRM, gruppemedlemskaber og firewallregler) i `%ProgramData%\SQLInsight\grant-windows-server\--foer.xml`. - **Præcis fjernelse:** hvad scriptet selv har tilføjet, står i `%ProgramData%\SQLInsight\grant-windows-server\.xml` (kun administratorer har adgang til mappen). `-Remove` fjerner kun det – et gruppemedlemskab eller en rettighed, kontoen havde før, bevares. Fejler et skridt undervejs, står det, der allerede er gjort, i filen, så scriptet kan køres igen eller med `-Remove`. - Service Control Manager kan gendannes manuelt med `sc.exe sdset scmanager ""`. Kendte begrænsninger med mindst mulige rettigheder: - **Tjenester:** en tjeneste, hvis egen sikkerhed ikke lader kontoen læse den, ses ikke. Ser agenten slet ingen tjenester, er området "ikke målbart" med årsagen. - **Planlagte opgaver:** agenten ser kun opgaver, kontoen må læse. Seneste resultat læses med Task Schedulers `GetInfoByName` (et skrivebeskyttet CIM-metodekald, som `Get-ScheduledTaskInfo`). Det kræver Windows' standardret *Execute Methods* på navnerummet (som Authenticated Users arver fra `root`); scriptet giver ikke mere. Over WinRM med kun læseret er metodekald ikke tilladt, så agenten læser opgaverne over DCOM (med `Protocol` = `Auto`); er protokollen låst til `WSMan`, er området "ikke målbart" med årsagen. - **Windows Server 2008 R2:** opgave-navnerummet findes ikke, så planlagte opgaver er "ikke målbare"; brug DCOM. ### Når en rettighed mangler Testen (**Test forbindelsen** på serverens side, eller `POST /api/v1/windows-servers/{id}/test`) udføres af agenten, som dens konto, og prøver hvert område én gang. Tabellen viser for hvert område *Kan læses* eller *Ikke målbar* med den præcise årsag, fx > Adgang nægtet til hændelseslog på aos01.firma.local over WS-Man: Agentens konto (FIRMA\AGENT01$) mangler Event Log Readers. Kør tildelingsscriptet (grant-windows-server.ps1) som administrator på serveren, og test igen. Agenten skal ikke være lokal administrator. Under overvågningen gælder det samme: et område, der ikke kan læses, gør kun dets regler "ikke målbare" med årsagen (under *Ikke målbart* på siden), og fund fra før forbliver åbne, indtil området kan læses igen. Problemet skrives én gang i agentens log, når det opstår eller ændrer sig – ikke hvert minut. Svarer serveren slet ikke, sendes én notifikation ("kan ikke nås") og én, når den svarer igen. ## Firewall Fra agentens server til de overvågede servere: | Port | Hvad | Tildelingsscriptets regel (`-EnableFirewall`) | |---|---|---| | TCP 135 + dynamiske RPC-porte (49152–65535) | DCOM/WMI (standard) | *SQLInsight Agent: RPC Endpoint Mapper* og *SQLInsight Agent: WMI over DCOM* | | TCP 135 + dynamiske RPC-porte | Hændelsesloggen (MS-EVEN6) | *SQLInsight Agent: hændelseslog (RPC)* | | TCP 5985 | WinRM (WS-Man), kun med `-WinRM` | *SQLInsight Agent: WinRM (HTTP 5985)* | `grant-windows-server.ps1 -EnableFirewall -AgentAddress ` opretter scriptets egne regler, kun for agentens adresse (Windows Server 2012 og nyere); `-AgentAddress` er påkrævet, så portene aldrig åbnes for alle. Windows' indbyggede regler røres ikke, og `-Remove` fjerner scriptets egne regler igen. Syntetiske tjek bruger de porte, de tjekker (se [syntetiske-tjek.md](syntetiske-tjek.md)). ## Hvad måles, og hvor ofte | Område | Interval | Hvad | |---|---|---| | CPU, hukommelse, oppetid | 1 minut | Gennemsnitlig CPU pr. minut (rå tællere, ikke et øjebliksbillede), ledig hukommelse, paging, commit, starttidspunkt | | Diske | 15 minutter | Ledig plads pr. drev og monteringspunkt; prognose for, hvornår drevet er fuldt | | Tjenester | 5 minutter | Alle tjenester med status og starttype | | Hændelseslog | 5 minutter | Fejl og kritiske hændelser i System og Application siden sidst (første gang det seneste døgn) | | Planlagte opgaver | 15 minutter | Opgaver uden for `\Microsoft\` med seneste kørsel, resultat og næste kørsel | Intervallerne ændres under `SQLInsight:Servers:Intervals` (`performance`, `disks`, `services`, `events`, `tasks`). Højst `MaxParallelServers` (standard 4, 1–32) servere læses ad gangen. Hver CIM-operation har en timeout (`OperationTimeout`, 5 sekunder–5 minutter), og en hel indsamling for én server højst `CycleTimeout` (standard 5 minutter, 1–30); når den er brugt, er resten "ikke målbart" til næste gang, og planlagte opgaver har en tredjedel af tiden. En server, der hænger eller ikke svarer, kan derfor aldrig holde agenten op. Svarer den ikke, prøves den igen efter 1, 2, 5, 10 og derefter hvert 15. minut, og den protokol, der virkede, huskes en time. ### "Disken er fuld om ca. N dage" Ledig plads pr. drev gemmes hvert 15. minut i SQLInsights repository. Prognosen lægger en ret linje (mindste kvadraters metode) gennem timegennemsnittene for de seneste 14 dage (`Disks:ForecastHistoryDays`) – kun siden drevet sidst skiftede størrelse, så et udvidet drev starter forfra. Der gives kun en prognose, når der er mindst to dages historik og 12 målinger, linjen passer rimeligt (R² mindst 0,5), drevet faktisk fyldes (mindst 0,01 GB om dagen), og den rammer inden for et år. Et backupdrev, der fyldes om natten og ryddes om morgenen, giver derfor ingen alarm. Fundet kommer, når drevet forventes fuldt inden for 30 dage (`Disks:ForecastDays`): Middel, inden for 7 dage Høj, inden for 2 dage Kritisk. ### Hændelsesloggen Som SQL Servers fejllog (se [fejllog.md](fejllog.md)) grupperes hændelserne pr. log, kilde og hændelses-id med antal, første og seneste tidspunkt og den nyeste tekst som eksempel. Kendt støj sorteres fra (DCOM 10016/10010, Schannel-alarmer, TPM-WMI, WMI 10 m.fl.), og det samme gør SQL Servers egne kilder (`MSSQLSERVER`, `MSSQL$…`, `SQLSERVERAGENT` …), som SQL Server-overvågningen allerede dækker. Egen støj tilføjes under `EventLog:Ignore` som `"Kilde:id"`, `"Kilde"` eller `"Kilde*"`. Disk- og filsystemfejl, opbrugte ressourcer og kritiske hændelser giver fund med det samme; tjenester der går ned, programnedbrud og Dynamics AX' AOS-fejl også; almindelige fejl først, når de er set 5 gange på et døgn (`EventLog:RepeatThreshold`). Et fund forbliver åbent et døgn efter hændelsen sidst blev set. Eksempelteksten kan nævne brugere, computere og stier: den vises i webbrugerfladen, men er `[udeladt]` i API'et. ## Regler | Regel | Fund | Tærskel (`SQLInsight:Servers:…`) | |---|---|---| | SQLI-WIN-001 | CPU højt i længere tid (Høj; Kritisk fra 98 %) | `Cpu:HighPercent` 90 % i `Cpu:SustainedMinutes` 15 min. | | SQLI-WIN-002 | Næsten ingen ledig hukommelse (Middel; Høj under 2 % og 256 MB) | under `Memory:AvailablePercent` 5 % **og** `Memory:AvailableMegabytes` 1024 MB (5 min.) | | SQLI-WIN-003 | Paging med lidt ledig hukommelse | `Memory:PagesPerSecond` 1000 (15 min.) og under 10 % ledig (fast i koden) | | SQLI-WIN-004 | Commit tæt på grænsen (Middel; Høj fra 97 %) | `Memory:CommitPercent` 90 % | | SQLI-WIN-005 | Lidt ledig plads på et drev | under `Disks:FreePercent` 10 % (Høj under `CriticalFreePercent` 5 %, Kritisk under 1 GB eller 1 %), medmindre mindst `EnoughFreeGigabytes` 50 GB er ledig | | SQLI-WIN-006 | Drevet er fuldt om ca. N dage ("ikke målbar", indtil der er historik nok) | `Disks:ForecastDays` 30 | | SQLI-WIN-007 | Automatisk tjeneste kører ikke | `Services:Ignore` (navn eller visningsnavn, `*` til sidst), `Services:StartupGraceMinutes` 15 ("ikke målbar" lige efter en genstart, så åbne fund bliver stående), `Services:MaxFindings` 15 (resten samles i ét fund); tjenester der stopper af sig selv (sppsvc, opdateringstjenester …) giver ingen fund | | SQLI-WIN-008 | Overvåget tjeneste kører ikke (eller findes ikke) | listen pr. server | | SQLI-WIN-009 | Fejl i hændelsesloggen | `EventLog:RepeatThreshold` 5 inden for de seneste 24 timer (talt pr. time), `EventLog:MaxFindings` 15 (resten samles i ét fund) | | SQLI-WIN-010 | Serveren er genstartet (uventet: Høj; planlagt: Info i et døgn; Lav, hvis hændelsesloggen ikke kan læses; "ikke målbar", til loggen er læst efter genstarten) | Kernel-Power 41, EventLog 6008, BugCheck 1001 | | SQLI-WIN-011 | Ikke genstartet i lang tid | `UptimeDays` (standard 0 = slået fra) | | SQLI-WIN-012 | Planlagt opgave fejlede | `Tasks:IncludeMicrosoftTasks`, `Tasks:Ignore`, `Tasks:MaxWatched` 50, `Tasks:IgnoreUserAndUpdaterTasks` (standard til: opgaver pr. bruger med SID i navnet, OneDrive-, Edge- og Google-opdatering) | | SQLI-WIN-013 | Planlagt opgave kørte ikke som planlagt | `Tasks:LateMinutes` 60 | Hver regel har sit eget script i [`SQL Scripts/`](../SQL%20Scripts/) (fx `SQLI-WIN-006.sql`) med de præcise CIM/WQL-forespørgsler og en skrivebeskyttet PowerShell-linje, der efterprøver dem. Fund på servere vises på serverens side, under **Aktive fund på servere og syntetiske tjek** på siden Windows-servere, sendes som notifikationer (med link til fundet) og findes i API'et. De sendes ikke til SQLInsight Hub og indgår endnu ikke i PDF-rapporterne. ## Opbevaring | Data | Standard | Indstilling | |---|---|---| | CPU og hukommelse pr. minut | 14 dage | `SQLInsight:Servers:SampleDays` | | Ledig plads pr. drev | 35 dage (mindst prognosens historik) | `SQLInsight:Servers:DiskHistoryDays` | | Grupperede hændelser | 90 dage | `SQLInsight:Servers:EventDays` | | Løste fund | 365 dage | `SQLInsight:Retention:ResolvedFindingDays` | En server med 5 drev fylder omkring 1.440 rækker om dagen for CPU/hukommelse og 480 for diskene. Agenten sletter i små portioner hver time. ## Konfiguration Alle tærskler, intervaller og opbevaringstider står i agentens `appsettings.json` under `SQLInsight:Servers`. Ændringer kræver en genstart af agenten. Servere, roller og tjenestelister ændres i webbrugerfladen og bruges inden for et minut. ## API | Kald | Svar | |---|---| | `GET /api/v1/windows-servers` | Servere med status, styresystem, protokol, områdernes målbarhed, seneste CPU/hukommelse, fyldigste drev, nærmeste "fuld"-prognose og antal fund | | `POST /api/v1/windows-servers` | Tilføj (`host`, `name`, `role`, `watchedServices`, `ignoredServices`); 201 med `serverTestRequestId` | | `GET`, `PATCH`, `DELETE /api/v1/windows-servers/{id}` | Én server; pause, rolle og tjenestelister; fjern (409 for SQL Server-hosts) | | `POST`, `GET /api/v1/windows-servers/{id}/test` | Test forbindelse og rettigheder (202, følg `GET /api/v1/agent-requests/{id}`; venter en test allerede, gives den samme); seneste test med manglende områder | | `GET /api/v1/windows-servers/{id}/grant-script` | Scriptet udfyldt med agentens konto (kontoen er `[udeladt]`, og scriptet er skabelonen, medmindre følsomme data er slået til) | | `GET /api/v1/windows-servers/{id}/performance?hours=24` | CPU og hukommelse pr. minut | | `GET /api/v1/windows-servers/{id}/disks` | Drev med ledig plads og prognose | | `GET /api/v1/windows-servers/{id}/services` | Tjenester og serverens lister | | `GET /api/v1/windows-servers/{id}/events?days=1` | `capturedAt`, `method`, `ignored`, `coverage` og de grupperede hændelser (eksemplet er `[udeladt]`) | | `GET /api/v1/windows-servers/{id}/tasks` | Overvågede planlagte opgaver | | `GET /api/v1/windows-servers/{id}/rule-states` | Reglernes udfald med årsag | | `GET /api/v1/server-findings?status=&scope=server&id=&limit=&continuation=` | Fund på servere og syntetiske tjek, højst `limit` (standard 100, højst 500) ad gangen, næste side via `X-Continuation`. Aktive fund på servere og tjek på pause eller fjernede er ikke med, medmindre `scope` og `id` angives | | `GET /api/v1/server-findings/{id}` | Ét fund med tidligere forekomster (`history`) | At ændre kræver scope `config:write` (API-token) eller medlemskab af `SQLInsight:Web:AdminGroups` (Windows-brugere; er den tom, den lokale gruppe Administratorer på webserveren), som for *Servere og databaser*. Hvem der har oprettet og ændret, og agentens konto i fejltekster, er `[udeladt]`, medmindre `SQLInsight:Web:ApiIncludesSensitiveEvidence` er slået til. Fjernes en server, beholdes dens syntetiske tjek, men uden server og tjeneste.