FileWatcher sends multiple emails with Net.Mail.MailMessage - powershell

I'm using a FileWatcher script and everything seems to be working as far as monitoring. The problem is that when a file changes, it's set to send me an email. It emails out fine but always sends 2 emails or if i'm sending to a text, 2 texts. What's going on here? Here's my code:
$fswAuctions = New-Object IO.FileSystemWatcher $auctions, $filter -Property #{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fswAuctions Changed -SourceIdentifier FilesChanged4 -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$SMTPBody = "The file '$name' was $changeType at $timeStamp"
Send-ToEmail -email "myemail#whatever.com" -strBody $SMTPBody -strSubject "Auctions Module"
Write-Host "The file '$name' was $changeType at $timeStamp" -fore white
}
function Send-ToEmail([string]$email, [string]$strBody, [string]$strSubject){
$message = new-object Net.Mail.MailMessage
$message.From = "do_not_reply#site.com"
$message.To.Add($email)
$message.Subject = $strSubject
$message.Body = $strBody
$smtp = new-object Net.Mail.SmtpClient("127.0.0.1", "25")
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
$smtp.send($message)
}

Related

Run Scripts in Powershell ISE from batch file

I am executing my batch file which opens the Powershell ISE and loads the script but does nothing... I would still need to run manually. Am I missing something here?
BatchFile to call Powershell:
Powershell_ise.exe C:\Users\Desktop\myscript.ps1
That the code am using to monitor the file changes in a folder and to email:
Function Register-Watcher {
param ($folder)
$filter = "logfile.txt" #all files
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $false
EnableRaisingEvents = $true
}
$changeAction = [scriptblock]::Create('
# This is the code which will be executed every time a file change is detected
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file $name was $changeType at $timeStamp"
Send-email
')
Register-ObjectEvent $Watcher "Changed" -Action $changeAction
}
Function Send-email{
$SMTPServer = "smtp.gmail.com"
$SMTPPort = "587"
$Username = "*****#gmail.com"
$Password = "*******"
$to = "*****#gmail.com"
$subject = "Email Subject"
$body = "Insert body text here"
$attachment = "C:\Users\Desktop\AccountMapping.sdl"
$message = New-Object System.Net.Mail.MailMessage
$message.subject = $subject
$message.body = $body
$message.to.add($to)
$message.from = $username
$message.attachments.add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password);
$smtp.send($message)
Write-Host "Mail Sent"
}
Register-Watcher "C:\Users\Desktop"

Split strings from registered event output in PowerShell

I have just started working with IO.FIleSystemWatcher. My current code works and alerts me of created files in the desired location, however I want to pipe some of the variables out and split the strings. I cannot get the split portion to work.
Functional Code:
$folder = 'D:\Output'
$filter = '*.jpg'
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Out-File D:\Output\scans\$name.txt
}
$name will always be formatted like so 'file.name.fn_xxx.jpg' and I want to use split to pull 'file' from $name, for example:
$name.split('.')[0]
However, this does nothing as far as I can tell. For instance I can output a file with $name as the filename, but if I try to split it first nothing outputs.
Non-Functional Code:
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
$name = $name.split('.')[0]
Out-File D:\Output\scans\$name.txt
}
This is a bit over my head so any advice or suggestion is appreciated.
Thanks
I ended up working it out by simply using another variable.
$folder = 'D:\Output'
$filter = '*.jpg'
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
Write-Host "$name"
$x = $name.split(".")[0]
Out-File D:\Output\scans\$x.txt
I am not sure why this works, but it does. If anyone knows why please comment!

$Event.SourceEventArgs.<attribute> is returning a null or empty object

I have a FileSystemWatcher program that whenever an event is raised it sends an email notifying me of where the change happened.
However, $Event.SourceEventArgs.FullPath returns empty, and the other attributes returns $null.
Relevant code:
Function Watch{
$global:FileChanged = $false
$folder = "\\foo\boo\here\is\folder"
$filter = "*this is the filter*"
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $true
EnableRaisingEvents = $true
}
# Start-Sleep -Seconds 1
Register-ObjectEvent $watcher "Changed" -Action {$global:FileChanged = $true} > $null
# Register-ObjectEvent $watcher "Created" -Action {$global:FileChanged = $true} > $null
# Register-ObjectEvent $watcher "Deleted" -Action {$global:FileChanged = $true} > $null
# $watcher.EnableRaisingEvents = $true
while($true){
while($global:FileChanged -eq $false){
Start-Sleep -Milliseconds 250
}
$global:FileChanged = $false
$paths = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.FileName
$changetype = $Event.SourceEventArgs.ChangeType
$TimeChanged = $Event.TimeGenerated
RunScript $paths, $name, $changetype, $TimeChanged
}
}
Function RunScript
{
param($paths, $name, $changetype, $TimeChanged)
Write-Host "This should work $paths $name $changetype $TimeChanged"
$From = "email"
$ToAddress = "email"
$MessageSubject = "Form Submitted by $paths"
$MessageBody = "File Path: $Event.SourceEventArgs.FullPath
Name: $name
Change Type?: $changetype
Time Changed: $timechanged"
$SendingServer = "999.999.999.9.9"
$SMTPMessage = New-Object System.Net.Mail.MailMessage $From, $ToAddress,
$MessageSubject, $MessageBody
$SMTPClient = New-Object System.Net.Mail.SMTPClient $SendingServer
$SMTPClient.Send($SMTPMessage)
}
Watcher
Updated example. Note: I haven't tested this at all so be aware there are likely bugs. I've added some comments and a couple of different approaches for other sections of the code.
Function Watch {
$folder = "\\foo\boo\here\is\folder"
$filter = "*this is the filter*"
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $true
EnableRaisingEvents = $true
}
# Start-Sleep -Seconds 1
Register-ObjectEvent $watcher "Changed" > $null
# Register-ObjectEvent $watcher "Created" > $null
# Register-ObjectEvent $watcher "Deleted" > $null
# $watcher.EnableRaisingEvents = $true
while($true){
Wait-Event | Get-Event | ForEach-Object {
# $paths = $_.SourceEventArgs.FullPath
# $name = $_.SourceEventArgs.FileName
# $changetype = $_.SourceEventArgs.ChangeType
# $TimeChanged = $_.TimeGenerated
# If you comma-delimit this list you pass all of the arguments into "RunScript".
# Either name the parameters or make them positional.
# Positional:
# RunScript $paths $name $changetype $TimeChanged
# Named:
# RunScript -Paths $paths -Name $name -ChangeType $changetype -TimeChanged $TimeChanged
# Or use Splatting:
$params = #{
Paths = $_.SourceEventArgs.FullPath
Name = $_.SourceEventArgs.FileName
ChangeType = $_.SourceEventArgs.ChangeType
TimeChanged = $_.TimeGenerated
}
RunScript #params
}
}
}
Function RunScript {
param($paths, $name, $changetype, $TimeChanged)
Write-Host "This should work $paths $name $changetype $TimeChanged"
# $From = "email"
# $ToAddress = "email"
# $MessageSubject = "Form Submitted by $paths"
# $MessageBody = "File Path: $Event.SourceEventArgs.FullPath
# Name: $name
# Change Type?: $changetype
# Time Changed: $timechanged"
# $SendingServer = "999.999.999.9.9"
# $SMTPMessage = New-Object System.Net.Mail.MailMessage $From, $ToAddress,
# $MessageSubject, $MessageBody
# $SMTPClient = New-Object System.Net.Mail.SMTPClient $SendingServer
# $SMTPClient.Send($SMTPMessage)
# Is there a reason you're not using Send-MailMessage?
# Splatting again :)
# The body of the email isn't going to be very pretty, but it's a start.
$params = #{
From = "email"
To = "email"
Subject = "Form Submitted by $paths"
Body = "File Path: $paths
Name: $name
Change Type?: $changetype
Time Changed: $timechanged"
"
SmtpServer = "999.999.999.9.9"
}
Send-MailMessage #params
}
Now you get a caveat. The FileSystemWatcher is useful, but because of how Windows works you may well receive two event notifications for a single change (that's a deep Windows problem as opposed to a code problem). Try it and see.
Chris
Edit: Forgot to remove the action parameter. It's gone now.

PowerShell function result wont be send via Email

I'm using this PowerShell function to check on a folder.
it works fine and when adding, changing and deleting a file happens on the folder; it shows the log message on the host screen.
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher | Get-Member -Type Properties,Event
$FileSystemWatcher.Path = "C:\Users\ali.shariaty\Desktop\test"
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action {
$Object = "{0} was {1} at {2}" -f $Event.SourceEventArgs.FullPath,
$Event.SourceEventArgs.ChangeType,
$Event.TimeGenerated
$WriteHostParams = #{
ForegroundColor = 'Green'
BackgroundColor = 'Black'
Object = $Object
}
Write-Host #WriteHostParams
}
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Changed -Action {
$Object = "{0} was {1} at {2}" -f $Event.SourceEventArgs.FullPath,
$Event.SourceEventArgs.ChangeType,
$Event.TimeGenerated
$WriteHostParams = #{
ForegroundColor = 'Yellow'
BackgroundColor = 'Black'
Object = $Object
}
Write-Host #WriteHostParams
}
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Deleted -Action {
$Object = "{0} was {1} at {2}" -f $Event.SourceEventArgs.FullPath,
$Event.SourceEventArgs.ChangeType,
$Event.TimeGenerated
$WriteHostParams = #{
ForegroundColor = 'Red'
BackgroundColor = 'Black'
Object = $Object
}
Write-Host #WriteHostParams
}
My issue is when I add these lines to my code to send me the result by email, the body of my emails are empty and do not contain the log message.
$mailtxt = $WriteHostParams
$mailSmtpServer = "mail.domain.com";
$mailFrom = "ali.shariaty#domain.com";
$mailTo = "ali.shariaty#domain.com";
$mailSubject = "Folder Change"
$mailbody = $mailtxt
$mail = New-Object Net.Mail.SmtpClient($mailSmtpServer);
$msg = new-object Net.Mail.MailMessage;
$msg.IsBodyHtml = 1;
$msg.To.Add($mailTo);
$msg.From = $mailFrom;
$msg.Subject = $mailSubject;
$msg.Body = $mailbody;
$mail.Send($msg);
Can someone help and tell me what I am doing wrong?
Thank you.
Have you tried setting the body to just the message? i.e.
$mailtext = $WriteHostParams.Object
Currently you are trying to set the body of the email to a hashtable, which I would expect would just set it to "System.Collections.Hashtable" after it was casted to a string

Powershell + Robocopy Auto backup executing multiple times

I've put together this script to detect file changes in a directory, so that whenever the changes take effect the file(s) changed will get backed up right away.
I have also set up an email notification.
The backup works. I can see whenever a file changes it gets copied over to the desired destination, however I am receiving three emails and the robocopy log shows no changes, which leads me to think it's being written three times each time a file changes. So the last time it gets written there will of course be no changes.
Below you can see the code, hope you can help me figure out what's going on.
#The Script
$folder = 'C:\_Using Last Template Approach\' # Enter the root path you want to monitor.
$filter = '' # You can enter a wildcard filter here.
# In the following line, you can change 'IncludeSubdirectories to $false if required.
$fsw = New-Object IO.FileSystemWatcher $folder -Property #{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Changed -SourceIdentifier AutoBackUp -Action {
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$datestamp = get-date -uformat "%Y-%m-%d#%H-%M-%S"
$Computer = get-content env:computername
$Body = "Documents Folders have been backed up"
robocopy "C:\_Using Last Template Approach" G:\BackUp\ /v /mir /xo /log:"c:\RobocopyLog.txt"
Send-MailMessage -To "me#me.com" -From "jdoe#me.com" -Subject $Body -SmtpServer "smtp-mm.me.com" -Body " "
# To stop the monitoring, run the following commands (e.g using PowerShell ISE:
# Unregister-Event AutoBackUp
}
i do not change your monitor script just change send mail and copy with copy-item powershell command
$folder = 'c:\sites' # Enter the root path you want to monitor.
$filter = '*.*' # You can enter a wildcard filter here.
# In the following line, you can change 'IncludeSubdirectories to $true if required.
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp" -fore white
Out-File -FilePath c:\sites\filechange\outlog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"
$username=”gmailaccount”
$password=”password”
$smtpServer = “smtp.gmail.com”
$msg = new-object Net.Mail.MailMessage
$smtp = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$smtp.EnableSsl = $true
$smtp.Credentials = New-Object System.Net.NetworkCredential( $username, $password )
$msg.From = "gmail"
$msg.To.Add(“mail should check notify”)
$msg.Body=”Please See archive for notification”
$msg.Subject = “backup information”
$files=Get-ChildItem “c:\sites\filechange\”
Foreach($file in $files)
{
Write-Host “Attaching File :- ” $file
$attachment = New-Object System.Net.Mail.Attachment –ArgumentList S:\sites\filechange\$file
$msg.Attachments.Add($attachment)
}
$smtp.Send($msg)
$attachment.Dispose();
$msg.Dispose();
Copy-Item c:\sites\$name C:\a\$name }
i check this script work for me if change file content of file first email log file then copy them to destination c:\a\ also you and that file changed to attachment of mail