Private/Signal.ps1
|
# The Signals: what a Finding observed, by a name that stays when its wording changes. # # A Finding's Check and Value are worded for a Technician and reworded whenever that helps # one. What reads several Findings together - a Reference from one to another, a Lead - # cannot go by that wording, so the Judge that produces a Finding says what it observed # with a name from this list. See ADR-0005. # # One list, because two Kinds that named the same observation differently would never # meet, and nothing would fail. A Signal is declared when the thing was observed: a # Finding that says "no disk errors" carries none. # Each with the Kinds that declare it: a Check that was skipped, or was refused the rights # it needed, can then say what it would have looked for. "No Lead" and "not looked" must # not read the same. A Kind that measures Servers through the Server Kind's Judge - Odbc, # AppConnection - declares what that Judge declares. $script:SignalValues = [ordered]@{ 'disk-errors' = @{ Kind = @('Stability'); Description = 'Windows logged errors of a disk, its controller or its file system' } 'drive-health-warning' = @{ Kind = @('DiskHealth'); Description = 'A drive reports wear, uncorrected errors or a temperature beyond its limits' } 'stop-code-disk' = @{ Kind = @('Stability'); Description = 'A blue screen whose stop code says a drive or its file system could not be read' } 'disk-write-slow' = @{ Kind = @('DiskTest'); Description = 'The disk write test was slower than its thresholds allow' } 'system-drive-low' = @{ Kind = @('Storage'); Description = 'The system drive has less free space than the Storage Check allows' } 'program-not-paged-in' = @{ Kind = @('Stability'); Description = 'A program installed on a local drive crashed because a page of it could not be read' } 'stop-code-memory' = @{ Kind = @('Stability'); Description = 'A blue screen whose stop code says memory or its management was corrupted' } 'hardware-errors' = @{ Kind = @('Stability'); Description = 'Windows logged hardware errors (WHEA): processor, memory or a bus' } 'memory-errors' = @{ Kind = @('Stability'); Description = 'Windows logged hardware errors (WHEA) of the memory' } 'access-violations-spread' = @{ Kind = @('Stability'); Description = 'Several unrelated programs crashed with an access violation' } 'stop-code-graphics' = @{ Kind = @('Stability'); Description = 'A blue screen whose stop code says the display driver could not be reset' } 'live-kernel-graphics' = @{ Kind = @('Stability'); Description = 'Windows recovered from a hang or fault of the graphics driver' } 'graphics-driver-old' = @{ Kind = @('System'); Description = 'The graphics driver is older than the age the Check notes' } 'link-dropped' = @{ Kind = @('NetworkDisruption'); Description = 'The network was disconnected at the device, or its adapter was reset' } 'servers-lost' = @{ Kind = @('NetworkDisruption'); Description = 'Existing connections to several Servers were lost' } 'cable-wifi-switching' = @{ Kind = @('NetworkDisruption'); Description = 'The network went away and a Wi-Fi disconnect followed shortly, repeatedly: the cable connection fails over to Wi-Fi and back' } 'server-lost' = @{ Kind = @('NetworkDisruption'); Description = 'Existing connections to one Server only were lost; its subject is that Server' } 'loss-on-own-network' = @{ Kind = @('Server', 'Odbc', 'AppConnection'); Description = 'Pings to a Server in the machine''s own network were lost' } 'usb-network-adapter' = @{ Kind = @('NetworkDependency'); Description = 'Programs on a share are reached through a USB network adapter' } 'adapter-power-saving' = @{ Kind = @('Network'); Description = 'A network adapter that is up has power saving on: Windows may switch it off' } 'crash-with-network-disruption' = @{ Kind = @('Stability'); Description = 'A program''s crashes coincide with network disruptions' } 'server-slow' = @{ Kind = @('Server', 'NetworkDependency', 'Odbc', 'AppConnection'); Description = 'A Server answers slowly, with loss or only some of the time; its subject is that Server' } 'server-unreachable' = @{ Kind = @('Server', 'NetworkDependency', 'Odbc', 'AppConnection'); Description = 'A Server does not answer; its subject is that Server' } # Of the Server itself, not of a Service of it: what tells the Server not answering from # each of its Services refused alike, which are one Signal however many (ADR-0015). 'ping-unanswered' = @{ Kind = @('Server', 'Odbc', 'AppConnection'); Description = 'A Server answered no ping, and none of its ports that were tried answered either; its subject is that Server' } 'printer-offline' = @{ Kind = @('Printing'); Description = 'Windows reports a printer other than the default as offline' } 'print-job-stuck' = @{ Kind = @('Printing'); Description = 'A print job has been lying in a queue for longer than the Check allows' } 'dependency-on-server' = @{ Kind = @('NetworkDependency'); Description = 'A program runs from a share of a Server; its subject is that Server' } 'drive-mapping-slow' = @{ Kind = @('GroupPolicy'); Description = 'The part of Group Policy that maps the drives took long in some of its runs' } 'share-not-found' = @{ Kind = @('NetworkDisruption'); Description = 'A Server answered that it does not have the share it was asked for' } 'sign-in-intermittent' = @{ Kind = @('Logon'); Description = 'Some sign-ins of the User are slow and others are not' } 'sign-in-by-controller' = @{ Kind = @('Logon'); Description = 'The slow sign-ins went to another domain controller than the quick ones' } 'controller-differs' = @{ Kind = @('Domain'); Description = 'One domain controller does not answer, or does not have or is slow to give what the others have' } 'namespace-target-gone' = @{ Kind = @('Domain'); Description = 'The DFS namespace behind the domain''s name names a Server that is not there' } 'namespace-unreachable' = @{ Kind = @('Domain'); Description = 'A folder of the DFS namespace behind the domain''s name has no Server it hands out that answers; the Namespace is one of its parts' } 'policies-differ' = @{ Kind = @('Domain'); Description = 'The domain controllers hold different versions of a policy in SYSVOL' } # Of NetworkProtocol, which reads the sign-ins Windows logs however it is set up. AppLog and # Nextcloud declare it too, where what they read names an HTTP status - a Definition whose # pattern reads one, a Nextcloud client up to 3.16 - and are not listed: a skipped one would # say it looked for what it may never have seen. 'service-denied' = @{ Kind = @('NetworkProtocol'); Description = 'A Service answered and refused the identity it was given: HTTP 401 or 403, a Kerberos ticket refused, a sign-in that failed' } # Causes of a refusal, which a Lead joins to it (ADR-0016). Their subject is the account's # Service. 'credential-missing' = @{ Kind = @('Nextcloud'); Description = 'No credential is saved for an account of an App, by the target names the user''s credential store lists: the App cannot sign in without asking' } 'credential-refused' = @{ Kind = @('Nextcloud'); Description = 'An account''s Service refused it, and let it in on no attempt since: its saved credential is no longer accepted' } 'service-maintenance' = @{ Kind = @('Nextcloud'); Description = 'A Service says, asked without credentials, that it is in maintenance or waits for an upgrade to finish: it refuses every sign-in while that lasts' } # Of a Service that offers Windows sign-in: one cause of a refusal, which a Lead joins to it. 'spn-missing' = @{ Kind = @('Kerberos'); Description = 'An HTTPS Service offers Windows sign-in (Negotiate) and the directory has no SPN HTTP/<host> or HOST/<host> for it: the client falls back to NTLM, or fails; its subject is that Service' } 'spn-duplicate' = @{ Kind = @('Kerberos'); Description = 'The directory has the SPN of an HTTPS Service (HTTP/<host>, or HOST/<host> where there is no HTTP one) on two or more accounts: the domain controller cannot tell which account the ticket is for, and Windows sign-in to the Service fails or falls back to NTLM; its subject is that Service' } # Of the machine's clock and of the tickets refused to it: a Lead joins the two, the clock # being the cause. Of the machine, and of no Service. 'clock-off' = @{ Kind = @('NetworkProtocol'); Description = 'This machine''s clock is further from its time source than the Check allows: Kerberos refuses a ticket from a clock more than five minutes off' } 'kerberos-refused' = @{ Kind = @('NetworkProtocol'); Description = 'Windows logged that a Server refused a Kerberos ticket of this machine: Kerberos events 4 and 5 (a ticket refused, the clock)' } # Said of the time of events, not of what they were: two Findings at 14:01 every day are # what a later Lead connects. 'events-daily' = @{ Kind = @('NetworkDisruption', 'NetworkProtocol', 'RemoteDesktop', 'Printing', 'GroupPolicy'); Description = 'Events a Finding counts come back at the same time of day on many days' } 'events-burst' = @{ Kind = @('NetworkDisruption', 'NetworkProtocol', 'RemoteDesktop', 'Printing', 'GroupPolicy'); Description = 'Most of the events a Finding counts fell in one short window' } } function Get-SignalList { <# .SYNOPSIS Every Signal a Judge may declare, with what it marks and which Kinds declare it. #> [CmdletBinding()] [OutputType([psobject])] param() foreach ($name in $script:SignalValues.Keys) { [pscustomobject]@{ Name = $name; Description = $script:SignalValues[$name].Description; Kind = @($script:SignalValues[$name].Kind) } } } function Get-SignalOfKind { <# .SYNOPSIS The Signals a Kind can declare: what a Check of that Kind would have looked for. #> [CmdletBinding()] [OutputType([string])] param([AllowNull()][AllowEmptyCollection()][string[]]$Kind) $kinds = @($Kind | Where-Object { $_ }) foreach ($name in $script:SignalValues.Keys) { if (@($script:SignalValues[$name].Kind | Where-Object { $_ -in $kinds }).Count) { $name } } } function Assert-Signal { <# .SYNOPSIS Throws for a Signal that is not on the list, naming it and the list. #> [CmdletBinding()] param([AllowNull()][AllowEmptyCollection()][string[]]$Signal) foreach ($name in @($Signal | Where-Object { $_ })) { if (-not $script:SignalValues.Contains($name)) { throw ("'{0}' is not a Signal. Add it to Private/Signal.ps1, or use one of: {1}." -f $name, (@($script:SignalValues.Keys) -join ', ')) } } } |