Powershell + Robocopy Auto backup executing multiple times - powershell

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

Related

Script for sending e-mail

I found one script online, which does quite simple work - sends e-mail to the specified address after the trigger is hit.
In the example below script should scan the path which I stated for the trigger which is: #task, then it expected that it should send e-mail with the text after #td.
It should be correct, but when I run it nothing happens - what I'm doing wrong?
I've got the following message in powershell:
enter image description here
# Unregister-Event FileCreated
Unregister-Event FileChanged
# Email-settings
$loginuser = 'xxx#gmail.com'
$loginpassword = 'password;'
$smtpserver = 'smtp.gmail.com'
$smtpport = 587
$sendfrom = 'xxx#gmail.com'
$sendto = 'add.task.9270372.1523940684#todoist.net'
# Folder-settings
$folder = 'D:\Google Drive\Other\Nirvana' # 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' }
# Trigger-settings
$trigger = '#task'
$lookfor = '#td'
$replaceto = '#intasklist'
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$fileContent = (Get-Content $folder$name)
# Write-Host "The file '$name' was $changeType at $timeStamp" -fore green
if ($fileContent -match $trigger) {
$fileContent | Select-String -Pattern ".*$($lookfor)" -AllMatches | ForEach-Object { $_.Matches } | ForEach-Object { $secpasswd = ConvertTo-SecureString $loginpassword -AsPlainText -Force; $cred = New-Object System.Management.Automation.PSCredential ($loginuser, $secpasswd); Send-MailMessage -To $sendto -From $sendfrom -Subject $_.Value -Body $name -SmtpServer $smtpserver -Port $smtpport -Credential $cred -UseSsl
$fileContent | ForEach-Object { $_ -replace $lookfor, $replaceto -replace " $($trigger)", '' -replace $trigger, '' } | Set-Content $folder$name }
}}
# To stop the monitoring, run the following commands:
# Unregister-Event FileChanged

FileSystemWatcher not firing events till PowerShell closes

I have a script (below) that watches a folder that the .ps1 script sits in.
When a file is created it fires a .bat file to do a job.
Initially it would run and close immediately.
So I added '''Start-Sleep -s 50'''
It works but it only triggers the .bat launch when the PowerShell window closes.
(As I don't know how long it will be till a file turns up in the folder, this is kind of useless).
Ideally I could do with the .bat file launching as soon as the new file is created, which in turn then closes the PowerShell window
$configFilePath = $PSScriptRoot
$filter = '*.*'
$fsw = New-Object IO.FileSystemWatcher $configFilePath, $filter -Property #{IncludeSubdirectories = $true;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 -FilePath c:\temp\log\Filelog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"
Set-Location "$PSScriptRoot"
Start-Process "$PSScriptRoot\PS_Run.bat"
}
Start-Sleep -s 50
You can replace Start-Sleep with:
Wait-Event -SourceIdentifier FileCreated
Then you need to add an exit command to your watcher like this:
Start-Process "$PSScriptRoot\PS_Run.bat"
exit
}
Since you cannot exit the console from the filewatcher, you can do this instead:
$configFilePath = $PSScriptRoot
$filter = '*.*'
$fsw = New-Object IO.FileSystemWatcher $configFilePath, $filter -Property #{IncludeSubdirectories = $true;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 -FilePath c:\temp\log\Filelog.txt -Append -InputObject "The file '$name' was $changeType at $timeStamp"
Set-Location "$PSScriptRoot"
Start-Process "$PSScriptRoot\PS_Run.bat"
}
Wait-Event -SourceIdentifier FileCreated -Timeout 50 # or no of seconds before file shows up.
When run as a scheduled task, this will execute the bat file as soon as a new file is created and close the console when the timeout is reached.

Powershell Change Watcher only Triggers on directories

I am building a file watching script in powershell. I have been manipulating code from: https://gallery.technet.microsoft.com/scriptcenter/Powershell-FileSystemWatche-dfd7084b
Everything seemed to work fine, but when I did some actual testing I noticed the change event was only triggering on the parent directory and not the actual file itself. Below is the code I have poached and updated:
$folder = 'C:\extended_attributes\testing\DesignerVistaReorganize' # 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 = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
# Here, all three events are registerd. You need only subscribe to events that you need:
Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$filePath = -join($folder,"\",$name) | Out-String
Write-Host "The file '$filePath' was $changeType at $timeStamp" -fore green
Out-File -FilePath C:\extended_attributes\testing\outlog.txt -Append -InputObject "The file '$filePath' was $changeType at $timeStamp"}
Register-ObjectEvent $fsw Deleted -SourceIdentifier FileDeleted -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$filePath = -join($folder,"\",$name) | Out-String
Write-Host "The file '$filePath' was $changeType at $timeStamp" -fore red
Out-File -FilePath C:\extended_attributes\testing\outlog.txt -Append -InputObject "The file '$filePath' was $changeType at $timeStamp"}
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$filePath = -join($folder,"\",$name) | Out-String
Write-Host "The file '$filePath' was $changeType at $timeStamp" -fore white
Out-File -FilePath c:\scripts\filechange\outlog.txt -Append -InputObject "The file '$filePath' was $changeType at $timeStamp"}
The delete and create events are working as one would expect (as shown below):
File Creation:
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Cart_Warnings\newFile.txt' Created at 10/01/2018 14:55:35
File Change:
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Cart_Warnings'
was Changed at 10/01/2018 15:01:18
File Deletion:
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Cart_Warnings\newFile.txt' Deleted at 10/01/2018 14:56:47
Another thing I noticed is that the change event is only firing on the first file change under the root directory. The other two events fire whenever a file is created or deleted. Has anyone run into this issue before and if so can you please provide some insight on a work around?
Work Around (not a valid answer though)
I have tried a bunch of differnt things trying to make this event fire consistently, and only one seems to work. I have two scripts for file change events. They are pretty much identical with the exception that they call each other after the event has completed. The key is not ensure that you kill the watcher by unregistering the event before the second script is called.
Script 1
$folder = 'C:\extended_attributes\testing\DesignerVistaReorganize' # 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 = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action {
echo "Script 1"
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$filePath = -join($folder,"\",$name) | Out-String
Unregister-Event FileChanged
Write-Host "The file '$filePath' was $changeType at $timeStamp" -fore white
Out-File -FilePath C:\extended_attributes\testing\outlog.txt -Append -InputObject "The file '$filePath' was $changeType at $timeStamp"
.\change_watcher_2.ps1
}
Script 2
$folder = 'C:\extended_attributes\testing\DesignerVistaReorganize' # 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 = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged -Action {
echo "Script 2"
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
$filePath = -join($folder,"\",$name) | Out-String
Unregister-Event FileChanged
Write-Host "The file '$filePath' was $changeType at $timeStamp" -fore white
Out-File -FilePath C:\extended_attributes\testing\outlog.txt -Append -InputObject "The file '$filePath' was $changeType at $timeStamp"
.\change_watcher_1.ps1
}
output
PS C:\extended_attributes\testing> C:\extended_attributes\testing\change_watcher_1.ps1
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
2 FileChanged NotStarted False ...
PS C:\extended_attributes\testing> The file 'C:\extended_attributes\testing\DesignerVistaReorganize\BusinessPrinting
' was Changed at 10/02/2018 10:46:43
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Editor_Warnings
' was Changed at 10/02/2018 10:47:09
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Mobile\Mobile_Control_Panel_2015_05_14.dvf
' was Changed at 10/02/2018 10:49:50
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Mobile
' was Changed at 10/02/2018 10:49:58
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Mobile\Gradients_Panels_Colors_Menus_2015_03_01.dvf
' was Changed at 10/02/2018 10:51:49
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Mobile\Tablet_Editor_2015_03_31.dvf
' was Changed at 10/02/2018 10:52:46
The file 'C:\extended_attributes\testing\DesignerVistaReorganize\Mobile
' was Changed at 10/02/2018 10:52:57
I would really like a better solution than this as I can foresee many problems arising from this approach.
I found a much better solution than I had posted in the update of my original questions. If you use the attribute to EnableRaisingEvents as shown below. The event will fire everytime a change has been made to the file system:
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = 'C:\extended_attributes\testing\DesignerVistaReorganize'
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
$changed = Register-ObjectEvent $watcher "Changed" -Action {
write-host "Changed: $($eventArgs.FullPath)"
$creation_time = gi -Path $eventArgs.FullPath | get-itemproperty | select -ExpandProperty CreationTime | Get-date -Format s
$file_extension = gi -Path $eventArgs.FullPath | get-itemproperty | select -ExpandProperty Extension
$file_base_name = gi -Path $eventArgs.FullPath | get-itemproperty | select -ExpandProperty BaseName
$last_access_time = gi -Path $eventArgs.FullPath | get-itemproperty | select -ExpandProperty LastAccessTime | Get-date -Format s
$last_write_time = gi -Path $eventArgs.FullPath | get-itemproperty | select -ExpandProperty LastWriteTime | Get-date -Format s
Write-Host "Creation time: $($creation_time)"
Write-Host "ex: $($file_extension)"
Write-Host "Name: $($file_base_name)"
Write-Host "access: $($last_access_time)"
Write-Host "write: $($last_write_time)"
$object = New-Object System.Object
$object | Add-Member -type NoteProperty –Name Extension –Value $file_extension
$object | Add-Member -type NoteProperty –Name BaseName –Value $file_base_name
$object | Add-Member -type NoteProperty –Name Createtime –Value $creation_time
$object | Add-Member -type NoteProperty –Name Accesstime –Value $last_write_time
$object | Add-Member -type NoteProperty –Name Writetime –Value $last_access_time
Write-Host "After Object"
# Load the module
Import-Module Mdbc
# Connect the new collection test.test
Connect-Mdbc . test test -NewCollection
# add the objects to the collection
$object | Add-MdbcData
# Get all data as custom objects and show them in a table
Get-MdbcData -As PS | Format-Table -AutoSize | Out-String
}

Scan specific sub-folder of every folder in powershell

I have this script which is working fine
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\folder_to_scan\"
$watcher.Filter = "*.nrrd"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
$action =
{
$path = $Event.SourceEventArgs.FullPath
Write-Host "The file '$path' was $changeType at '$(Get-Date)'" -fore green
}
Register-ObjectEvent $watcher "Created" -Action $action
while ($true) {sleep 3600}
But in my C:\folder_to_scan\ I have a lot of sub-directories like 00123, 00245, 56002 ... And inside each of them I have \THE_DIRECTORY_TO_SCAN
So I tried this $watcher.Path = "C:\folder_to_scan\*\THE_DIRECTORY_TO_SCAN\" and $watcher.Path = "C:\folder_to_scan\[0-9]*\THE_DIRECTORY_TO_SCAN\"
But this is not working. Is it possible to use wildcard in this situation?
If not, how to use multi path with FileSystemWatcher?
Because I figured out that we can use this
Resolve-Path "C:\folder_to_scan\*\THE_DIRECTORY_TO_SCAN\" | Select -ExpandProperty Path
I'm not familiar with FileSystemWatcher so I am assuming you just need to feed in the folder paths to $watcher.Path
I'm also assuming your code works already.
try using Get-ChildItem and use a for loop:
$watcher = New-Object System.IO.FileSystemWatcher
Get-ChildItem "C:\folder_to_scan\" -Recurse | ? { $_.PSIsContainer -and $_.Name.EndsWith("THE_DIRECTORY_TO_SCAN")}| %{
$watcher.Path = $_.FullName #change this
$watcher.Filter = "*.nrrd"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
}
$action =
{
$path = $Event.SourceEventArgs.FullPath
Write-Host "The file '$path' was $changeType at '$(Get-Date)'" -fore green
}
Register-ObjectEvent $watcher "Created" -Action $action
while ($true) {sleep 3600}
Ok so to clarify what i was talking about earlier. You are only repeating your wait-function. To show you what i mean :
echo "This would be your code running."
while ($true) {sleep -second 3}
This would print the sentence once and then keep waiting for eternity for 3 seconds each time $true is true.
What you need to do is :
do{
echo "This would be your code running."
sleep -seconds 3
} while($true)
This will print the sentence every 3 seconds.
Or in your case, run your watcher every 3 seconds.
I didn't find a perfect solution so I did this
if ( $path -like '*\THE_DIRECTORY_TO_SCAN\*' )
{ Write-Host "File created in \THE_DIRECTORY_TO_SCAN" -fore green }
else
{ Write-Host "File created NOT in \THE_DIRECTORY_TO_SCAN" -fore red }

Monitoring files for changes, but only changes to the content (not last modified date)?

I have tinkered with a small script that monitors a folder and alerts if there is a change with that folder. Here is what I have so far:
$folder = 'folder\to\monitor'
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}
Register-ObjectEvent $fsw Changed -SourceIdentifier FileChanged1 -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 = " $path on $Computer was $changeType at $timeStamp"
$PIECES=$path.split("\")
$newfolder=$PIECES[-2]
Out-File -FilePath c:\Scripts\config_changes.txt -Append -InputObject " $path on $Computer was $changeType at $timeStamp"
Send-MailMessage -To "email#domain.com" -From "email#domain.com" -Subject $Body -SmtpServer "192.168.#.##" -Body " "
#Copy-Item $path "c:\scripts\versions\$newfolder"
#Rename-Item "c:\Scripts\Versions\$newfolder\web.config" "web.config-$datestamp"
#Remove-Item -path "c:\Scripts\Versions\$newfolder\web.config" -force}
# To stop the monitoring, run the following commands:
# Unregister-Event FileChanged1
However, I am wanting to make the "criteria" for a file change a little more specific. From what research I've done, the FileSystemWatcher.Notify filter limits me to File Name, Last Write, etc. What I would like to do is check to see if any changes have been made to the content of the file. If none of the content has changed, then I don't want it to alert.
The file constantly gets overwritten, even if there are no changes, so the modified date continues to change even if there is no content change.