I wrote a script which detects a folder called Post within the subfolders of W:\SUS Test2 and moves CSV file which has "EMMain" in the filename. But the problem I have is the CSV files doesn't copy to the destination folder W:\SUS Test3 it copies it to W:\SUS Test2 folder.
$path = "W:\SUS Test2\"
$destination = "W:\SUS Test3\"
$fsw = New-Object System.IO.FileSystemWatcher $path -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'DirectoryName
}
$createdLTC = Register-ObjectEvent $fsw -EventName Created -Action {
$item = Get-Item $eventArgs.FullPath
if ($item.Name -like "Post") {
Get-ChildItem $item -filter "*EMMain*" | Copy-Item -dest $destination
}
}
You are trying to access the $destination variable in a portion of code that it is not available in. The script block in your Register-OjbectEvent will not have access to this variable. Try declaring $destination in the script block directly.
$createdLTC = Register-ObjectEvent $fsw -EventName Created -Action {
$destination = "W:\SUS Test3\"
$item = Get-Item $eventArgs.FullPath
If ($item.Name -like "Post") {
Get-ChildItem $item -filter "*EMMain*" | Copy-Item -dest $destination
}
}
Related
UPDATED:
Hi. Apologies if my question sounds vague. When I run both Scripts below together all the csv files from ES and LTC sub-folder end up in one folder instead of two folders. I have two separate scripts
to monitor two sub-folders LTC and ES and copy the files to the folders.
LTC Script:
$folder = 'C:\2014-15'
$destination = 'N:\Test'
$fsw = New-Object System.IO.FileSystemWatcher $folder -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'DirectoryName'
}
$created = Register-ObjectEvent $fsw -EventName Created -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "LTC") {
Copy-Item -Path $folder -Destination $destination
}
}
$renamed = Register-ObjectEvent $fsw -EventName Renamed -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "LTC") {
Copy-Item -Path $folder -Destination $destination
}
}
ES Script:
$folder = 'C:\2014-15'
$destination = 'N:\Test1'
$fsw = New-Object System.IO.FileSystemWatcher $folder -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'DirectoryName'
}
$created = Register-ObjectEvent $fsw -EventName Created -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "ES") {
Copy-Item "$item\*.csv" -Destination $destination
}
}
$created = Register-ObjectEvent $fsw -EventName Created -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "ES") {
Copy-Item "$item\*.csv" -Destination $destination
}
}
$folder = 'C:\2014-15'
$destination = 'N:\Test'
$destination1 = 'N:\Test1'
$fsw = New-Object System.IO.FileSystemWatcher $folder -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'DirectoryName'
}
$created = Register-ObjectEvent $fsw -EventName Created -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "LTC") {
Copy-Item -Path $folder -Destination $destination
}
}
$renamed = Register-ObjectEvent $fsw -EventName Renamed -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "LTC") {
Copy-Item -Path $folder -Destination $destination
}
}
$fsw = New-Object System.IO.FileSystemWatcher $folder -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'DirectoryName'
}
$created = Register-ObjectEvent $fsw -EventName Created -Action {
$item1 = Get-Item $eventArgs.FullPath
If ($item1.Name -ilike "ES") {
Copy-Item "$item1\*.csv" -Destination $destination1
}
}
$created = Register-ObjectEvent $fsw -EventName Created -Action {
$item1 = Get-Item $eventArgs.FullPath
If ($item1.Name -ilike "ES") {
Copy-Item "$item1\*.csv" -Destination $destination1
}
}
I have a folder called C:\2014-15 and new sub folders are created every month which contain csv files i.e
C:\2014-15\Month 1\LTC
C:\2014-15\Month 2\LTC
C:\2014-15\Month 3\LTC
How to write a script which would detect when a LTC sub folder is created for every month and move the csv files to N:\Test?
UPDATED:
$folder = 'C:\2014-15'
$filter = '*.*'
$destination = 'N:Test\'
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host
Copy-Item -Path $path -Destination $destination
}
The error I get is:
Register-ObjectEvent : Cannot subscribe to event. A subscriber with source identifier 'FileCreated' already exists.
At line:8 char:34
+ $onCreated = Register-ObjectEvent <<<< $fsw Created -SourceIdentifier FileCreated -Action {
+ CategoryInfo : InvalidArgument: (System.IO.FileSystemWatcher:FileSystemWatcher) [Register-ObjectEvent], ArgumentException
+ FullyQualifiedErrorId : SUBSCRIBER_EXISTS,Microsoft.PowerShell.Commands.RegisterObjectEventCommand
Credit to this post.
Notify on a different event: [IO.NotifyFilters]'DirectoryName'. This removes the need for $filter since filename events are not relevant.
You should also notify for renamed folders and created folders, making your final script something like this
$folder = 'C:\2014-15'
$destination = 'N:\Test'
$fsw = New-Object System.IO.FileSystemWatcher $folder -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'DirectoryName'
}
$created = Register-ObjectEvent $fsw -EventName Created -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "LTC") {
# do stuff:
Copy-Item -Path $folder -Destination $destination
}
}
$renamed = Register-ObjectEvent $fsw -EventName Renamed -Action {
$item = Get-Item $eventArgs.FullPath
If ($item.Name -ilike "LTC") {
# do stuff:
Copy-Item -Path $folder -Destination $destination
}
}
From the same console you can unregister since that console knows about $created and $renamed:
Unregister-Event $created.Id
Unregister-Event $renamed.Id
Otherwise you need to use this which is bit uglier:
Unregister-Event -SourceIdentifier Created -Force
Unregister-Event -SourceIdentifier Renamed -Force
Also, thanks for the question. I didn't realise these event captures existed in powershell until now...
Note: Running PowerShell v3
I've got a directory setup that is currently:
\ftproot\001\converted
\ftproot\001\inbound
\ftproot\001\pdf
\ftproot\002\converted
\ftproot\002\inbound
\ftproot\002\pdf
\ftproot\xxx\converted
\ftproot\xxx\inbound
\ftproot\xxx\pdf
Each FTP user is mapped to an inbound directory. The structure can be changed if this makes the solution easier
\ftproot\converted\001
\ftproot\converted\002
\ftproot\converted\xxx
\ftproot\inbound\001
\ftproot\inbound\002
\ftproot\inbound\xxx
\ftproot\pdf\001
\ftproot\pdf\002
\ftproot\pdf\xxx
I need to monitor each inbound directory for TIFF files and pickup new FTP users and inbound directories as they are added (following the same structure), so I'm not looking to modify the script for each new user.
The script is currently like:
$fileDirectory = "\ftproot";
$folderMatchString = "^[0-9]{3}$";
$inboundDirectory = "inbound";
$filter = "*.tif";
$directories = dir -Directory $fileDirectory | Where-Object {$_.Name -match $folderMatchString}
foreach ($directory in $directories) {
$sourcePath = "$fileDirectory\$directory\$inboundDirectory"
if(Test-Path -Path $sourcePath -pathType container ) {
// Problem is here //
$fsw = New-Object IO.FileSystemWatcher $sourcePath, $filter -Property #{
IncludeSubdirectories = $false
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
}
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp"
}
I'm wrapping the New-Object IO.FileSystemWatcher in a loop so in the case of the above example, only the last directory will be monitored.
Is it possible to create an array or list or similar of IO.FileSystemWatcher? And if so, how can I code the Register-ObjectEvent for each instance? There will be over a hundred directories to monitor in the end (and slow increasing) but the same action applies to all inbound folders.
Or is there a better solution I should investigate?
The process is the same for each FTP user, the files need to say within directories that can be linked back to the user. The inbound directory will be monitored for uploaded TIFF files, when a file is detected a multi page TIFF is split into individual files and moved into the converted directory, when a new file is detected in converted another action is performed on the TIFF file, then it is converted to PDF and moved to the PDF folder.
Thank you
Solution
$result = #($directoriesOfInterest | ? { Test-Path -Path $_ } | % {
$dir = $_;
$fsw = New-Object IO.FileSystemWatcher $dir, $filter -Property #{
IncludeSubdirectories = $false
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
};
$oc = Register-ObjectEvent $fsw Created -Action {
$path = $Event.SourceEventArgs.FullPath;
$name = $Event.SourceEventArgs.Name;
$changeType = $Event.SourceEventArgs.ChangeType;
$timeStamp = $Event.TimeGenerated;
Write-Host "The file '$name' was $changeType at $timeStamp";
};
new-object PSObject -Property #{ Watcher = $fsw; OnCreated = $oc };
});
Is it possible to create an array or list or similar of IO.FileSystemWatcher?
Yes. Making use of a pipeline would be something like:
$fsws = $directoriesOfInterest | ? { Test-Path -Path $_ } | % {
new-object IO.FileSystemWatcher …
}
and $fsws will be an array, if there is more than one watcher created (it will be a waster if there is only one, $null if there are none). To always get an array put the pipeline in #(…):
$fsws = #($directoriesOfInterest | ? { Test-Path -Path $_ } | % {
new-object IO.FileSystemWatcher …
})
if so, how can I code the Register-ObjectEvent for each instance?
Put the object registration in the same loop, and return both the watcher and the event registration:
$result = #($directoriesOfInterest | ? { Test-Path -Path $_ } | % {
# $_ may have a different value in code in inner pipelines, so give it a
# different name.
$dir = $_;
$fsw = new-object IO.FileSystemWatcher $dir, …;
$oc = Register-ObjectEvent $fsw Created …;
new-object PSObject -props #{ Watcher = $fsw; OnCreated = $oc };
})
and $result will be an array of objects will those two properties.
Note the -Action code passed to Register-ObjectEvent can reference $fsw and $dir and thus know which watcher has fired its event.
I am attempting to write a powershell script that will look at a file until it gets modified and then email the change that happened. So far I have this code + the code that will send the email using Net.Mail.SmtpClient
$DOCDIR = [Environment]::GetFolderPath("MyDocuments")
$TARGETDIR = "$DOCDIR\MatchedLog"
if(!(Test-Path -Path $TARGETDIR )){
New-Item -ItemType directory -Path $TARGETDIR
}
$FILE = 'matched.txt'
$FSW = New-Object IO.FileSystemWatcher $TARGETDIR, $FILE - Property#{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FirstName, LastWrite'}
Register-ObjectEvent $FSW Changed -SourceIdentifier FileChanged -Action {
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
}
The error I get is:
Register-ObjectEvent : Cannot bind argument to parameter 'InputObject' because it is null.
I am not sure exactly why this is happening
This looks like it might be a typo, but [IO.NotifyFilters] doesn't have the definition FirstName. You probably mean FileName
http://msdn.microsoft.com/en-us/library/system.io.notifyfilters.aspx
This works fine, it prints the change twice in a row for some reason. I saw many people having the same problem online but I am still trying to find the problem. I also need to get the line that has changed from "matched.txt" and print that instead of "Changed: /path/to/file/matched.txt"
$DOCDIR = [Environment]::GetFolderPath("MyDocuments")
$TARGETDIR = "$DOCDIR\MatchedLog"
if(!(Test-Path -Path $TARGETDIR )){
New-Item -ItemType directory -Path $TARGETDIR
}
$FILE = 'matched.txt'
$FSW = New-Object System.IO.FileSystemWatcher
$FSW.Path = $TARGETDIR
$FSW.IncludeSubdirectories = $false
$changed = Register-ObjectEvent $FSW "Changed" -Action{
write-host "Changed: $($eventArgs.FullPath)"
}
Hi I have installed the PowerShellPack and I am using the FileSystem watcher module,but the problem when I safe the file as a script and execute it.
The problem is that if you execute the script it runs and the monitors the folder for changes but once the script stops (gets to the end of execution) the folder is no longer monitored.
I have tried to place everything in a do while loop but that does not seem to work.
PowerShellPack Install
Import-Module -Name FileSystem
$TempCopyFolder = "c:\test"
$PatchStorage = "c:\testpatch"
Start-FileSystemWatcher -File $TempCopyFolder -Do {
$SearchPath = $File
$PatchesPath = $PatchStorage
$NewFolderFullPath = "$($eventArgs.FullPath)"
$NewFolderName = "$($eventArgs.Name)"
$PathToCheck = "$PatchesPath\$NewFolderName"
#Check if it is a filde or folder
switch ($ObjectType)
{{((Test-Path $NewFolderFullPath -PathType Container) -eq $true)}{$ObjectType = 1;break}
{((Test-Path $NewFolderFullPath -PathType Leaf) -eq $true)}{$ObjectType = 2;break}}
# Its a folder so lets check if we have a folder in the $PatchesPath already
IF($ObjectType -eq 1){
IF(!(Test-Path -LiteralPath $PathToCheck -EA 0))
{
sleep -Seconds 3
#Make a new directory where we store the patches
New-item -Path $PatchesPath -Name $NewFolderName -ItemType directory
#Make a folde in the folder for TC1
$TcFolder=$NewFolderName + '_1'
$NewPatchesPath = "$PatchesPath\$NewFolderName"
New-item -path $NewPatchesPath -Name $TcFolder -ItemType directory
$CopySrc = $NewFolderFullPath
$CopyDes = "$NewPatchesPath\$TcFolder"
}
# There is a folder there so lets get the next number
Else{
$HighNumber = Get-ChildItem -Path $PathToCheck | select -Last 1
#Core_SpanishLoginAttemptsConfiguration_Patch_03
$NewNumber = [int](Select-String -InputObject $HighNumber.Name -Pattern "(\d\d|\d)" | % { $_.Matches } | % { $_.Value } )+1
$TcFolder= $NewFolderName + '_' + $NewNumber
$NewPatchesPath = "$PatchesPath\$NewFolderName"
$CopySrc = $NewFolderFullPath
$CopyDes = "$NewPatchesPath\$TcFolder"
}
#Lets copy the files to their new home now that we know where every thing goes
$robocopy = "robocopy.exe"
$arguments = '''' + $CopySrc + '''' +' '+ ''''+ $CopyDes + '''' + '/E'
Invoke-Expression -Command "$robocopy $arguments"
Do {sleep -Seconds 1;$p = Get-Process "robo*" -ErrorAction SilentlyContinue}
While($p -ne $null)
#Now lets check every thing copyed
$RefObj = Get-ChildItem -LiteralPath $NewFolderFullPath -Recurse
$DifObj = Get-ChildItem -LiteralPath $CopyDes -Recurse
IF(Compare-Object -ReferenceObject $RefObj -DifferenceObject $DifObj)
{write-host "Fail"}
Else{# Now lets delete the source
Remove-Item -LiteralPath $CopySrc -Force -Recurse
}
}}
You don't need add-on modules or WMI for this. Just set of the FileSystemWatcher yourself and register an event. Sure, it's a bit more code, but at least you know what's going on. :)
$watcher = new-object System.IO.FileSystemWatcher
$watcher.Path = 'c:\logs'
$watcher.Filter = '*.log' # whatever you need
$watcher.IncludeSubDirectories = $true # if needed
$watcher.EnableRaisingEvents = $true
Register-ObjectEvent $watcher -EventName Changed -SourceIdentifier 'Watcher' -Action { param($sender, $eventArgs)
<process event here>
}
When done:
Unregister-Event -SourceIdentifier 'Watcher'
This is something you probably need: Monitoring file creation using WMI and PowerEvents module
PowerEvents Module isn't mandatory if you know how to create Permanent Events in WMI. For more information on that, check my eBook on WQL via PowerShell: http://www.ravichaganti.com/blog/?page_id=2134