Powershell send email on event id - windows

I found a tutorial to send an email when a certain event occurs. The code is this:
$EventId = 4771
$A = Get-WinEvent -MaxEvents 1 -FilterHashTable #{Logname = "System" ; ID = $EventId}
$Message = $A.Message
$EventID = $A.Id
$MachineName = $A.MachineName
$Source = $A.ProviderName
$EmailFrom = "email#domain.com"
$EmailTo = "email#domain.com"
$Subject ="Alert From $MachineQ"
$Body = "EventID: $EventIDnSource: $SourcenMachineQ: $MachineQ `nMessage: $Message"
$SMTPServer = "smtp.server"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
The problem is that I would also like to receive the date/time of the event in the email but I don't know how to add that parameter. Currently the email looks like this:
EventID: 4771
Source: Microsoft-Windows-Security-Auditing
MachineName: server.domain
Message: user blocked.
I would like something like:
EventID: 4771
Source: Microsoft-Windows-Security-Auditing
**Date: 25/11/2022 10:02**
MachineName: server.domain
Message: user blocked.
Could someone tell me how to modify the code to add this parameter?

Related

Powershell script is not displaying registry

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(500,300)
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$label = New-Object System.Windows.Forms.Label
$label.Text = "Click the button to view the ProfileList registry in regedit"
$label.Size = New-Object System.Drawing.Size(300,30)
$label.Location = New-Object System.Drawing.Point(100,50)
$display_button = New-Object System.Windows.Forms.Button
$display_button.Text = "Display ProfileList"
$display_button.Size = New-Object System.Drawing.Size(150,30)
$display_button.Location = New-Object System.Drawing.Point(175,100)
$display_button.Add_Click({
regedit "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
})
$form.Controls.Add($label)
$form.Controls.Add($display_button)
$form.ShowDialog()
Upon running the script I receive the following error:
"Error opening the file"
I am not sure if the path is correct, can someone point out what I'm doing wrong?
Before opening regedit.exe, perform the following:
Set-ItemProperty 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Applets\Regedit' 'LastKey' 'Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
or
$splat = #{
'Path' = 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Applets\Regedit'
'Name' = 'LastKey'
'Value' = 'Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
}
Set-ItemProperty #splat
and edit your button click actdion to simply:
$display_button.Add_Click({
regedit
})

Trying to count the time passed between a start and stop events in PowerShell

I am trying to obtain the difference in time between each start and stop action in the following output:
User Computer Time Event Action
---- -------- ---- ----- ------
TEST\me TEST-DC-01 27/05/2020 14:45:06 Logoff Stop
TEST\me TEST-DC-01 27/05/2020 14:44:56 Unlock Start
TEST\me TEST-DC-01 27/05/2020 14:44:49 Lock Stop
TEST\me TEST-DC-01 27/05/2020 14:44:40 Reconnect Start
TEST\me TEST-DC-01 27/05/2020 14:43:17 Disconnect Stop
TEST\me TEST-DC-01 27/05/2020 14:43:07 Logon Start
I've been playing with the New-Timespan cmdlet but seem to be going round and round in circles when trying to integrate it with the script (below) which the above output is derived from.
Ideally, I'd like to see the following appended to it:
Total active time: 00:00:29
Can anyone advise on the best approach (either by fully integrating with the existing script or by importing the output in CSV format).
Any guidance most appreciated.
#
# GROUP POLICY (TO ENABLE 480x AND 477x EVENTS):
#
# COMPUTER CONFIGURATION
# - WINDOWS SETTINGS
# - SECURITY SETTINGS
# - ADVANCED AUDIT POLICY CONFIGURATION
# - SYSTEM AUDIT POLICIES - LOCAL GROUP POLICY OBJECT
# - LOGON/LOGOFF
# - AUDIT OTHER LOGON/LOGOFF EVENTS
# - SUCCESS
#
$OU = "OU=Domain Controllers,DC=test,DC=local"
# WHERE TO SEARCH FOR COMPUTERS IN ACTIVE DIRECTORY
$days = "-1"
# HOW MANY DAYS TO SEARCH BACK THROUGH
$directory = "C:\"
# LOCATION OF FAILED CONNECTIONS FILE
$computers = Get-ADComputer -Filter * -SearchBase $OU
$logs = #()
$timestamp = ((Get-Date).ToString("yyyyMMdd_HHmmss"))
$output = ForEach ($computer in $computers){
try{
$logs += get-eventlog `
-LogName system `
-ComputerName $computer.Name `
-After (Get-Date).AddDays($days)
$logs += get-eventlog `
-LogName security `
-ComputerName $computer.Name `
-After (Get-Date).AddDays($days)
$res = #()
ForEach ($log in $logs){
if($log.instanceid -eq 7001){
$type = "Logon"
$user =
try{
(New-Object System.Security.Principal.SecurityIdentifier(
$log.ReplacementStrings[1])).Translate(
[System.Security.Principal.NTAccount]).value
}
catch{
$log.ReplacementStrings[1]
}
$action = "Start"
}
Elseif ($log.instanceid -eq 7002){
$type = "Logoff"
$user =
try{
(New-Object System.Security.Principal.SecurityIdentifier(
$log.ReplacementStrings[1])).Translate(
[System.Security.Principal.NTAccount]).value
}
catch{
$log.ReplacementStrings[1]
}
$action = "Stop"
}
Elseif ($log.instanceid -eq 4800){
$type = "Lock"
$user = $log.ReplacementStrings[2] + "\" +
$log.ReplacementStrings[1]
$action = "Stop"
}
Elseif ($log.instanceid -eq 4801){
$type = "Unlock"
$user = $log.ReplacementStrings[2] + "\" +
$log.ReplacementStrings[1]
$action = "Start"
}
Elseif ($log.instanceid -eq 4778){
$type = "Reconnect"
$user = $log.ReplacementStrings[1] + "\" +
$log.ReplacementStrings[0]
$action = "Start"
}
Elseif ($log.instanceid -eq 4779){
$type = "Disconnect"
$user = $log.ReplacementStrings[1] + "\" +
$log.ReplacementStrings[0]
$action = "Stop"
}
Else {
Continue
}
$hash = [ordered]#{
"User" = $user
"Computer" = $computer.Name
"Time" = $log.TimeWritten
"Event" = $type
"Action" = $action
}
$res += New-Object PSObject -Property $hash
}
$res
}
Catch {
Add-Content -Path "${directory}${timestamp}_failed.txt" $computer.Name
}
}
$TimeDescending = #{
Expression = 'Time'
Descending = $true
}
$EventDescending = #{
Expression = 'Event'
Descending = $true
}
$output |
sort User,Computer,$TimeDescending,$EventDescending |
? User -like "*me" |
ft
You could use the New-TimeSpan cmdlet:
$start = Get-Date
# Do some stuff here
$end = Get-Date
$timeTaken = (New-TimeSpan -Start $start -End $end).TotalSeconds

Error Handler not catching Errors in PowerShell

On my venture in learning PowerShell, I have hit into another issue which I would like to get your help in this.
I have a code below inside a try-catch but when an error occurs inside the try block it does not seem to send it to catch block.
The Code:
try{
if ($isFileAvailable -gt 0){
$hashArgumentWithAttachment = #{
From = $From
To = $To
Subject = $Subject
Body = $Body
SmtpServer = $SMTPServer
Port = $SMTPPort
UseSsl = $true
Credential = $smtpCredential
Attachments = $filePath
}
Send-MailMessage #hashArgumentWithAttachment
}
Else {
$hashArgumentWithOutAttachment = #{
From = $From
To = $To
Subject = $Subject
Body = $Body
SmtpServer = $SMTPServer
Port = $SMTPPort
UseSsl = $true
Credential = $smtpCredential
}
Send-MailMessage #hashArgumentWithoutAttachment
}
Write-Output "Emailed"
break
}catch {
Write-Output "Error Occured, No of Attempts So far: " + $attempts.ToString()
}
On an instance where there is a Server connectivity error I expect to hit the catch block but instead it throws an error like this:
Add ErrrorAction to the CMDLet:
Send-MailMessage #hashArgumentWithoutAttachment -ErrorAction Stop
Cheers!

Unable to clear or reset a listbox

I'm having trouble clearing a listbox that I created in my PowerShell form. If I call the listbox.Item.Clear method, the data stored in the listbox object is cleared but the items displayed in the from remain. Even after I try to create a new, blank listbox, the old items are still displayed. The listbox is created in a function that is called by a button click. I want the listbox to be cleared and repopulated each time the button is clicked. I can easily clear and re-add text to a text box by doing something like $textbox.Text = "new text". Is there a way to do this with a listbox? Here's what I have:
function AddMembers() {
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form
$form.Text = 'Select a Computer'
$form.Size = New-Object System.Drawing.Size(610,450)
$form.StartPosition = 'CenterScreen'
# Create the TextBox used to capture the user's text.
$textBox = New-Object System.Windows.Forms.Textbox
$textBox.Location = '10,40'
$textBox.Size = '375,170'
$textBox.AcceptsReturn = $true
$textBox.Multiline = $true
#$textBox.Text = $UserInputData
$form.Controls.Add($textBox)
function Global:GetTheSearchString() {
# If any text is present in the text box, convert it to a sting, parse, then conver to array $Global:UserInput2
$UserInput = $textBox.ToString()
$UserInput = $UserInput -replace "System.Windows.Forms.TextBox, Text: "
$Global:UserInput2 = $UserInput -split "`r`n"
Write-Host $Global:UserInput2
$InputLength = $UserInput2.Length
Write-Host $InputLength
$Global:lastLine = $UserInput2[$InputLength -1]
Write-Host "$Global:lastLine lastLine"
#return $Global:lastLine
}
# Take an input string, search AD, and return the results as an array.
function Global:SearchAD($SearchString) {
$Groups = Get-ADObject -LDAPFilter "(cn=$SearchString*)" | select Name | Out-String
$Groups = $Groups -replace "Name"
$Groups = $Groups -replace "----"
$Groups = $Groups.Trim()
$GroupsArray = $Groups -split "`r`n"
#Write-Host $GroupsArray
return $GroupsArray
}
# Create the list box for displaying search results
function CreateListBoxResults($searchResults, $param) {
$listBox = New-Object System.Windows.Forms.ListBox
#$form.Controls.Add($listBox)
#$listBox.Items.Clear()
#$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,225)
$listBox.Size = New-Object System.Drawing.Size(375,20)
$listBox.Height = 150
# Add values to the list box
foreach ($line in $searchResults) {
[void] $listBox.Items.Add($line)
Write-Host $line
}
#$listBox.Refresh()
$form.Controls.Add($listBox)
Write-Host "$param param"
#Write-Host "$listBox listbox"
$form.Controls.Add($listBox)
if ($param -eq $true) {
Write-Host "$param param"
$listBox.Dispose()
$listBox.Items.Clear()
$form.Controls.Add($listBox)
}
}
#$selectButton.Add_Click({ [string]$selection = $listBox.SelectedItem.ToString(); Write-Host $selection; Global:ResetSearchBox($selection)})
#$selectButton.Add_Click({ Write-Host $Global:listBox; $click = $true; $Global:listBox.Items.Clear(); $form.Controls.Remove($Global:listBox); $form.Controls.Add($Global:listBox)})
Write-Host $UserInput2
$checkButton = New-Object System.Windows.Forms.Button
$checkButton.Location = New-Object System.Drawing.Point(9,380)
$checkButton.Size = New-Object System.Drawing.Size(85,23)
$checkButton.Text = 'Check Name'
$form.Controls.Add($checkButton)
$checkButton.Add_Click({ Global:GetTheSearchString; Write-Host "$Global:lastLine check"; CreateListBoxResults (Global:SearchAD($Global:lastLine)) $false })
$selectButton = New-Object System.Windows.Forms.Button
$selectButton.Location = New-Object System.Drawing.Point(102,380)
$selectButton.Size = New-Object System.Drawing.Size(75,23)
$selectButton.Text = 'Select'
$form.Controls.Add($selectButton)
$selectButton.Add_Click({ CreateListBoxResults $nul $true})
#$form.Controls.Add($listBox)
$form.Topmost = $true
$form.Add_Shown({$form.Activate()})
$form.ShowDialog() > $nul
}
AddMembers
For clearing the listbox you are right in using listbox.Item.Clear().
However there are some other usefull methods:
$listBox.Dispose()
The Dispose method leaves the Component in an unusable state. (You might not want this one.)
$form.Controls.Remove($listBox)
Remove your listbox from the form instead of deleting the object.
$listBox.Visible = $false (or $true)
Hide your listbox instead of removing it
$listBox.Items.Clear()
$listBox.Items.AddRange(*SomeArrayHere*)
The closest you can get to $textbox.text = "NewText"
Using some of these your function could look something like this:
function CreateListBoxResults($searchResults, $param) {
# Only create a listbox if it doesn't exist
if (!$listBox) {
$listBox = New-Object System.Windows.Forms.ListBox
$listBox.Location = New-Object System.Drawing.Point(10,225)
$listBox.Size = New-Object System.Drawing.Size(375,20)
$listBox.Height = 150
}
# Add listbox to form
$form.Controls.Add($listBox)
# Add values to the list box
$listBox.Items.Clear()
foreach ($line in $searchResults) {
[void] $listBox.Items.Add($line)
Write-Host $line
}
# Remove listbox from form if $param = $true
Write-Host "$param param"
if ($param -eq $true) {
Write-Host "$param param"
$form.Controls.Remove($listBox)
}
}

How to add an embedded image to a script?

I am completely stumped. I am trying to add an embedded image to a notification email. The only scripts i can find are using .net to create a new email object.Can this only be done using .net to create an email object? Any Ideas
#################################################
# Configure the following variables….
# expireindays1 + 2 = At what count of days left on a password do you want a notification?
$smtpServer=”smtprelay.domain.com”
$expireindays1 = 5
#$expireindays2 = 1
$from = “Technology Helpdesk <technologyhelpdesk#domain.com>”
#################################################
#Get Users From AD who are enabled
Import-Module ActiveDirectory
$users = get-aduser -filter * -Properties enabled, GivenName, passwordneverexpires, passwordexpired, emailaddress, passwordlastset |where {$_.Enabled -eq “True”} | where { $_.PasswordNeverExpires -eq $false } | where { $_.passwordexpired -eq $false }
foreach ($user in $users)
{
$Name = (Get-ADUser $user | foreach { $_.Name})
$UserID = (Get-ADUser $user -Properties *).Samaccountname
$emailaddress = $user.emailaddress
$passwordSetDate = (get-aduser $user -properties passwordlastset | foreach { $_.PasswordLastSet })
$PasswordPol = (Get-AduserResultantPasswordPolicy $user)
# Check for Fine Grained Password
if (($PasswordPol) -ne $null)
{
$maxPasswordAge = ($PasswordPol).MaxPasswordAge
}
else
{
$maxPasswordAge = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge
}
$expireson = $passwordsetdate + $maxPasswordAge
$today = (get-date)
$daystoexpire = (New-TimeSpan -Start $today -End $Expireson).Days
#$subject=
$body = #'
#<html>
<body>
<img src="cid:image1"><br>
<b>$UserID : Your password will expire soon</b>
<br>
<br>
<br>
Dear $name,<br>
Your password will expire in $daystoexpire days. Please change your password before it expires to avoid password related problems. .<br>
<br>
<br>
<b>Password complexity rules:<br>
<br>
- Must be 7 or 8 characters long<br>
- Must contain at least 1 uppercase letter<br>
- Must contain at least 1 lowercase letter<br>
- Must contain at least 1 number<br>
- Must NOT contain repeating characters (e.g., aa, 11)</b><br>
<br>
<br>
Please use the following steps to change your password:<br>
- Press CTRL+ALT+DEL<br>
- Click Change a password…<br>
- Verify your User ID is correct, then type in your old and new passwords (you cannot use previously used passwords)<br>
- After the change is complete, you will be prompted that your password has been changed<br>
- If you have a Blackberry, iPhone, or iPad, those devices will need your new password as soon as your password has been changed<br>
<br>
If you have questions, or need assistance updating your passwords, please contact the Technology Help Desk. <br>
</body>
#</html>
'#
if (($daystoexpire -eq $expireindays1))
# -or ($daystoexpire -eq $expireindays2))
{
#Send-Mailmessage -smtpServer $smtpServer -from $from -to user#domain.com -subject $subject -body $body -bodyasHTML -priority High
####################################################################################################################
$images = #{
image1 = "c:\temp\action needed.png"
}
$params = #{
InlineAttachments = $images
#Attachments = 'C:\temp\action needed.png'
Body = $body
BodyAsHtml = $true
Subject = ”Your password will expire in $daystoExpire days”
From = "Technology Helpdesk <technologyhelpdesk#domain.com>"
To = 'user#domain.com'
#Cc = 'recipient2#domain.com', 'recipient3#domain.com'
SmtpServer = 'smtprelay.domain.com'
}
Send-MailMessage #params
}
}
This code does not use the dot net classes. I hope it helps.
$images = #{
image1 = 'c:\temp\test.jpg'
image2 = 'C:\temp\test2.png'
}
$body = #'
<html>
<body>
<img src="cid:image1"><br>
<img src="cid:image2">
</body>
</html>
'#
$params = #{
InlineAttachments = $images
Attachments = 'C:\temp\attachment1.txt', 'C:\temp\attachment2.txt'
Body = $body
BodyAsHtml = $true
Subject = 'Test email'
From = 'username#gmail.com'
To = 'recipient#domain.com'
Cc = 'recipient2#domain.com', 'recipient3#domain.com'
SmtpServer = 'smtp.gmail.com'
Port = 587
Credential = (Get-Credential)
UseSsl = $true
}
Send-MailMessage #params
BTW all credit to David Wyatt who created the code. He seems to be a good resource on powershell script.

Resources