<# .Synopsis Get downtime from computer(s) .DESCRIPTION This gets the startup events (EventID 12 ) from the System log, and for each the prior event in the log to calculate the time a computer was powered off. .PARAMETER Computername Name of computer to query. Default is local machine .PARAMETER StartDate Optional date to start query .EXAMPLE Get-Downtime get the downtime for the local computer going back as far as the logs permit .EXAMPLE "Zardoz,$env:COMPUTERNAME".Split(",")| % {Get-Downtime $_ -DateString "2/1/2017"} Get the downtime for Zardoz and the local computer beginning 2/1/2017 .Notes Alan dot Kaplan at VA dot Gov 2-24-2017 #> Function Get-Downtime { Param ( [string]$ComputerName = $env:COMPUTERNAME, #DateString is when to start search [string]$StartDate ) Begin {$error.Clear()} Process { #Returns datetime or string error message $OldestEvent = Get-OldestEvent $Computername if ($OldestEvent -is [string]){ [PSCustomObject]@{ ShutdownTime = '' StartUpTime = '' ElapsedDownTime = '' ComputerName = $computername ErrorMsg = $OldestEvent } }ELSE{ if ($StartDate){ $RetvalDate = [datetime]$StartDate }ELSE{ $RetvalDate = [datetime]$OldestEvent } #Get the UTC date for FilterXpath $UTCDate = $RetvalDate.ToUniversalTime().ToString('s') $Filter = "*[System[TimeCreated[@SystemTime>='$UTCDate']][Provider[@Name='Microsoft-Windows-Kernel-General']][EventID=12]]" Write-Progress "Getting events from $computername System log beginning $RetvalDate ... " Try{ $StartEvents = Get-WinEvent -logname system -FilterXPath $filter -ComputerName $computername -ErrorAction Stop }Catch{ $errmsg = $Error[0].Exception.Message } if ($StartEvents.count -eq 0){ $errMsg = "No shutdowns found beginning $RetvalDate" } if ($errMsg){ [PSCustomObject]@{ ShutdownTime = '' StartUpTime = '' ElapsedDownTime = '' ComputerName = $computername ErrorMsg = $errmsg } }ELSE{ $StartEvents | foreach { Try{ #The event before the restart is easy to get $PriorID = $_.RecordId -1 $PreviousSysEventFilter ="*[System[(EventRecordID=$priorID)]]" $PreviousSysEvent =Get-WinEvent -LogName System -FilterXPath $PreviousSysEventFilter -ComputerName $computername -ErrorAction Stop $ETS = $_.TimeCreated - $PreviousSysEvent.TimeCreated [PSCustomObject]@{ ShutdownTime = $PreviousSysEvent.TimeCreated StartUpTime = $_.TimeCreated ElapsedDownTime = "{0:dd\.hh\:mm\:ss}" -f $ETS ComputerName = $computername ErrorMsg = '' } }Catch{ $errmsg = $Error[0].Exception.Message [PSCustomObject]@{ ShutdownTime = '' StartUpTime = $_.TimeCreated ElapsedDownTime = '' ComputerName = $computername ErrorMsg = $errmsg } #end PSCustomObject }#End Try/Catch }#End Foreach } #End If/Else } #End Process } #End top If/Else End{ Write-progress "Done" -Completed } } Function Get-OldestEvent($ComputerName){ Try{ [datetime]$Retval = (Get-WinEvent -ComputerName $computername -LogName System -Oldest -MaxEvents 1 -ErrorAction Stop).TimeCreated }Catch{ [string]$retval = $Error[0].Exception.Message } $retval } ### Dot Source Reminder Begins ### $ScriptFullPath = $MyInvocation.MyCommand.Definition.ToString() $command = $MyInvocation.MyCommand.Name.Replace(".ps1","") if (($host.Name).Contains("ISE")){ Write-host "`n`nYou have loaded the advanced function `"$command`"" -ForegroundColor Green Write-Host "Use `"Get-Help`" for information about this function, Ex:`nPS C:\> Get-Help $command -detailed`n`n" }ELSE{ if ($MyInvocation.InvocationName -ne '.') { Write-host "`n`nThis is an advanced function which must be dot sourced in order to work correctly`n" -ForegroundColor Green write-host "Load example:`nPS C:\> . $ScriptFullPath`n" Write-Host "Use `"Get-Help`" for information about this function, Ex:`nPS C:\> Get-Help $command -detailed`n`n" #Pause if launched from shell with "Run with PowerShell" if (([Environment]::GetCommandLineArgs()) -match '&'){pause} } } ### Dot Source Reminder Ends