This script will generate a logon report of a specific user on a specific machine. This script is designed to query the event viewer logs on either a local or remote machine. It does not require WinRM for this to occur.
The script begins by querying the registry or remote registry to find the associated SID with the specified user profile. It then proceeds to retrieve all Event 4624 IDs from the event viewer logs. It filters those logs into four categories: Keyboard Logins, Unlock, Remote, and Cached Credentials. This website helped me considerably in knowing how to generate and classify the reporting.
The script will write the output to a CSV file, categorizing the logon times by the four categories listed above. If the -Rawdata parameter is used, the script will also write the detailed message data with a timestamp on each data entry to a TXT file.
Command line execution to get a formatted CSV file:
The script begins by querying the registry or remote registry to find the associated SID with the specified user profile. It then proceeds to retrieve all Event 4624 IDs from the event viewer logs. It filters those logs into four categories: Keyboard Logins, Unlock, Remote, and Cached Credentials. This website helped me considerably in knowing how to generate and classify the reporting.
The script will write the output to a CSV file, categorizing the logon times by the four categories listed above. If the -Rawdata parameter is used, the script will also write the detailed message data with a timestamp on each data entry to a TXT file.
Command line execution to get a formatted CSV file:
- powershell.exe -file LogonTimes.ps1 -ComputerName "Test01" -Username "User01"
Command line execution to get a formatted CSV and raw data TXT file:
- powershell.exe -file LogonTimes.ps1 -ComputerName "Test01" -Username "User01" -Rawdata
- powershell.exe -file LogonTimes.ps1 -Username "User01"
You can download the script from GitHub.
PowerShell Studio made writing this script a breeze. If you look at the script and see all of the documentation in it, that is because PowerShell Studio makes that very easy and quick. It is well worth the money to purchase this tool.
This is a view of a success execution of the script:
LogonTimes.ps1
<#
.SYNOPSIS
User Logon Report
.DESCRIPTION
This script will query the event viewer logs of a specified system for a list of logon times for a specific user. There are four fields in the report: Keyboard logons, Screen Unlock, Remote Session logons, and Cached Logon. It has the option to either generate a report in a CSV file with all of the above field data, or it can generate a TXT file containing the raw message data with each data field split off by two dash rows.
NOTE: This does not require WinRM to be enabled to run on external systems. Also, this can take quite a while to execute if the logs are really big.
.PARAMETER ComputerName
Name of system to retrieve the logs from. If this is left blank, the script will use "." representing the computer this script is executing on.
.PARAMETER Rawdata
Generate a report using the raw data from the event viewer logs of the specified user
.PARAMETER Username
Username to generate this report of.
.EXAMPLE
Generate a CSV file report containing the times and sorted by each logon type
powershell.exe -file LogonTimes.ps1 -Username MickPletcher -ComputerName PC01
Generate a TXT file that contains all of the raw message data fields for the specified system
powershell.exe -file LogonTimes.ps1 -Username MickPletcher -ComputerName PC01 -Rawdata
.NOTES
===========================================================================
Created with: SAPIEN Technologies, Inc., PowerShell Studio 2017 v5.4.136
Created on: 3/15/2017 12:00 PM
Created by: Mick Pletcher
Filename: LogonTimes.ps1
===========================================================================
#>
[CmdletBinding()]
param
(
[String]$ComputerName,
[switch]$Rawdata,
[ValidateNotNullOrEmpty()][string]$Username
)
function Get-FilteredData {
<#
.SYNOPSIS
Filter By LogonType Type
.DESCRIPTION
This will filter the data for the specified LogonType type
.PARAMETER LogonType
Specified LogonType type
.PARAMETER Message
Message to display on the screen
.PARAMETER Logons
Array containing all logons
.NOTES
Additional information about the function.
#>
[CmdletBinding()]
param
(
[ValidateNotNullOrEmpty()]$LogonType,
[ValidateNotNullOrEmpty()][string]$Message,
[ValidateNotNullOrEmpty()]$Logons
)
$Errors = $false
Write-Host $Message"....." -NoNewline
Try {
$Data = $Logons | Where-Object { $_.Message -like "*Logon Type*"+[char]9+[char]9+$LogonType+"*" }
} catch {
$Errors = $true
}
If ($Errors -eq $false) {
Write-Host "Success" -ForegroundColor Yellow
} else {
Write-Host "Failed" -ForegroundColor Red
}
Return $Data
}
function Get-SID {
<#
.SYNOPSIS
Retrieve SID from HKEY_LOCAL_MACHINE
.DESCRIPTION
This script will retrieve the SID by querying the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList by matching the ProfileImagePath value with the Username parameter.
.EXAMPLE
PS C:\> Get-SID
.NOTES
Additional information about the function.
#>
[CmdletBinding()][OutputType([string])]
param ()
Write-Host "Retrieving SID for $Username....." -NoNewline
If ($ComputerName -eq ".") {
#Get associated SID of User Profile
$SID = (get-childitem -path REGISTRY::"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList" | Where-Object { $_.Name -like "*S-1-5-21*" } | ForEach-Object { Get-ItemProperty REGISTRY::$_ } | Where-Object { $_.ProfileImagePath -like "*$Username*" }).PSChildName
} else {
$HKEY_LOCAL_MACHINE = 2147483650
$Key = "SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
$RegClass = Get-WMIObject -Namespace "Root\Default" -List -ComputerName $ComputerName | Where-object { $_.Name -eq "StdRegProv" }
$Value = "ProfileImagePath"
$SID = ($RegClass.EnumKey($HKEY_LOCAL_MACHINE, $Key)).sNames | Where-Object { $_ -like "*S-1-5-21*" } | ForEach-Object {
If (($RegClass.GetStringValue($HKEY_LOCAL_MACHINE, $Key + "\" + $_, $Value)).sValue -like "*" + $Username + "*") {
$_
}
}
}
If (($SID -ne "") -and ($SID -ne $null)) {
Write-Host "Success" -ForegroundColor Yellow
} else {
Write-Host "Failed" -ForegroundColor Red
}
Return $SID
}
function Get-RelativePath {
<#
.SYNOPSIS
Get the relative path
.DESCRIPTION
Returns the location of the currently running PowerShell script
.NOTES
Additional information about the function.
#>
[CmdletBinding()][OutputType([string])]
param ()
$Path = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent) + "\"
Return $Path
}
function New-Report {
<#
.SYNOPSIS
Generate CSV Report File
.DESCRIPTION
This function will generate a CSV report.
.PARAMETER Keyboard
A description of the Keyboard parameter.
.PARAMETER Unlock
A description of the Unlock parameter.
.PARAMETER Remote
A description of the Remote parameter.
.PARAMETER Cached
A description of the Cached parameter.
.EXAMPLE
PS C:\> New-Report
.NOTES
Additional information about the function.
#>
[CmdletBinding()]
param
(
$Keyboard,
$Unlock,
$Remote,
$Cached
)
$RelativePath = Get-RelativePath
#Name of report file
$FileName = $RelativePath + "$Username.csv"
#Delete report file if it exists
If ((Test-Path $FileName) -eq $true) {
Write-Host "Deleting $Username.csv....." -NoNewline
Remove-Item -Path $FileName -Force
If ((Test-Path $FileName) -eq $false) {
Write-Host "Success" -ForegroundColor Yellow
} else {
Write-Host "Failed" -ForegroundColor Red
}
}
Write-Host "Generating $Username.csv report file....." -NoNewline
#Create new file
"Logon Type,Date/Time" | Out-File -FilePath $FileName -Encoding UTF8 -Force
$Errors = $false
#Report all keyboard logons
foreach ($Logon in $Keyboard) {
$Item = "Keyboard," + [string]$Logon.TimeCreated
try {
$Item | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
} catch {
$Errors = $true
}
}
#Report all screen unlocks
foreach ($Logon in $Unlock) {
$Item = "Unlock," + [string]$Logon.TimeCreated
Try {
$Item | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
} catch {
$Errors = $true
}
}
#Report all remote logons
foreach ($Logon in $Remote) {
$Item = "Remote," + [string]$Logon.TimeCreated
Try {
$Item | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
} catch {
$Errors = $true
}
}
#Report all cached logons
foreach ($Logon in $Cached) {
$Item = "Cached," + [string]$Logon.TimeCreated
Try {
$Item | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
} catch {
$Errors = $true
}
}
If ($Errors -eq $false) {
Write-Host "Success" -ForegroundColor Yellow
} else {
Write-Host "Failed" -ForegroundColor Red
}
}
function Get-LogonLogs {
<#
.SYNOPSIS
Retrieve all Logon Logs from Event Viewer
.DESCRIPTION
This function will query the event viewer for all Event ID 4624, filtered with the user's SID.
.PARAMETER SID
User's SID
.EXAMPLE
PS C:\> Get-LogonLogs
.NOTES
Additional information about the function.
#>
[CmdletBinding()]
param
(
[ValidateNotNullOrEmpty()]$SID
)
If ($ComputerName -ne ".") {
Write-Host "Retrieving all logon logs for $Username on $ComputerName....." -NoNewline
} else {
Write-Host "Retrieving all logon logs for $Username on $env:COMPUTERNAME....." -NoNewline
}
$Errors = $false
Try {
If ($ComputerName -ne ".") {
$AllLogons = Get-WinEvent -FilterHashtable @{ logname = 'security'; ID = 4624 } -ComputerName $ComputerName | where-object { ($_.properties.value -like "*$SID*") }
} else {
$AllLogons = Get-WinEvent -FilterHashtable @{ logname = 'security'; ID = 4624 } | where-object { ($_.properties.value -like "*$SID*") }
}
} catch {
$Errors = $true
}
If ($Errors -eq $false) {
Write-Host "Success" -ForegroundColor Yellow
} else {
Write-Host "Failed" -ForegroundColor Red
}
Return $AllLogons
}
#******************************************************************************
#******************************************************************************
Clear-Host
If (($ComputerName -eq "") -or ($ComputerName -eq $null)) {
$ComputerName = "."
}
$SID = Get-SID
#Retrieve all logon logs
$AllLogons = Get-LogonLogs -SID $SID
#Logon at keyboard and screen of system
$KeyboardLogons = Get-FilteredData -Logons $AllLogons -LogonType "2" -Message "Filtering keyboard logons"
#Unlock workstation with password protected screen saver
$Unlock = Get-FilteredData -Logons $AllLogons -LogonType "7" -Message "Filtering system unlocks"
#Terminal Services, Remote Desktop or Remote Assistance
$Remote = Get-FilteredData -Logons $AllLogons -LogonType "10" -Message "Filtering remote accesses"
#logon with cached domain credentials such as when logging on to a laptop when away from the network
$CachedCredentials = Get-FilteredData -Logons $AllLogons -LogonType "11" -Message "Filtering cached logins"
#Generate a rawdata report
If ($Rawdata.IsPresent) {
$RelativePath = Get-RelativePath
#Name of report file
$FileName = $RelativePath + "$Username.txt"
#Delete report file if it exists
If ((Test-Path $FileName) -eq $true) {
Write-Host "Deleting $Username.txt....." -NoNewline
Remove-Item -Path $FileName -Force
If ((Test-Path $FileName) -eq $false) {
Write-Host "Success" -ForegroundColor Yellow
} else {
Write-Host "Failed" -ForegroundColor Red
}
}
Write-Host "Generating raw data file....." -NoNewline
foreach ($Logon in $AllLogons) {
[string]$Logon.TimeCreated | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
$Logon.Message | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
" " | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
"----------------------------------------------------------------------------------------------------------------------------------------------------------------" | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
"----------------------------------------------------------------------------------------------------------------------------------------------------------------" | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
" " | Out-File -FilePath $FileName -Encoding UTF8 -Append -Force
}
If ((Test-Path $FileName) -eq $true) {
Write-Host "Success" -ForegroundColor Yellow
} else {
Write-Host "Failed" -ForegroundColor Red
}
} else {
New-Report -Keyboard $KeyboardLogons -Unlock $Unlock -Remote $Remote -Cached $CachedCredentials
}
0 comments:
Post a Comment