# Copyright (c) 2026, R. W. Rodolico # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # windows_system.ps1 # Boot time, uptime and operating system facts. # Sensor contract: unix/sensors/Documentation/README.md; keys: Documentation/Spec.md 7.6 # Must stay Windows PowerShell 5.1 compatible and pure ASCII. # # Version 1.0.0 20261018 Claude # Initial version (bug 211, stage W2) Import-Module ([IO.Path]::Combine($PSScriptRoot, '..', 'lib', 'SysinfoSensor.psm1')) Test-SysinfoWindows Invoke-SysinfoSensor { if ($null -eq (Get-Command Get-CimInstance -ErrorAction SilentlyContinue)) { Exit-SysinfoSensor -Code $SYSINFO_EXIT_NOT_APPLICABLE -Message 'Get-CimInstance not available' } $os = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop | Select-Object -First 1 if ($null -eq $os) { Exit-SysinfoSensor -Code $SYSINFO_EXIT_NOT_APPLICABLE -Message 'Win32_OperatingSystem returned nothing' } # UTC epoch; a DateTime of Kind Unspecified or Local is taken as local time $boot = New-Object System.DateTimeOffset ([datetime]$os.LastBootUpTime) $lastBoot = $boot.ToUnixTimeSeconds() $now = [System.DateTimeOffset]::UtcNow.ToUnixTimeSeconds() $ubr = '' $release = '' $base = [Microsoft.Win32.RegistryKey]::OpenBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, [Microsoft.Win32.RegistryView]::Registry64) try { $key = $base.OpenSubKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion') if ($null -ne $key) { try { $ubr = [string]$key.GetValue('UBR', '') $release = [string]$key.GetValue('DisplayVersion', '') if ($release.Trim() -eq '') { $release = [string]$key.GetValue('ReleaseId', '') } } finally { $key.Close() } } } finally { $base.Close() } $version = [string]$os.Version $kernel = $version if ($ubr -ne '') { $kernel = "$version.$ubr" } Write-SysinfoFact -Path @('system', 'last_boot') -Value $lastBoot Write-SysinfoFact -Path @('system', 'uptime') -Value ([math]::Max(0, $now - $lastBoot)) Write-SysinfoFact -Path @('operatingsystem', 'os_name') -Value 'Windows' Write-SysinfoFact -Path @('operatingsystem', 'description') -Value $os.Caption Write-SysinfoFact -Path @('operatingsystem', 'os_version') -Value $version Write-SysinfoFact -Path @('operatingsystem', 'kernel') -Value $kernel Write-SysinfoFact -Path @('operatingsystem', 'release') -Value $release }