Ich wurde kürzlich gebeten, etwas sehr Ähnliches zu tun, aber Start- und Anmeldezeiten anzugeben und historische Referenzen zu berücksichtigen. Das folgende Powershell-Skript führt also Folgendes aus:
- greift auf einige Umgebungsvariablen zu
- Ruft den Zeit- / Datumsstempel für 4 verschiedene Ereignisprotokolleinträge ab. Die 2. und 4. davon sind keine exakten Messungen, aber nach ziemlich umfangreichen Recherchen, Fehlerbehebung und Tests sind sie sehr nah und nach dem, was ich gesehen habe, die besten Optionen.
- berechnet die Differenz zwischen diesen 4 Ereignissen
- füllt alle Zahlen in eine einfache SQL-Tabelle [Sie können sie natürlich anpassen, um die Zahlen in alles zu leiten, was Sie wollen]
Das Skript soll also über eine geplante Aufgabe oder nach einem bestimmten Zeitplan ausgeführt werden, wenn Sie möglicherweise über SCCM verfügen (nicht während der Anmeldung, um die Anmeldung überhaupt nicht zu ändern). Das Schöne ist, dass Sie den PC-Namen in einen anderen Namen ändern können, um ihn von Ihrem eigenen PC aus auszuführen und die Daten von einem Remotecomputer abzurufen (obwohl der Benutzername als Ihr eigener angezeigt wird), um Fehler zu beheben und die Nummern zu überprüfen.
Ich habe einen weiteren Schritt unternommen und SharePoint verwendet, um eine Liste externer Daten (mit BCS) zu erstellen, damit diese eine schöne Front-End-Benutzeroberfläche haben. Skript unten, ich habe in den meisten kommentierten Zeilen, die ich beim Schreiben verwendet habe, verlassen:
$USER = $env:username.ToUpper()
$COMPUTER = $env:computername.ToUpper()
$Current_Time = Get-Date
$PCname = ''
$addedtime = 0
#1. get event time of last OS load
$filterXML = @'
<QueryList>
<Query Id="0" Path="System">
<Select Path="System">*[System[Provider[@Name='Microsoft-Windows-Kernel-General'] and (Level=4 or Level=0) and (EventID=12)]]</Select>
</Query>
</QueryList>
'@
$OSLoadTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML).timecreated
#Write-Host $PCname
#Write-Host "1. Last System Boot @ " $OSLoadTime
#2. Get event time of Time-Service [pre-Ctrl+Alt-Del] after latest OS load
$filterXML = @'
<QueryList>
<Query Id="0" Path="System">
<Select Path="System">*[System[Provider[@Name='Microsoft-Windows-Time-Service'] and (Level=4 or Level=0) and (EventID=35)]]</Select>
</Query>
</QueryList>
'@
$CtrlAltDelTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML).timecreated
#Write-Host "2. Time-sync after Boot @ " $CtrlAltDelTime
#get minutes (rounded to 1 decimal) between OS load time and 1st load of GPOs
$BootDuration = "{0:N1}" -f ((($CtrlAltDelTime - $OSLoadTime).TotalSeconds + $addedtime)/60)
#3. get event time of 1st successful logon
$filterXML = @'
<QueryList>
<Query Id="0" Path="System">
<Select Path="System">*[System[Provider[@Name='Microsoft-Windows-Winlogon'] and (Level=4 or Level=0) and (EventID=7001)]]</Select>
</Query>
</QueryList>
'@
$LogonDateTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML -ErrorAction SilentlyContinue).timecreated
If ($LogonDateTime) {
#Write-Host "3. Successful Logon @ " $LogonDateTime
}
Else {
#Write-Host "Duration of Bootup = " $BootDuration "minutes" -foregroundcolor blue -BackgroundColor white
#Write-Host $PCname "has not logged back in." -foregroundcolor red -BackgroundColor white
Exit
}
#Write-Host "Duration of Bootup = " $BootDuration "minutes" -foregroundcolor blue -BackgroundColor white
#4. Get Win License validated after logon (about same time as explorer loads)
$filterXML = @'
<QueryList>
<Query Id="0" Path="Application">
<Select Path="Application">*[System[Provider[@Name='Microsoft-Windows-Winlogon'] and (Level=4 or Level=0) and (EventID=4101)]]</Select>
</Query>
</QueryList>
'@
$DesktopTime=(Get-WinEvent -ComputerName $PCname -MaxEvents 1 -FilterXml $filterXML).timecreated
$LogonDuration = "{0:N1}" -f ((($DesktopTime - $LogonDateTime).TotalSeconds + $addedtime)/60)
#Write-Host "4. WinLicVal after Logon @ " $DesktopTime
#Write-Host "Duration of Logon = " $LogonDuration "minutes" -foregroundcolor blue -BackgroundColor white
#START SQL Injection Section
[void][reflection.assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo")
$sqlServer = "SQLserver01"
$dbName = "BootUpTimes"
$tbl = "tblBootUpTimes"
#$srv = New-Object Microsoft.SqlServer.Management.Smo.Server $sqlServer
#$db = $srv.databases[$dbName]
#$conn = New-Object System.Data.SqlClient.SqlConnection("Data Source=$sqlServer;Initial Catalog=$dbName; Integrated Security=SSPI")
$conn = New-Object System.Data.SqlClient.SqlConnection("server=$sqlServer;database=$dbName;Password=plaintext;User Id=BootUpTimes")
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "INSERT INTO $tbl VALUES ('$Current_Time','$USER','$COMPUTER','$OSLoadTime','$CtrlAltDelTime','$BootDuration','$LogonDateTime','$DesktopTime','$LogonDuration')"
Try
{
$null = $cmd.ExecuteNonQuery()
}
Catch
{
}
$conn.Close()
In diesem letzten SQL-Abschnitt gibt es einige auskommentierte Zeilen, die eine andere Methode (sicherheitsbasiert) für die Eingabe in SQL anbieten, ohne dass ein Kennwort im Klartext erforderlich ist.