Launch-GetEventsGUI.ps1
<#PSScriptInfo
.VERSION 1.5.1 .GUID 08eee800-b250-4366-82b9-8bc6862466fe .AUTHOR SammyKrosoft .COMPANYNAME SammykroSoft #> <# .DESCRIPTION This script is a graphical user interface for the Get-EventsFromEventLogs.ps1 script that you can find on my GitHub page https://github.com/SammyKrosoft. See the description in the Get-EventsFromEventLogs function below. .NOTES With the help of : Jim Moyle @jimmoyle How-To GUI From Jim Moyle : https://github.com/JimMoyle/GUIDemo #> $global:GUIversion = "2" <# Release notes v1.2 -> changed way to call ShowDialog() to avoid crashes v1.1.1 -> fixed lack of IsPSV3 function ... #> #======================================================== #region Functions definitions (NOT the WPF form events) #======================================================== Function IsPSV3 { <# .DESCRIPTION Just printing Powershell version and returning "true" if powershell version is Powershell v3 or more recent, and "false" if it's version 2. .OUTPUTS Returns $true or $false .EXAMPLE IsPSVersionV3 #> $PowerShellMajorVersion = $PSVersionTable.PSVersion.Major $msgPowershellMajorVersion = "You're running Powershell v$PowerShellMajorVersion" Write-Host $msgPowershellMajorVersion -BackgroundColor blue -ForegroundColor yellow If($PowerShellMajorVersion -le 2){ Write-Host "Sorry, PowerShell v3 or more is required. Exiting." Return $false Exit } Else { Return $true } } Function Get-EventsFromEventLogs { <# .SYNOPSIS Searches and Get specific events from any computer, local or remote, or from a computer list. .DESCRIPTION This script gathers events from a computer or a list of computers, from the Application, System or Security or all of these Event logs types. You just have to specify which event ID or IDs (e.g. 105, 1020, 67 or just 105 or any number), and spit the events list on the screen. By default, if no computers are specified, the script will search on the local computer. .PARAMETER Computers By default, the script will search for events in the local computer (defined as 127.0.0.1). You can specify a remote computer (NOTE: you must have the Administrative rights in the remote machine), or you can also specify a list of computers, in the form of strings separated by commas like: -Computers "Server1", "Server2", "Server3", "Server4" .PARAMETER EventLogName Which Event Log to look at => default will look on Application and System logs. This parameter can be a string like Application, or an array of strings like ('Application', 'System') for example. By default, the EventLogName parameter is set to ('Application', 'System'), but you can specify "Application" to search on the Application Log only, or "System" to search in the System Log only, or "Security", etc... .PARAMETER EventID This parameter determines which Event number to check. It can be a single number, or an array of numbers. For a single number just type the event ID you're looking for, and for an array of numbers, type the numbers you want the script to search, separated by commas. Example: Get-EventsFromEventLogs.ps1 -EventID 2121 or Get-EventsFromEventLogs.ps1 -EventID 2121, 2242, 2080 .PARAMETER EventSource This parameter determine which Event source to search for. This is optional. To search for all events of type "Outlook" for example on your workstation, type -EventSource "Outlook" .PARAMETER EventLevel With this additionnal parameter, you can filter your search on Event Logs on the Level of events: Name Value ---- ----- Verbose 5 Informational 4 Warning 3 Error 2 Critical 1 LogAlways 0 .PARAMETER NumberOfLastEventsToGet Indicates how many events you want the script to dump. By default the script outputs the 30 last events that you searched for. If there are less than 30 events (or the number you specified), it will dump all the existing events, which can be less than 30 (or the number you specified) .PARAMETER ExportToFile This is a SWITCH that, if specified, will store the results in a CSV file. This file will be placed on the directory where the script is located, and named : "GetEventsFromEventLogs_EventID1-EventID2-XXXXX_Year-MONTH-DAY-Hour-Minute-Second.csv" Example: "GetEventsFromEventLogs_916-105_2018-04-13-09-52-08.csv" AND it will be opened automatically in notepad once the script finishes. .INPUTS The name of the Event Log you want to search in (see EventLogName parameter) and the ID of the event you're looking for (see EventToCheck parameter) .OUTPUTS Shows the events found on the console and/or exported on a file. .EXAMPLE .\Get-EventsFromEventLogs.ps1 Launching the script without options will : - Ask you which event(s) you wish to search for (separated by commas if you want multiple event IDs to search) - Search the local computer - Search the Application and System logs - Get 30 events of the type specified .EXAMPLE .\Get-EventsFromEventLogs.ps1 -Computers MyServers -EventLevel Error This will collect the Error events (the last 30 errors by default) from the computer named MyServers. It won't store it into a file as we didn't call the "-ExportToFile" parameter, just dump into the screen to have an idea if your server is okay or if it's full of errors .EXAMPLE .\Get-EventsFromEventLogs.ps1 -Computers SRV-EX-01,SRV-EX-02,SRV-EX-03 -EventLevel Error -ExportToFile This will collect the Warning, Error, Critical events on computers SRV-EX-01, 02 and 03. The results will be dumped into a file labelled GetEventsFromEventLogs-Date-time.csv as we specified the ExportToFile parameter. Note that the computers list can come from a txt file as well (see next example) .EXAMPLE .\Get-EventsFromEventsLogs.ps1 -Computers $(Get-Content .\ServersList.txt) -EventLevel Error,Critical -ExportToFile This will collect Error and Critical events on computers list defined in the "ServersList.txt" file on the current directory from where you launched the script (.\ refers to the current user directory, NOT the directory where the script is) and store it into a file. .EXAMPLE .\Get-EventsFromEventLogs.ps1 -NumberOfLastEventsToGet 10 -EventID 916,105 -ExportToFile - Search for the 10 last events (-NumberOfLastEventsToGet 10) - Search for event IDs 916 and 105 - As no Event Log name (Application, System, Security, etc...) were specified, the script will look inside the Application AND System logs by default. - We asked the script to look for Event IDs 916 and 105 (-EventID 916, 105) The exported file will be named GetEventsFromEventLogs_916-105_2018-04-13-10-01-55.csv as I ran the script on 13th April 2018 at 10h01 and 55 seconds in the morning. .EXAMPLE .\Get-EventsFromEventLogs.ps1 -NumberOfLastEventsToGet 30 -EventID 26 -EventLogName Application - Search for the last 30 events (-NumberOfLastEventsToGet 30) - Search for Event ID 26 only - Search in the Application Log only - We don't output any file, just print the results on the screen .EXAMPLE .\Get-EventsFromEventLogs.ps1 -EventSource "Outlook" - Search all events generated by the "Outlook" application (all Event IDs, all Level (Info, Warning, etc...)) - Search in Application and System (because I didn't specify which event log) - Search the last 30 events of type "Outlook" - if there are less, it will just print less - We don't output any file because I didn't specify the -ExportToFile parameter MachineName LogName TimeCreated LevelDisplayName Id Message ----------- ------- ----------- ---------------- -- ------- 12345678901 Application 4/13/2018 11:57:06 AM Information 63 La demande de service web Exchange GetAppManifestssuccède à.</0w> 12345678901 Application 4/13/2018 7:57:00 AM Information 63 La demande de service web Exchange GetAppManifestssuccède à.</0w> 12345678901 Application 4/13/2018 7:56:59 AM Information 63 Outlook a détecté une notification de modification pour vos applications et va t... 12345678901 Application 4/13/2018 7:56:55 AM Information 45 Outlook a chargé le(s) complément(s) suivant(s) :... .EXAMPLE .\Get-EventsFromEventLogs.ps1 -EventSource "disk","Outlook" -EventLevel Warning -NumberOfLastEventsToGet 1000 - Search all events which source are "Disk" and "Outlook" - Search only "Warning" events of the above defined sources - All Event IDs of these (because I didn't specify any ID to filter) - Get the 1000 last events of the above criteria - didn't specify the -ExportToFile so will just display to screen .EXAMPLE .\Get-EventsFromEventLogs.ps1 -EventSource "disk" -NumberOfLastEventsToGet 1000 -EventLevel Critical,Warning,Error -ExportToFile - Search all events about the "disk" - Search only Critical, Warning and Error events - Search the 1000 last events about the above criteria - Export into a file (like GetEventsFromEventLogs_None_2018-04-14-04-34-27.csv) .NOTES More examples to be documented as the script gain experience over the usage... .COMPONENT Get-WinEvent cmdlet .LINK https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.diagnostics/get-winevent .LINK https://github.com/SammyKrosoft #> [CmdLetBinding(DefaultParameterSetName = "NormalRun")] Param( [Parameter(Mandatory = $False, Position = 1, ParameterSetName = "NormalRun")] $Computers = ("127.0.0.1"), [Parameter(Mandatory = $False, Position = 2, ParameterSetName = "NormalRun")][ValidateSet("Application","System","Security")] [array]$EventLogName = ('Application', 'System'), [Parameter(Mandatory = $False, Position = 3, ParameterSetName = "NormalRun")] [array]$EventID="All", [Parameter(Mandatory = $False, Position = 4, ParameterSetName = "NormalRun")] [array]$EventSource="All", [Parameter(Mandatory = $False, Position = 5, ParameterSetName = "NormalRun")][ValidateSet("All","Information","Warning","Error","Critical", "Verbose")] [array]$EventLevel="All", [Parameter(Mandatory = $False, Position = 6, ParameterSetName = "NormalRun")] [int]$NumberOfLastEventsToGet = 30, [Parameter(Mandatory = $False, Position = 7, ParameterSetName = "NormalRun")] [Switch]$ExportToFile, [Parameter(Mandatory = $False, Position = 8, ParameterSetName = "NormalRun")] [Boolean]$Confirm = $true, [Parameter(Mandatory = $False, Position = 9, ParameterSetName = "NormalRun")] [switch]$DebugScript, [Parameter(Mandatory = $false, Position = 10, ParameterSetName = "CheckVersionOnly")][Switch]$CheckVersion ) <# ------- SCRIPT_HEADER (Only Get-Help comments and Param() above this point) ------- #> #Initializing a $Stopwatch variable to use to measure script execution $stopwatch = [system.diagnostics.stopwatch]::StartNew() #Using Write-Debug and playing with $DebugPreference -> "Continue" will output whatever you put on Write-Debug "Your text/values" # and "SilentlyContinue" will output nothing on Write-Debug "Your text/values" $DebugPreference = "Continue" # Set Error Action to your needs $ErrorActionPreference = "SilentlyContinue" #Script Version $ScriptVersion = "1.4.4.1" <# Version changes : v1.4.4.1 -> update for the GUI version Get-Events function - added out-string to dump events on host Write-Host ($Events | Select -first $NumberOfLastEventsToGet | ft -a | out-string) v1.4.4 -> corrected examples v1.4.3 -> added a test on Powershell version (using $PSVersionTable) to check whether we can use $PSSCriptRoot variable or $scriptPath = split-path -parent $MyInvocation.MyCommand.Definition instead 1.4.1 -> 1.4.2 Added the CheckVersion switch 1.4 -> 1.4.1 Fixed file name generation when not supplying any EventID and no EventSource -> putting "Last_X_" inside the csv name 1.3 -> 1.4 Oddly, had some events with description = $null on my test machine => I had a stop error on replace carriage with # sign and then added the condition $Event.Message -eq $null to not replace anything to fix this error 1.2.1 -> 1.3 simplified the script requirements : if no parameters specified, search and dump all events ! 1.2 -> 1.2.1 replaced "None" with "All" when we don't specify a filter parameter (because when $EventSouce = nothing, we basically search for all event sources) #> If ($CheckVersion) {Return $ScriptVersion} # Log or report file definition # $EventsReport = "$PSScriptRoot\GetEventsFromEventLogs_$(get-date -f yyyy-MM-dd-hh-mm-ss).csv" # Other Option for Log or report file definition (use one of these) #$LogOrReportFile2 = "$PSScriptRoot\PowerShellScriptExecuted-$(Get-Date -Format 'dd-MMMM-yyyy-hh-mm-ss-tt').txt" <# ---------------------------- /SCRIPT_HEADER ---------------------------- #> <# -------------------------- DECLARATIONS -------------------------- #> $FilterHashProperties = $null $Answer = "" $Events4All = @() <# /DECLARATIONS #> <# -------------------------- FUNCTIONS -------------------------- #> function IsEmpty($Param){ If ($Param -eq "All" -or $Param -eq "" -or $Param -eq $Null -or $Param -eq 0) { Return $True } Else { Return $False } } Function IsPSV3 { <# .DESCRIPTION Just printing Powershell version and returning "true" if powershell version is Powershell v3 or more recent, and "false" if it's version 2. .OUTPUTS Returns $true or $false .EXAMPLE IsPSVersionV3 #> $PowerShellMajorVersion = $PSVersionTable.PSVersion.Major $msgPowershellMajorVersion = "You're running Powershell v$PowerShellMajorVersion" Write-Host $msgPowershellMajorVersion -BackgroundColor blue -ForegroundColor yellow If($PowerShellMajorVersion -le 2){ Return $false } Else { Return $true } } <# /FUNCTIONS #> <# -------------------------- EXECUTIONS -------------------------- #> #cls Write-Host "Starting script..." #$Computers = Get-ExchangeServer #$Computers = "Server-01", "Server-02", "Server-03", "Server-04" #$COmputers = Get-Content C:\temp\MyServersList.txt #$Computers = "127.0.0.1" while ($Answer -ne "Y" -AND $Answer -ne "N") { cls If (IsEmpty $EventSource -and IsEmpty $EventID -and IsEmpty $EventLevel){ Write-host "No Event ID, Event Source or Event Level specified, we will search for all the last $NumberOfLastEventsToGet events on each machine`nor the local machine if you didn't specify the -Computers parameter" -BackgroundColor yellow -ForegroundColor blue } Write-Host "Event log names : $($EventLogName -join ", ")" Write-Host "Computers : $($Computers -join ", ")" Write-Host "Event ID to check : $($EventID -join ", ")" Write-Host "Event Source to check : $($EventSource -join ", ")" Write-Host "Event Level to check : $($EventLevel -join ", ")" Write-Host "Number of events to get : $NumberOfLastEventsToGet" If($ExportToFile){ Write-Host "Write into a file : YES" -ForegroundColor yellow } Else { Write-Host "Write into a file : NO" -ForegroundColor yellow } If ($Confirm){ Write-Host "`nContinue (Y/N) ?" -BackgroundColor Red -ForegroundColor Blue $Answer = Read-host } Else { $Answer = "Y" } If ($Answer -eq "Y"){$StopWatch.Reset();$StopWatch.start()} IF ($Answer -eq "N"){exit} } # Note for remember - sample of Hash table definition: # $Hash= @{LogName='application'; ProviderName='outlook';Level = 2,4} # Which gives: # Name Value # ---- ----- # ProviderName outlook # Level {2, 4} # LogName application # # Then calling Get-WinEvent -FilterHash $Hash $FilterHashProperties = @{ LogName = $EventLogName } If (!(IsEmpty $EventSource)){ $FilterHashProperties.Add('ProviderName',$EventSource) } If (!(IsEmpty $EventID)){ $FilterHashProperties.Add("ID",$EventID) } If (!(IsEmpty $EventLevel)){ for ($i=0;$i -lt $($EventLevel.count);$i++){ $EventLevel[$i] = switch ($EventLevel[$i]) { "LogAlways" {0} "Critical" {1} "Error" {2} "Warning" {3} "Information" {4} "Verbose" {5} } } $FilterHashProperties.Add('Level',$EventLevel) } #Just adding a debug hard coded switch to check my filter... if ($DebugScript){ $FilterHashProperties $Computer = "127.0.0.1" $Events = Get-WinEvent -FilterHashtable $FilterHashProperties -MaxEvents $NumberOfLastEventsToGet -Computer $Computer -ErrorAction stop | select MachineName, LogName, TimeCreated, LevelDisplayName, ProviderName, ID, Message Foreach ($Event in $Events) { If ($Event.Message -ne $null){ $Event.Message = $Event.Message.Replace("`r","#") } } Write-host "Found at least $($Events.count) events ! Here are the $NumberOfLastEventsToGet last ones :" Write-Host ($Events | Select -first $NumberOfLastEventsToGet | ft -a | out-string) exit } Foreach ($computer in $computers) { Write-host "Checking Computer $Computer" -BackgroundColor yellow -ForegroundColor Blue Try { $LastEvent = Get-WinEvent -ComputerName $Computer -Logname 'Application' -oldest -MaxEvents 1 Write-host "Event logs on $computer goes as far as $($LastEvent.TimeCreated)" Try { $Events = Get-WinEvent -FilterHashtable $FilterHashProperties -MaxEvents $NumberOfLastEventsToGet -Computer $Computer -ErrorAction stop | select MachineName, LogName, TimeCreated, LevelDisplayName, ProviderName, ID, Message Foreach ($Event in $Events) { If ($Event.Message -ne $null){ $Event.Message = $Event.Message.Replace("`r","#") } } Write-host "Found at least $($Events.count) events ! Here are the $NumberOfLastEventsToGet last ones :" Write-Host ($Events | Select -first $NumberOfLastEventsToGet | ft -a | out-string) $Events4All += $Events } Catch { Write-Host "No such events with EventID = $($FilterHashProperties.ID) in the $($FilterHashProperties.LogName) event log on this computer..." -ForegroundColor Green } Finally { Write-Host "OK_" } } Catch { Write-Host "Error accessing Event Logs of $computer" -ForegroundColor Red } } Write-host "Found $($Events4all.count) Events in total ..." -BackgroundColor blue -ForegroundColor yellow Write-host "Here are the stats by Event Level :" Write-host ($Events4All | Group-Object LevelDisplayName | ft @{Label="Event Level";Expression ={$_.Name}},@{Label = "Number of Events";Expression = {$_.Count}} | out-string) If ($ExportToFile){ If (!(IsEmpty $EventID)){ $FileEventLogFirstID = "GetEventsFromEventLogs_$($EventID[0])_$(get-date -f yyyy-MM-dd-hh-mm-ss).csv" If (IsPSV3){ $EventsReport = "$PSScriptRoot\$FileEventLogFirstID" } Else { $EventsReport = "$(split-path -parent $MyInvocation.MyCommand.Definition)\$FileEventLogFirstID" } } Else { If (!(IsEmpty $EventSource)){ $FileEventLogFirstSource = "GetEventsFromEventLogs_$($EventSource[0])_$(get-date -f yyyy-MM-dd-hh-mm-ss).csv" If (IsPSV3){ $EventsReport = "$PSScriptRoot\$FileEventLogFirstSource" } Else { $EventsReport = "$(split-path -parent $MyInvocation.MyCommand.Definition)\$FileEventLogFirstSource" } } Else { $FileNumberOfLastEvents = "GetEventsFromEventLogs_Last_$($NumberOfLastEventsToGet)_$(get-date -f yyyy-MM-dd-hh-mm-ss).csv" If(IsPSV3){ $EventsReport = "$PSScriptRoot\$FileNumberOfLastEvents" } else { $EventsReport = "$(split-path -parent $MyInvocation.MyCommand.Definition)\$FileNumberOfLastEvents" } } } $Events4all | Export-Csv -NoTypeInformation $EventsReport notepad $EventsReport } <# /EXECUTIONS #> <# ---------------------------- SCRIPT_FOOTER ---------------------------- #> #Stopping StopWatch and report total elapsed time (TotalSeconds, TotalMilliseconds, TotalMinutes, etc...) $stopwatch.Stop() Write-Host "The script took $($StopWatch.Elapsed.TotalSeconds) seconds to execute..." <# ---------------- /SCRIPT_FOOTER (NOTHING BEYOND THIS POINT) ----------- #> } function IsEmpty($Param){ If ($Param -eq "All" -or $Param -eq "" -or $Param -eq $Null -or $Param -eq 0) { Return $True } Else { Return $False } } Function Say { [CmdletBinding(DefaultParameterSetName = "NormalRun")] Param( [Parameter(Mandatory = $false, Position = 0, ParameterSetName = "NormalRun")] [String]$Msg ) If ($wpf.chkSpeech.IsChecked -eq $true) { $InstalledVoices = @() Add-Type -AssemblyName System.Speech $Speak = New-Object system.Speech.Synthesis.SpeechSynthesizer # $InstalledVoices = $Speak.GetInstalledVoices().VoiceInfo # $InstalledVoices # Select by hint like this ('Male/Female', 'NotSet/Child/Teen/Adult/Senior',[int32]'Position which voices are ordered','fr/en') switch ($wpf.lstBoxLanguage.SElectedItem.Content) { "Francais" {$Language = 'fr'} "English" {$Language = 'en'} "" {$language = 'en'} $null {$Language = 'en'} } $Speak.SelectVoiceByHints(0,0,0,$language) $Speak.Speak($Msg) } } Function WritNSay ($msg) { Write-Host $msg Say $msg } Function Split-ListColon { param( [string]$StringToSplit, [switch]$Noquotes ) $TargetSplit = $StringToSplit.Split(',') $ListItems = "" If ($NoQuotes){ For ($i = 0; $i -lt $TargetSplit.Count - 1; $i++) {$ListItems += $TargetSplit[$i].trim() + (", ")} $ListItems += $TargetSplit[$TargetSplit.Count - 1].trim() } Else { For ($i = 0; $i -lt $TargetSplit.Count - 1; $i++) {$ListItems += ("""") + $TargetSplit[$i].trim() + (""", ")} $ListItems += ("""") + $TargetSplit[$TargetSplit.Count - 1].trim() + ("""") } Return $ListItems } Function Update-cmd{ # [Parameter(Mandatory = $False, Position = 1, ParameterSetName = "NormalRun")] # $Computers = ("127.0.0.1"), # [Parameter(Mandatory = $False, Position = 2, ParameterSetName = "NormalRun")][ValidateSet("Application","System","Security")] # [array]$EventLogName = ('Application', 'System'), # [Parameter(Mandatory = $False, Position = 3, ParameterSetName = "NormalRun")] # [array]$EventID="All", # [Parameter(Mandatory = $False, Position = 4, ParameterSetName = "NormalRun")] [array]$EventSource="All", # [Parameter(Mandatory = $False, Position = 5, ParameterSetName = "NormalRun")][ValidateSet("All","Information","Warning","Error","Critical", "Verbose")] # [array]$EventLevel="All", # [Parameter(Mandatory = $False, Position = 6, ParameterSetName = "NormalRun")] [int]$NumberOfLastEventsToGet = 30, # [Parameter(Mandatory = $False, Position = 7, ParameterSetName = "NormalRun")] [Switch]$ExportToFile, # [Parameter(Mandatory = $False, Position = 8, ParameterSetName = "NormalRun")] [Boolean]$Confirm = $true, # [Parameter(Mandatory = $False, Position = 9, ParameterSetName = "NormalRun")] [switch]$DebugScript, # [Parameter(Mandatory = $false, Position = 10, ParameterSetName = "CheckVersionOnly")][Switch]$CheckVersion $command = "Get-EventsFromEventLogs" If ($($wpf.txtCSVComputersList.Text) -ne ""){ $TextBoxList = Split-ListColon -StringToSplit $wpf.txtCSVComputersList.Text $command += (" -Computers ") + ($TextBoxList) } If ($($wpf.chkAppLog.IsChecked) -or $($wpf.chkSystemLog.IsChecked) -or $($wpf.chkSecurityLog.IsChecked)){ [string[]]$LogsToSearch = @() If($wpf.chkAppLog.IsChecked){$LogsToSearch += "Application"} If($wpf.chkSystemLog.IsChecked) {$LogsToSearch += "System"} If($wpf.chkSecurityLog.IsChecked) {$LogsToSearch += "Security"} $LogsToSearch = $LogsToSearch -join ", " $Command += (" -EventLogName ") + $LogsToSearch } If ($($wpf.chkLevelInformation.IsChecked) -or $($wpf.chkLevelWarning.IsChecked) -or $($wpf.chkLevelError.IsChecked) -or $($wpf.chkLevelCritical.IsChecked)){ [string[]]$EventLevelToSearch = @() If ($wpf.chkLevelInformation.IsChecked){$EventLevelToSearch += "Information"} If ($wpf.chkLevelWarning.IsChecked){$EventLevelToSearch += "Warning"} If ($wpf.chkLevelError.IsChecked){$EventLevelToSearch += "Error"} If ($wpf.chkLevelCritical.IsChecked){$EventLevelToSearch += "Critical"} $EventLevelToSearch = $EventLevelToSearch -join ", " $command += (" -EventLevel ") + $EventLevelToSearch } If ($($wpf.chkSaveToFile.IsChecked)){ $command += " -ExportToFile" } If ($($wpf.txtEventIDs.Text) -ne ""){ $TextBoxList = Split-ListColon -StringToSplit $wpf.txtEventIDs.Text -NoQuotes $command += (" -EventID ") + ($TextBoxList) } If ($($wpf.txtEventSources.Text) -ne ""){ $TextBoxList = Split-ListColon -StringToSplit $wpf.txtEventSources.Text $command += (" -EventSource ") + ($TextBoxList) } If (($($wpf.txtNumberOfEvents.Text) -ne "30") -and ($($wpf.txtNumberOfEvents.Text) -ne "")){ $command += (" -NumberOfLastEventsToGet ") + ($wpf.txtNumberOfEvents.Text) } $command += " -Confirm `$false" # Populate the cmdlet text box that it's gonna use... $wpf.txtCommand.text = $command } #======================================================== # End of Functions definitions (note the WPF form events) #endregion #======================================================== #======================================================== #region WPF form definition and load controls #======================================================== # Load a WPF GUI from a XAML file build with Visual Studio Add-Type -AssemblyName presentationframework, presentationcore $wpf = @{} # NOTE: Either load from a XAML file or paste the XAML file content in a "Here String" # $inputXML = Get-Content -Path "C:\Users\Kamehameha\Documents\GitHub\PowerShell\Get-EventsFromEventLog\VisualStudio2017WPFDesign\Launch-EventsCollector-WPF\Launch-EventsCollector-WPF\MainWindow.xaml" $inputXML = @" <Window x:Name="EventCollectWindow" x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp1" mc:Ignorable="d" Title="SearchAndCollect" Height="573.903" Width="800" ShowActivated="False" Background="#FFA19C9C"> <Grid Margin="0,0,0,0" Background="Teal"> <TextBox x:Name="txtCSVComputersList" HorizontalAlignment="Left" Height="147" Margin="10,41,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="317"/> <Label Content="Computers List (Comma Separated)" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="202"/> <CheckBox x:Name="chkLevelInformation" Content="Information" HorizontalAlignment="Left" Margin="498,28,0,0" VerticalAlignment="Top"/> <CheckBox x:Name="chkLevelWarning" Content="Warning" HorizontalAlignment="Left" Margin="498,48,0,0" VerticalAlignment="Top"/> <CheckBox x:Name="chkLevelError" Content="Error" HorizontalAlignment="Left" Margin="498,68,0,0" VerticalAlignment="Top"/> <CheckBox x:Name="chkLevelCritical" Content="Critical" HorizontalAlignment="Left" Margin="498,88,0,0" VerticalAlignment="Top"/> <TextBox x:Name="txtNumberOfEvents" HorizontalAlignment="Left" Height="20" Margin="228,233,0,0" TextWrapping="Wrap" Text="30" VerticalAlignment="Top" Width="99"/> <TextBlock HorizontalAlignment="Left" Margin="228,193,0,0" TextWrapping="Wrap" Text="Events to collect per computer" VerticalAlignment="Top" Width="104"/> <TextBox x:Name="txtCommand" HorizontalAlignment="Left" Height="75" Margin="10,354,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="775" IsReadOnly="True"/> <Label Content="Function Command Line we'll launch" HorizontalAlignment="Left" Margin="10,323,0,0" VerticalAlignment="Top" Width="240"/> <Button x:Name="btnRun" Content="Run" HorizontalAlignment="Left" Height="30" Margin="149,434,0,0" VerticalAlignment="Top" Width="161"/> <Button x:Name="btnCancel" Content="Cancel" HorizontalAlignment="Left" Margin="471,434,0,0" VerticalAlignment="Top" Width="160" Height="30"/> <CheckBox x:Name="chkSpeech" Content="Speech" HorizontalAlignment="Left" Margin="681,28,0,0" VerticalAlignment="Top"/> <ListBox x:Name="lstBoxLanguage" HorizontalAlignment="Left" Height="47" Margin="681,48,0,0" VerticalAlignment="Top" Width="70" IsSynchronizedWithCurrentItem="False" IsEnabled="False" SelectedIndex="1"> <ListBoxItem Content="Francais"/> <ListBoxItem Content="English"/> </ListBox> <TextBox x:Name="txtEventIDs" HorizontalAlignment="Left" Height="32" Margin="483,143,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="302"/> <TextBox x:Name="txtEventSources" HorizontalAlignment="Left" Height="62" Margin="483,206,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="302"/> <Label Content="Event IDs to look for (comma separated)" HorizontalAlignment="Left" Margin="483,117,0,0" VerticalAlignment="Top" Width="302"/> <Label Content="Event Sources to look for (comma separated)" HorizontalAlignment="Left" Margin="483,180,0,0" VerticalAlignment="Top" Width="302"/> <CheckBox x:Name="chkSaveToFile" Content="Save events to file" HorizontalAlignment="Left" Margin="483,282,0,0" VerticalAlignment="Top"/> <Label x:Name="lblGUIVer" Content="GUI version" HorizontalAlignment="Left" Margin="10,242,0,0" VerticalAlignment="Top" Background="#FFC1B621"/> <Label x:Name="lblFUNCVer" Content="Event collector function version" HorizontalAlignment="Left" Margin="10,268,0,0" VerticalAlignment="Top" Background="#FF66D71F"/> <ListBox x:Name="lstEventLogs" HorizontalAlignment="Left" Height="284" Margin="332,10,0,0" VerticalAlignment="Top" Width="146" SelectionMode="Multiple"/> <Button x:Name="btnGetList" Content="Get Event Log List" HorizontalAlignment="Left" Margin="332,308,0,0" VerticalAlignment="Top" Width="146"/> <TextBlock x:Name="txtStatus" HorizontalAlignment="Center" Margin="10,506,22,0" TextWrapping="Wrap" Text="Ready !" VerticalAlignment="Top" Width="763" Height="30" Background="#FF969292" FontSize="20" IsEnabled="False"/> </Grid> </Window> "@ $inputXMLClean = $inputXML -replace 'mc:Ignorable="d"','' -replace "x:N",'N' -replace 'x:Class=".*?"','' -replace 'd:DesignHeight="\d*?"','' -replace 'd:DesignWidth="\d*?"','' [xml]$xaml = $inputXMLClean $reader = New-Object System.Xml.XmlNodeReader $xaml $tempform = [Windows.Markup.XamlReader]::Load($reader) $namedNodes = $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") $namedNodes | ForEach-Object {$wpf.Add($_.Name, $tempform.FindName($_.Name))} $FormName = $NamedNodes[0].Name #======================================================== # END of WPF form definition and load controls #endregion #======================================================== #region in-form functions definition Function Status-Ready{ $wpf.txtStatus.text = "Ready !" $wpf.txtStatus.ForeGround = "Green" $wpf.$FormName.IsEnabled = $true $wpf.$FormName.Dispatcher.Invoke("Render",[action][scriptblock]{}) } Function Status-Working{ [CmdletBinding()] Param( [Parameter(Mandatory = $False, Position = 1)] [String]$Msg="Please wait while working...", [Parameter(Mandatory = $False, Position = 2)] [String] $Color = "Red" ) $wpf.txtStatus.text = $Msg $wpf.txtStatus.Foreground = $Color $wpf.$FormName.IsEnabled = $false $wpf.$FormName.Dispatcher.Invoke("Render",[action][scriptblock]{}) } #endregion #End of in-form functions definition #======================================================== #region WPF EVENTS definition #======================================================== #region Buttons $wpf.btnRun.add_Click({ $msg = "Running the command" WritNSay $msg Status-Working "Please wait while getting all the events ..." Invoke-expression $wpf.txtCommand.text Status-Ready }) $wpf.btnCancel.add_Click({ $msg = "Exiting..." WritNSay $msg $wpf.$FormName.Close() }) $wpf.btnGetList.add_Click({ # Option #4 - a message, a title, buttons, and an icon # More info : https://msdn.microsoft.com/en-us/library/system.windows.messageboximage.aspx $msg = "Warning: if you're not Local Admin of the machine, some Event Log sources won't be displayed, such as the System log and other Crimson Channel logs.`nLaunch again the tool using an elevated prompt (Run As Admin) to view all the Event Logs." $Title = "Awareness - if you're not Local Admin" $Button = "Ok" $Icon = "Warning" [System.Windows.MessageBox]::Show($msg,$Title, $Button, $icon) #Updating form while loading event logs list... Status-Working "Please wait while getting Event Logs list..." # Action ! # $EventLogsList = @() $EventLogsList = Get-WinEvent -ListLog * -ErrorAction SilentlyContinue | ForEAch {$_.LogName} # $EventLogsList = $EventLogsList | Foreach {$_.LogName} $wpf.lstEventLogs.ItemsSource = $EventLogsList #Updating form when loading event logs list is done... Status-Ready }) # End of Buttons region #endregion #region Speech management region $wpf.chkSpeech.add_Checked({ $wpf.lstBoxLanguage.Isenabled = $true If ($($wpf.lstBoxLanguage.SelectedItem.content) -eq "Francais") { $msg = "Narrateur activé - merci de m'enlever mon baillon !" } Else { $msg = "Narrator activated - thanks for unmuting me !" } WritNsay $msg }) $wpf.chkSpeech.add_UnChecked({ $wpf.lstBoxLanguage.Isenabled = $false }) $wpf.lstBoxLanguage.add_SelectionChanged({ $msg = "Language = $($wpf.lstBoxLanguage.SelectedItem.content)" If ($($wpf.lstBoxLanguage.SelectedItem.content) -eq "Francais") { $msg = "Langue Francaise sélectionnée !" } Else { $msg = "English Language selected !" } WritNsay $msg}) # End of speech management region #endregion #region Load, Draw (render) and closing form events #Things to load when the WPF form is loaded aka in memory $wpf.$FormName.Add_Loaded({ $wpf.lblGUIVer.content += $global:GUIversion $wpf.lblFUNCVer.content += (" ") + (Get-EventsFromEventLogs -CheckVersion) }) #Things to load when the WPF form is rendered aka drawn on screen $wpf.$FormName.Add_ContentRendered({ Update-cmd }) $wpf.$FormName.add_Closing({ $msg = "bye bye !" WritNSay $msg }) # End of load, draw and closing form events #endregion #region Text Changed events $wpf.txtCSVComputersList.add_TextChanged({ Update-cmd }) $wpf.txtNumberOfEvents.add_TextChanged({ Update-cmd }) $wpf.txtEventIDs.add_TextChanged({ Update-cmd }) $wpf.txtEventSources.add_TextChanged({ Update-cmd }) #End of Text Changed events #endregion #region Clicked on Checkboxes events $wpf.chkLevelInformation.add_Click({ Say "Information events" Update-cmd }) $wpf.chkLevelWarning.add_Click({ Say "Warning events" Update-cmd }) $wpf.chkLevelError.add_Click({ Say "Error events" Update-cmd }) $wpf.chkLevelCritical.add_Click({ Say "Critical events" Update-cmd }) $wpf.chkSaveToFile.add_Click({ Say "Save to file" Update-cmd }) # End of Clicked on Checkboxes events #endregion #region Event Log types selection #endregion #End of region for event log type selection #======================================================= #End of Events from the WPF form #endregion #======================================================= IsPSV3 | out-null # Load the form: # Older way >>>>> $wpf.$FormName.ShowDialog() | Out-Null >>>> generates crash if run multiple times # USing method from https://gist.github.com/altrive/6227237 to avoid crashing Powershell after we re-run the script after some inactivity time or if we run it several times consecutively... $async = $wpf.$FormName.Dispatcher.InvokeAsync({ $wpf.$FormName.ShowDialog() | Out-Null }) $async.Wait() | Out-Null |