powershellfile-watcher

How to detect Folder change (renaming in particular) inside a folder using Powershell file watcher


I am using powershell to detect and record a folder change (created, renamed, deleted etc) inside a folder. This parent folder receives subfolders from another location in format TEMP_XYZ. Once this folder is copied to this parent folder, the process automatically renames it to XYZ (Removed suffix TEMP_)

This change (rename) had to be detected and recorded in a log file as

\\test\folderwatch\XYZ was Renamed at 7/28/2021 2:03:00 PM

Folder TEMP_XYZ was renamed to XYZ

However, I am not able to achieve this as the code below only works on files. (txt,bmp, zip etc)

Any help is appreciated.

Code:

# specify the path to the folder you want to monitor:
$Monitorpath ="\\test\folderwatch"
$Path = $Monitorpath

# specify which files you want to monitor
$FileFilter = '*'  

# specify whether you want to monitor subfolders as well:
$IncludeSubfolders = $true

# specify the file or folder properties you want to monitor:
$AttributeFilter = [IO.NotifyFilters]::FileName, [IO.NotifyFilters]::LastWrite 

try
{
  $watcher = New-Object -TypeName System.IO.FileSystemWatcher -Property @{
    Path = $Path
    #Filter = $FileFilter
    IncludeSubdirectories = $IncludeSubfolders
    NotifyFilter = $AttributeFilter
  }

  $action = {
    # change type information:
    $details = $event.SourceEventArgs
    $Name = $details.Name
    $FullPath = $details.FullPath
    $OldFullPath = $details.OldFullPath
    $OldName = $details.OldName
    $ChangeType = $details.ChangeType
    $Timestamp = $event.TimeGenerated
    $LogDate = Get-Date -format "dd-MMMM-yy"
    
    # save information to a global variable for testing purposes
    # so you can examine it later
    # MAKE SURE YOU REMOVE THIS IN PRODUCTION!**************************DO NOT USE FOR PROD**************************
    $global:all = $details
    
    $text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp
    Write-Host ""
    Write-Host $text -ForegroundColor DarkYellow
    Add-content "\\test\folder_watch_logs\watchlog_$LogDate.txt" -value $text

    switch ($ChangeType)
    {
      'Changed'  { "CHANGE" }
      'Created'  { "CREATED"}
      'Deleted'  { "DELETED"

        Write-Host "Deletion Handler Start" -ForegroundColor Gray
        Start-Sleep -Seconds 4  
        Write-Host "Deletion Handler End" -ForegroundColor Gray
      
      }
      'Renamed'  { 
        # this executes only when a file was renamed
        $text = "Folder {0} was renamed to {1}" -f $OldName, $Name
        Write-Host $text -ForegroundColor Yellow
        Add-content "test\folder_watch_logs\watchlog_$LogDate.txt" -value $text
      }
        
      # any unhandled change types surface here:
      default   { Write-Host $_ -ForegroundColor Red -BackgroundColor White ;
      Add-content "test\folder_watch_logs\watchlog_$LogDate.txt" -value $_ }
    }
  }

  $handlers = . {
    Register-ObjectEvent -InputObject $watcher -EventName Changed  -Action $action 
    Register-ObjectEvent -InputObject $watcher -EventName Created  -Action $action 
    Register-ObjectEvent -InputObject $watcher -EventName Deleted  -Action $action 
    Register-ObjectEvent -InputObject $watcher -EventName Renamed  -Action $action 
  }

  # monitoring starts now:
  $watcher.EnableRaisingEvents = $true
  $LogDate = Get-Date -format "dd-MMMM-yy"
  Write-Host "Watching for changes to $Path"
  Add-content "test\folder_watch_logs\watcherstatus.txt" -value "Watching for changes to $Path"

  # since the FileSystemWatcher is no longer blocking PowerShell
  # we need a way to pause PowerShell while being responsive to
  # incoming events. Use an endless loop to keep PowerShell busy:
  do
  {
    Wait-Event -Timeout 1

    # write a dot to indicate we are still monitoring:
    #Write-Host "." -NoNewline
        
  } while ($true)
}
finally
{
  # stop monitoring
  $watcher.EnableRaisingEvents = $false
  
  # remove the event handlers
  $handlers | ForEach-Object {
    Unregister-Event -SourceIdentifier $_.Name
  }
  
  $handlers | Remove-Job
  
  # properly dispose the FileSystemWatcher:
  $watcher.Dispose()
  $LogDate = Get-Date -format "dd-MMMM-yy"
  Write-Warning "Event Handler disabled, monitoring ends."
  Add-content "test\folder_watch_logs\watcherstatus.txt" -value "Event Handler disabled, monitoring ends."
}

//Jagbir


Solution

  • Adjust your watcher's NotifyFilter so that it is looking at directory names

    $AttributeFilter = [IO.NotifyFilters]::FileName, [IO.NotifyFilters]::LastWrite, [IO.NotifyFilters]::DirectoryName  
    

    or if you are only interested in changes in directory names only specify

    $AttributeFilter = [IO.NotifyFilters]::DirectoryName  
    

    If you are only interested in the renaming events do not register the others

      $handlers = . {
        # Remove Changed, Created, and Deleted if they are of no concern    
        # Register-ObjectEvent -InputObject $watcher -EventName Changed  -Action $action 
        # Register-ObjectEvent -InputObject $watcher -EventName Created  -Action $action 
        # Register-ObjectEvent -InputObject $watcher -EventName Deleted  -Action $action 
        Register-ObjectEvent -InputObject $watcher -EventName Renamed  -Action $action 
      }