Event Logs, System Information, and Operational Evidence
Collect evidence-first incident data with platform-aware event sources, selective system information, UTC correlation, structured reports, and integrity hashes.
Learning objectives
- Explain evidence-first troubleshooting and why remediation can destroy clues.
- Use Get-WinEvent efficiently on Windows with bounded source-side filters.
- Recognize Get-WinEvent and Get-ComputerInfo as Windows-only.
- Normalize timestamps and add correlation identifiers.
- Use native Linux/macOS evidence sources through isolated adapters.
- Build a read-only incident snapshot with file-integrity hashes.
1. Incident response starts by preserving evidence
When a host looks unhealthy, immediate changes can erase the clues that explain what happened. An evidence-first workflow records time, host identity, process state, relevant events, and configuration facts before remediation—unless an urgent safety/security runbook requires immediate containment.
The goal is not to collect everything. It is to collect enough structured, timestamped evidence to test a hypothesis and correlate events.
2. Get-WinEvent is Windows-only
Get-WinEvent reads Windows Event Log and Event Tracing for Windows (ETW) data. Microsoft documents it as Windows-only. On Linux, journalctl is common on systemd hosts; macOS provides the unified logging system through the native log command. Those are distinct native contracts.
[pscustomobject]@{
IsWindows = $IsWindows
GetWinEvent = [bool](Get-Command Get-WinEvent -ErrorAction SilentlyContinue)
Journalctl = [bool](Get-Command journalctl -ErrorAction SilentlyContinue)
MacUnifiedLog = $IsMacOS -and [bool](Get-Command log -CommandType Application -ErrorAction SilentlyContinue)
}3. Discover logs/providers before guessing names
if ($IsWindows) {
Get-WinEvent -ListLog 'System','Application' |
Select-Object LogName,RecordCount,IsEnabled,FileSize,MaximumSizeInBytes
Get-WinEvent -ListProvider 'Microsoft-Windows-*' |
Select-Object -First 10 Name
}4. Filter at the event source
Get-WinEvent -FilterHashtable can filter by log, provider, event ID, level, and time window before returning records. This is usually more efficient than reading a large log and then using Where-Object.
if ($IsWindows) {
$filter = @{
LogName = 'System'
StartTime = (Get-Date).AddHours(-2)
}
Get-WinEvent -FilterHashtable $filter -MaxEvents 20 -ErrorAction SilentlyContinue |
Select-Object TimeCreated,Id,LevelDisplayName,ProviderName,Message
}5. An event record is structured evidence, not only a message string
Useful event properties include TimeCreated, Id, LevelDisplayName, ProviderName, RecordId, MachineName, and Message. The message is important for humans, but IDs/providers/timestamps are often more stable for machine correlation.
6. Normalize time before correlation
Different systems and tools may display local time, UTC, or an offset. Keep the original timestamp when preserving evidence, and add a normalized UTC field when correlating records across hosts.
$now = Get-Date
[pscustomobject]@{
LocalTime = $now
UtcTime = $now.ToUniversalTime()
Offset = [DateTimeOffset]$now
}7. Get-ComputerInfo is useful—but Windows-only and very wide
Get-ComputerInfo returns a consolidated Windows system-information object. Query only properties relevant to the incident instead of dumping the entire object.
if ($IsWindows) {
Get-ComputerInfo -Property CsName,OsName,OsVersion,OsBuildNumber |
Select-Object CsName,OsName,OsVersion,OsBuildNumber
} else {
[pscustomobject]@{
Computer = [Environment]::MachineName
OS = [System.Runtime.InteropServices.RuntimeInformation]::OSDescription
Arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture
}
}8. Cross-platform event sources stay behind adapters
if ($IsLinux -and (Get-Command journalctl -ErrorAction SilentlyContinue)) {
$sample = journalctl --since '-30 minutes' --no-pager -n 20 2>$null
[pscustomobject]@{ Source='journalctl'; Lines=@($sample).Count; ExitCode=$LASTEXITCODE }
}
if ($IsMacOS -and (Get-Command log -CommandType Application -ErrorAction SilentlyContinue)) {
# Bounded read-only query. Native macOS syntax is intentionally isolated here.
$sample = & log show --last 10m --style compact 2>$null | Select-Object -First 20
[pscustomobject]@{ Source='macOS unified log'; Lines=@($sample).Count; ExitCode=$LASTEXITCODE }
}9. Correlation turns separate clues into an investigation
A correlation identifier is a value used to connect evidence from the same request, deployment, or troubleshooting run. If your application already emits request IDs, preserve them. For a local collection run, generate an ID and attach it to every evidence file/object so later analysis knows which snapshot belongs together.
$correlationId = [guid]::NewGuid().ToString('N')
$capturedAtUtc = [datetime]::UtcNow
[pscustomobject]@{ CorrelationId=$correlationId; CapturedAtUtc=$capturedAtUtc }10. Lab: create a read-only incident snapshot
This lab changes no host configuration. It writes only to a disposable temporary directory, records a portable system/process snapshot, adds Windows event evidence when available, and hashes every evidence file.
$root = Join-Path ([System.IO.Path]::GetTempPath()) ('ps-ch12-evidence-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $root | Out-Null
$correlationId = [guid]::NewGuid().ToString('N')
$capturedAt = [datetime]::UtcNow
$hostSummary = [pscustomobject]@{
CorrelationId = $correlationId
CapturedAtUtc = $capturedAt
Computer = [Environment]::MachineName
PowerShell = $PSVersionTable.PSVersion.ToString()
OS = [System.Runtime.InteropServices.RuntimeInformation]::OSDescription
Architecture = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()
}
$hostSummary | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $root 'host.json') -Encoding utf8
Get-Process |
Sort-Object WorkingSet64 -Descending |
Select-Object -First 25 Id,ProcessName,CPU,WorkingSet64 |
ConvertTo-Json -Depth 4 |
Set-Content -LiteralPath (Join-Path $root 'processes.json') -Encoding utf8
if ($IsWindows -and (Get-Command Get-WinEvent -ErrorAction SilentlyContinue)) {
$events = Get-WinEvent -FilterHashtable @{
LogName='System'; StartTime=(Get-Date).AddHours(-1)
} -MaxEvents 50 -ErrorAction SilentlyContinue |
Select-Object TimeCreated,Id,LevelDisplayName,ProviderName,RecordId,Message
$events | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath (Join-Path $root 'events-system.json') -Encoding utf8
}
$manifest = Get-ChildItem -LiteralPath $root -File | ForEach-Object {
$hash = Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256
[pscustomobject]@{ File=$_.Name; SHA256=$hash.Hash; Length=$_.Length }
}
$manifest | ConvertTo-Json | Set-Content -LiteralPath (Join-Path $root 'manifest.json') -Encoding utf8
Get-ChildItem -LiteralPath $root | Select-Object Name,Length11. Preserve evidence before cleanup
In a real incident, do not delete the snapshot until your retention policy says it is safe. The temporary directory is appropriate for a training lab, but production evidence belongs in a controlled location with access, integrity, retention, and privacy rules.
# Training cleanup only, after you have inspected the files:
# Remove-Item -LiteralPath $root -Recurse -Force12. Common mistakes
- Changing the system before collecting enough evidence to explain the initial state.
- Reading an entire event log and filtering locally when source-side filters are available.
- Dumping every property from wide system-information objects.
- Comparing timestamps without normalizing time zones.
- Assuming Windows event APIs exist on Linux/macOS.
- Storing incident evidence in uncontrolled locations that may contain sensitive data.
13. Knowledge check
Question 1. Why collect evidence before remediation?
Question 2. Is Get-WinEvent cross-platform?
Question 3. Why is -FilterHashtable usually preferable to filtering a huge event set locally?
Question 4. Why add UTC timestamps to evidence?
Question 5. What does hashing evidence files provide?
14. Summary and next bridge
Operational evidence should be narrow, structured, timestamped, platform-aware, and preserved before change. Windows provides Get-WinEvent and Get-ComputerInfo; Linux/macOS use different native evidence sources. The stable cross-platform layer is the object contract you produce. In the final lesson we apply that adapter pattern to schedulers and local administration boundaries.
15. Authoritative references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.