Public/system/Get-SystemSummary.ps1

#Requires -Version 5.1
function Get-SystemSummary {
    <#
        .SYNOPSIS
            Gather comprehensive system information from Windows machines
 
        .DESCRIPTION
            Queries six WMI/CIM classes to build a detailed system summary for local or remote
            Windows machines. Supports pipeline input, explicit credentials for remote hosts,
            and returns a structured PSCustomObject per machine. CIM session management and
            cleanup are handled automatically.
 
        .PARAMETER ComputerName
            One or more computer names or IP addresses to query. Defaults to the local machine.
            Accepts pipeline input by value and by property name.
 
        .PARAMETER Credential
            Optional PSCredential used to authenticate against remote machines. Ignored for
            local queries. Obtain via Get-Credential or SecretManagement.
 
        .EXAMPLE
            Get-SystemSummary
            Returns a full system summary for the local machine.
 
        .EXAMPLE
            Get-SystemSummary -ComputerName 'SRV01', 'SRV02' -Credential (Get-Credential)
            Returns system summaries for two remote servers using explicit credentials.
 
        .EXAMPLE
            'WEB01', 'WEB02' | Get-SystemSummary -Verbose
            Queries two machines via pipeline input with verbose logging.
 
        .OUTPUTS
            PSWinOps.SystemSummary
            System information summary including OS, CPU, RAM, and uptime.
 
        .NOTES
            Author: Franck SALLET
            Version: 1.0.0
            Last Modified: 2026-03-15
            Requires: PowerShell 5.1+, CIM/WMI access on target machines
            Permissions: Local admin or equivalent WMI read permissions on remote targets
 
        .LINK
            https://github.com/k9fr4n/PSWinOps
 
        .LINK
            https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/win32-operatingsystem
    #>

    [CmdletBinding()]
    [OutputType('PSWinOps.SystemSummary')]
    param(
        [Parameter(Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [ValidateNotNullOrEmpty()]
        [Alias('CN', 'Name', 'DNSHostName')]
        [string[]]$ComputerName = $env:COMPUTERNAME,

        [Parameter(Mandatory = $false)]
        [PSCredential]$Credential
    )

    begin {
        Write-Verbose "[$($MyInvocation.MyCommand)] Starting"
        $localNames = @($env:COMPUTERNAME, 'localhost', '.')
        $hasCredential = $PSBoundParameters.ContainsKey('Credential')
    }

    process {
        foreach ($machine in $ComputerName) {
            $cimSession = $null
            try {
                $isLocal = $localNames -contains $machine

                # Build common CIM params for this machine (splat for all 6 classes)
                $cimParams = @{ ErrorAction = 'Stop' }
                if (-not $isLocal) {
                    if ($hasCredential) {
                        $cimSession = New-CimSession -ComputerName $machine -Credential $Credential -ErrorAction Stop
                        $cimParams['CimSession'] = $cimSession
                    } else {
                        $cimParams['ComputerName'] = $machine
                    }
                }

                # Query all 6 CIM classes
                $system = Get-CimInstance -ClassName 'Win32_ComputerSystem' @cimParams
                $os = Get-CimInstance -ClassName 'Win32_OperatingSystem' @cimParams
                $bios = Get-CimInstance -ClassName 'Win32_BIOS' @cimParams
                $processor = Get-CimInstance -ClassName 'Win32_Processor' @cimParams | Select-Object -First 1
                $disks = Get-CimInstance -ClassName 'Win32_LogicalDisk' @cimParams | Where-Object -FilterScript { $_.DriveType -eq 3 }
                $networkAdapters = Get-CimInstance -ClassName 'Win32_NetworkAdapterConfiguration' @cimParams | Where-Object -FilterScript { $null -ne $_.DefaultIPGateway }

                # Calculate uptime
                $uptime = (Get-Date) - $os.LastBootUpTime

                # Build disk summary strings
                $diskSummary = ($disks | ForEach-Object -Process {
                        '[{0}] {1} ({2}) {3:N2}/{4:N2} GB ({5:N1}% Free)' -f
                        $_.FileSystem, $_.DeviceID, $_.VolumeName,
                        ($_.FreeSpace / 1GB), ($_.Size / 1GB),
                        (($_.FreeSpace / $_.Size) * 100)
                    }) -join ' | '

                # Extract IPv4 addresses only
                $ipv4Addresses = ($networkAdapters.IPAddress | Where-Object -FilterScript { $_ -match '^\d+\.\d+\.\d+\.\d+$' }) -join ', '
                $gatewayList = ($networkAdapters.DefaultIPGateway) -join ', '
                $dnsList = ($networkAdapters.DNSServerSearchOrder) -join ', '

                # Determine PS version string
                $psVersionString = if ($isLocal) {
                    $PSVersionTable.PSVersion.ToString()
                } else {
                    'N/A (remote)'
                }

                [PSCustomObject]@{
                    PSTypeName             = 'PSWinOps.SystemSummary'
                    ComputerName           = $machine
                    Domain                 = $system.Domain
                    OSName                 = $os.Caption
                    OSVersion              = $os.Version
                    OSArchitecture         = $os.OSArchitecture
                    InstallDate            = $os.InstallDate
                    LastBootTime           = $os.LastBootUpTime
                    UptimeDays             = [decimal][math]::Round($uptime.TotalDays, 2)
                    UptimeDisplay          = '{0} days, {1} hours, {2} minutes' -f $uptime.Days, $uptime.Hours, $uptime.Minutes
                    Manufacturer           = $system.Manufacturer
                    Model                  = $system.Model
                    SerialNumber           = $bios.SerialNumber
                    BIOSVersion            = $bios.SMBIOSBIOSVersion
                    Processor              = $processor.Name.Trim()
                    TotalCores             = [int]$processor.NumberOfCores
                    TotalLogicalProcessors = [int]$processor.NumberOfLogicalProcessors
                    TotalRAMGB             = [decimal][math]::Round($system.TotalPhysicalMemory / 1GB, 2)
                    FreeRAMGB              = [decimal][math]::Round($os.FreePhysicalMemory / 1MB, 2)
                    RAMUsagePercent        = [decimal][math]::Round((1 - ($os.FreePhysicalMemory / $os.TotalVisibleMemorySize)) * 100, 1)
                    Disks                  = $diskSummary
                    IPAddresses            = $ipv4Addresses
                    DefaultGateway         = $gatewayList
                    DNSServers             = $dnsList
                    PSVersion              = $psVersionString
                    Timestamp              = Get-Date -Format 'o'
                }
            } catch {
                Write-Error "[$($MyInvocation.MyCommand)] Failed on '${machine}': $_"
            } finally {
                if ($null -ne $cimSession) {
                    Remove-CimSession -CimSession $cimSession -ErrorAction SilentlyContinue
                }
            }
        }
    }

    end {
        Write-Verbose "[$($MyInvocation.MyCommand)] Completed"
    }
}