3LToolKit.psm1
Function Get-3LLogonEventAccountName { #requires -RunAsAdministrator #requires -Modules PSScriptTools <# .SYNOPSIS Get all logon events (Success and Failure) and extract some logon details .SYNOPSIS Get all authenticate events that are used to authenticate. Logon attempts are retrieved from events in the security eventlog with eventid 4624 and 4625. Each computer is queried as a separate job. The output of all jobs is merged in the end. .EXAMPLE Get-3LLogonEventAccountName -InformationAction Continue Get all logon events on the local machine and displays status messages. .EXAMPLE Get-3LLogonEventAccountName -afterDate (Get-Date).addDays(-14) Get all logon events on the local machine in the last 14 days .EXAMPLE Get-3LLogonEventAccountName -afterDate (Get-Date).addHours(-1) Get all logon events on the local machine in the hour .EXAMPLE Get-3LLogonEventAccountName -computerName SVR1, SVR2 -Progress Get all logon events on the specified computers. During analyzing the Security log Events, a progressbar is displayed. .EXAMPLE Get-3LLogonEventAccountName -InformationVariable info $info | Where Tags -eq 'Success' The first command collect all logon events on the local computer. Messages from the Information stream are collected in the info variable The second command shows all Information messages tagged as 'Success' .NOTES Author: Frits van Drie (3-Link.nl) Date : 2021-10-20 #> [CmdletBinding()] param( [string[]]$computerName, [datetime]$afterDate = (Get-Date).AddDays(-1), [switch]$progress ) Begin { Function Write--JobProgress { <# .NOTES Date: 2021-10-19 #> param($job) # Make sure the first child job exists if($job.ChildJobs[0].Progress -ne $null) { # Extract the latest progress of the job and write the progress $jobProgressHistory = $job.ChildJobs[0].Progress $latestProgress = $jobProgressHistory[$jobProgressHistory.Count - 1] $latestPercentComplete = $latestProgress | Select -expand PercentComplete $latestActivity = $latestProgress | Select -expand Activity $latestStatus = $latestProgress | Select -expand StatusDescription # a unique ID per ProgressBar if ( $latestProgress.PercentComplete -ge 0 ) { Write-Progress -Id $job.Id -Activity $latestActivity -Status $latestStatus -PercentComplete $latestPercentComplete } } } # module PSScriptTools required try { $module = 'PSScriptTools' Import-Module $module -ErrorAction Stop Write-Information "SUCCESS: Imported Module: $module" $function_ConvertEventLogRecord = "Function Convert-EventLogRecord {" + (Get-Item function:Convert-EventLogRecord).ScriptBlock + " }" } catch { Write-Information "FAILURE: Could not import required Module: $module" Write-Error $_ Break } if ( ($PSBoundParameters.Keys -notcontains 'computerName') -or ($computerName -eq 'localhost') ) { $computerName = $env:COMPUTERNAME } $msec = ((Get-Date)- $afterDate).TotalMilliseconds $xml = @" <QueryList> <Query Id="0" Path="Security"> <Select Path="Security">*[System[(Level=2 or Level=4 or Level=0) and (EventID=4624 or EventID=4625) and (TimeCreated[timediff(@SystemTime) `<= $msec])]]</Select> </Query> </QueryList> "@ # xmlFilter [array]$startedJobs = @() } # end Begin{} Process { foreach ( $computer in $computerName ) { $jobName = "LogonEvents-$computer" Write-Information "STATUS : Running Job $jobName" -Tags 'Status' $job = Start-Job -Name $jobName -ArgumentList $xml, $computer, $progress, $function_ConvertEventLogRecord { param($xml, $computer, $progress, $function_ConvertEventLogRecord) Write-Information "STATUS : Setting up session to computer $computer" -Tags 'Status' try { New-PSSession -ComputerName $computer -ErrorAction Stop Write-Information "SUCCESS: Connected to computer $computer" -Tags 'Success' } # try New-PSSession catch { Write-Information "FAILURE: Session to computer $computer failed" -Tags 'Failure' continue } if ( $session = Get-PSSession -ComputerName $computer -ErrorAction SilentlyContinue) { Write-Information "STATUS : Starting Invoke-Command to computer $computer" -Tags 'Status' $outputInvoke = Invoke-Command -Session $session -ArgumentList $xml, $progress, $activity, $function_ConvertEventLogRecord { param($xml, $progress, $activity, $function_ConvertEventLogRecord) iex $function_ConvertEventLogRecord # load function: Convert-EventLogRecord $computer = $env:COMPUTERNAME $splatParam = @{} $splatParam.add('FilterXml', $xml) $splatParam.add('ComputerName', $computer) try { Write-Information "STATUS : Reading events from computer $computer" -Tags 'Status' $events = Get-WinEvent @splatParam -ErrorAction Stop $total = $events.Count } catch { Write-Information "INFO : $($_.tostring())" Write-Error $_ return } $activity = "Analyzing $total Events from computer $computer" Write-Information "STATUS : $activity" -Tags 'Status' $done = 0 $returnInvoke = @() foreach ($event in $events) { $obj = Convert-EventLogRecord $event $returnInvoke += $obj if ( $progress ) { $done++ Write-Progress -Activity $activity -Status "$done\$total" -PercentComplete ($done/$total*100) } } # end foreach event if ( $progress ) { Write-Progress -Activity $activity -Status "$done\$total" -PercentComplete ($done/$total*100) #Write-Progress -Activity $activity -Completed } return $returnInvoke } # end Invoke-Command Get-PSSession -ComputerName $computer | Remove-PSSession return $outputInvoke } # end if Get-PSSession } # end Start-Job [array]$startedJobs += $job } # end foreach computer Write-Information "" } # end Process{} End { # while ( $jobs = (Get-Job -Name '*-LogonEvents') ) { Write-Information "STATUS : Waiting for jobs to finish`n" while ( $startedJobs ) { # foreach ( $job in $jobs ) { foreach ( $job in $startedJobs ) { $jobState = $job.State # to prevent status changes during processing if ($jobState -eq 'Completed' ) { Write--JobProgress -job $job Write-Information "STATUS : Importing results from job: $(($job).Name)" -Tags 'Status' $receivedJob = Receive-Job $job $job | Remove-Job $startedJobs = $startedJobs | Where {$_ -ne $job} if ($receivedJob.length -gt 1) { # remove the first item which is the job [array]$outputJob += $receivedJob[1..($receivedJob.length-1)] } Write-Information "SUCCESS: Job ready: $(($job).Name)`n" -Tags 'Success' } else { Write--JobProgress -job $job #sleep 1 } } # end foreach job } # end While Write-Output $outputJob } # end End{} } Function Write-3LNetworkConfigurationToFile { <# .SYNOPSIS Find text in a file .NOTES Author : Frits van Drie (3-Link.nl) Versions : 2021.09.24 .EXAMPLE SaveNetworkConfigurationToFile -openFile .EXAMPLE SaveNetworkConfigurationToFile -path 'C:\data\network.txt' #> [CmdletBinding()] param ( [string]$path = "$($env:USERPROFILE)\Documents\$($env:COMPUTERNAME)-$($MyInvocation.MyCommand)-$(Get-Date -Format yyyyMMdd_HHmmss).txt", [string]$header, [switch]$openFile, [switch]$noFile ) [array]$result = @() $result += "=================================================================================================" $result += "Computer : $($env:COMPUTERNAME)" $result += "Date : $(Get-Date -Format 'yy-MM-dd (HH:mm:ss)')" if ($MyInvocation.BoundParameters.ContainsKey('header')) { $result += "Description: $header" } $result += "=================================================================================================`n" # Gather info try { $result += "`n=================================================================================================" $result += "Get-NetAdapter" $result += "=================================================================================================`n" $result += Get-NetAdapter -ErrorAction Stop | ft -AutoSize $result += "`n=================================================================================================" $result += "Get-NetIPAddress" $result += "=================================================================================================`n" $result += Get-NetIPAddress -ErrorAction Stop | ft -AutoSize $result += "`n=================================================================================================" $result += "Get-NetRoute" $result += "=================================================================================================`n" $result += Get-NetRoute -ErrorAction Stop | ft -AutoSize $result += "`n=================================================================================================" $result += "Get-DnsClientCache" $result += "=================================================================================================`n" $result += Get-DnsClientCache -ErrorAction Stop | ft -AutoSize $result += "`n=================================================================================================" $result += "Show-DnsServerCache" $result += "=================================================================================================`n" (Get-DnsClientServerAddress -Family IPv4 | Where serveraddresses ).serveraddresses | foreach { $result += "`n====================" $result += "DNS: $_" $result += "====================`n" try { $result += Show-DnsServerCache -ComputerName $_ -ea Stop } catch { $result += "Cache of $_ could not be read" } } $result += "`n=================================================================================================" $result += "Get-NetTCPConnection" $result += "=================================================================================================`n" $result += Get-NetTCPConnection -ErrorAction Stop | ft -AutoSize $result += "`n=================================================================================================" $result += "Get-Process" $result += "=================================================================================================`n" $result += Get-Process -ErrorAction Stop | ft -AutoSize $result += "`n=================================================================================================" $result += "Get-DnsClientServerAddress" $result += "=================================================================================================`n" $result += Get-DnsClientServerAddress -ErrorAction Stop | ft -AutoSize $result += "`n=================================================================================================" $result += "Certificates" $result += "=================================================================================================`n" $result += GCI 'Cert:\LocalMachine\My' -ErrorAction Stop | ft -AutoSize $result += GCI 'Cert:\CurrentUser\My' -ErrorAction Stop | ft -AutoSize } catch { Write-Error $error[0] break } if ( $noFile ) { $openFile = $true $path = Join-Path $env:TEMP (Split-Path $path -Leaf) } try { $result | Out-File $path -Append -ErrorAction Stop -Width 200 } catch { Write-Error $error[0] break } if ($openFile) { notepad.exe $path } if ($noFile) { Write-Verbose "Network configuration saved to $path" Start-Sleep 2 Remove-Item $path -Force -ea SilentlyContinue } else { Write-Host "Network configuration saved to $path" -f Yellow } } Function Out-3LNotepad { param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true)] [String] [AllowEmptyString()] $Text ) begin { $sb = New-Object System.Text.StringBuilder } process { $null = $sb.AppendLine($Text) } end { $text = $sb.ToString() $process = Start-Process notepad -PassThru $null = $process.WaitForInputIdle() $sig = ' [DllImport("user32.dll", EntryPoint = "FindWindowEx")]public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); [DllImport("User32.dll")]public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam); ' $type = Add-Type -MemberDefinition $sig -Name APISendMessage -PassThru $hwnd = $process.MainWindowHandle [IntPtr]$child = $type::FindWindowEx($hwnd, [IntPtr]::Zero, "Edit", $null) $null = $type::SendMessage($child, 0x000C, 0, $text) } } Function Find-3LStringInFile { <# .SYNOPSIS Find text in a file .NOTES Author : Frits van Drie (3-Link.nl) Versions : 2021.09.23 .EXAMPLE FindStringInFile -pattern 'Project' -path "document.txt" searches document.txt in current folder for 'project' or 'Project' .EXAMPLE FindStringInFile -pattern 'Project' -path "document.txt" -caseSensitive searches document.txt in current folder for 'Project' .EXAMPLE gci "C:\Users\user\documents" -File | foreach { FindStringInFile -pattern 'project' -path $_.FullName } searches all users documents 'project' or 'Project' #> [CmdletBinding()] param ( [parameter(mandatory = $true)] [string]$pattern, [parameter(mandatory = $true)] [string]$path, [parameter(mandatory = $false)] [switch]$caseSensitive ) begin { Write-Verbose "Start Function: $($MyInvocation.MyCommand)" } process { foreach ($file in $path) { try { $objfile = Get-item $path -ea Stop $result = $objFile | Select-String -Pattern $pattern -ea Stop -CaseSensitive:$caseSensitive Write-Output $result } catch { Write-Error "File not found: $path" } } } end { Write-Verbose "End Function: $($MyInvocation.MyCommand)" } } |