Filesystemwatcher problem copying files

This topic contains 10 replies, has 3 voices, and was last updated by Profile photo of Jesper Kristensen Jesper Kristensen 4 months, 4 weeks ago.

Viewing 11 posts - 1 through 11 (of 11 total)
  • Author
    Posts
  • #38293
    Profile photo of Jesper Kristensen
    Jesper Kristensen
    Participant

    Hi Guys

    Need a little help here.
    I have a system that generates pdf files and stores them in a few different subfolders under the same parent folder.

    I need theese files printed out and then moved to a subfolder within their respective folders.
    Filestructure looks like this:

    Parent |
    |- subfolder1 |
    | |printed
    |
    |-subfolder2 |
    | |printed
    |
    |-subfolder3 |
    |printed

    I found the script below which watches the parent folder (including subfolders) and prints whenever a new pdf is generated in one of those. This works fine.

    But... I cannot get the file moved from ex. subfolder1 to "subfolder1>printed" afterwards.

    Current script:

    $FileSystemWatcher = New-Object System.IO.FileSystemWatcher
     $FileSystemWatcher.Path = โ€œC:\DocsToPrint\Filesโ€
     $FileSystemWatcher.IncludeSubdirectories = $true
    
    Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action {
    $folderpath = Get-Item $Event.SourceEventArgs.FullPath
      if((Get-Item $Event.SourceEventArgs.FullPath | select -Expand Extension) -eq โ€œ.pdfโ€)
     {
    Start-Process -FilePath $Event.SourceEventArgs.FullPath -Verb Print -PassThru | %{ sleep 10;$_ } | kill
     }
     Move-Item -Path $folderPath.path -Filter *.pdf -Destination ($folderpath + "\" + 'printed')
     Out-File -FilePath c:\DocsToPrint\outlog.txt -Append 
     }
    

    Problems: Move-Item not working, no log output (just added 2 min ago for troubleshooting).
    Also I should probably make sure that the "printed" folders are not watched, so that I don't get a print from there too.

    Any help will be greatly appreciated. ๐Ÿ™‚

    Best Regards,
    Jesper

    #38298
    Profile photo of Don Jones
    Don Jones
    Keymaster

    So, you probably _don't_ want to move the files to a subfolder in the same hierarchy, or you'll trigger the Watcher again. Keep that in mind.

    Also keep in mind that you don't need to concatenate paths like you're doing, and that the Join-Path command is a better way of doing so.

    $destination = Join-Path $folderpath "printed"

    Are you getting any errors? My supposition is that your -Destination path isn't correctly formed, which my suggestion will correct, but without any kind of errors it's a little tough to troubleshoot.

    #38333
    Profile photo of Jesper Kristensen
    Jesper Kristensen
    Participant

    Hi Don
    Thanks a lot for the reply. I have never heard of join-path before. But I can see that it seems like the right way to go. I'll see if I can make that work. ๐Ÿ™‚

    Regarding providing errors, I would love to give you some, but I am not getting any?which is why I was trying the out-file log thing.
    I was thinking if this failing could be due to the script kind of "never ending", cause it is always active (watching for new files). Don't know if I am right in that assumption?

    When I run the script in ISE, I just get this:

    PS C:\Users\jeskri> P:\Powershell scripts\PDF_Printout3.ps1
    
    Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                  
    --     ----            -------------   -----         -----------     --------             -------                  
    2      ce4b160a-791...                 NotStarted    False                                ...                      
    
    
    
    PS C:\Users\jeskri> 
    

    No output what so ever, when dragging pdf files to the folders... or any errors from the move-item command which is not working.

    I have been searching a little bit for "the right way" to get errorlogs from your scripts, but there seem to be a lot of different ways to do it. PSLogging, the transscipt way or write-debug etc? any suggestions?

    /Jesper

    #38336

    well looking through your code, your out-file appears to have nothing passed to it.

    i would do something like this (assuming you take don's advice and use the join-path into a $destination variable)

    try
    {
     Move-Item -Path $folderPath.path -Filter *.pdf -Destination ($folderpath + "\" + 'printed')
    "file moved to $destination"| Out-File -FilePath c:\DocsToPrint\outlog.txt -Append
    }
    catch
    {
    $error|Out-File  -FilePath c:\DocsToPrint\outlog.txt -Append
    $Error.Clear()
    }
    

    essentially wrap the move into a try/catch, if successful output to the logfile

    and if an error occurs send the error details to the logfile

    #38344
    Profile photo of Jesper Kristensen
    Jesper Kristensen
    Participant

    Hi David

    Thanks for pitching in. I tried your suggestion and it seems I am getting closer to a solution.

    With your help the error logging part is now working, so I have some output to troubleshoot with.

    The Script now looks like this:

    $FileSystemWatcher = New-Object System.IO.FileSystemWatcher
     $FileSystemWatcher.Path = โ€œC:\DocsToPrint\Filesโ€
     $FileSystemWatcher.IncludeSubdirectories = $true
     
    Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action {
      if((Get-Item $Event.SourceEventArgs.FullPath | select -Expand Extension) -eq โ€œ.pdfโ€)
     {
    Start-Process -FilePath $Event.SourceEventArgs.FullPath -Verb Print -PassThru | %{ sleep 10;$_ } | kill
     }
     $folderpath = Get-Item $Event.SourceEventArgs.FullPath
      try
    {
     Move-Item -Path $folderPath.path -Filter *.pdf -Destination ($folderpath + "\" + 'printed')
    "file moved to $destination"| Out-File -FilePath c:\DocsToPrint\outlog.txt -Append
    }
    catch
    {
    $error|Out-File  -FilePath c:\DocsToPrint\outlog.txt -Append
    $Error.Clear()
    }
     }
    

    There is something wrong with the $folderpath variable and I admit that I am not at all sure where in the script to place that variable? I tried placing it in the top with the other variables, but that gives an error in the console:
    Get-Item : Cannot bind argument to parameter 'Path' because it is null.

    Placing it where it is now in the above script, gives a similar error in the errorlog.
    Outlog.txt gives this error:

    Move-Item : Cannot bind argument to parameter 'Path' because it is null.
    At P:\Powershell scripts\PDF_Printout6.ps1:13 char:18
    +  Move-Item -Path $folderPath.path -Filter *.pdf -Destination ($folderpath + "\"  ...
    +                  ~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidData: (:) [Move-Item], ParameterBindingValidationException
        + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.MoveItemCommand
     
    Method invocation failed because [System.IO.FileInfo] does not contain a method named 'op_Addition'.
    At P:\Powershell scripts\PDF_Printout6.ps1:13 char:2
    +  Move-Item -Path $folderPath.path -Filter *.pdf -Destination ($folderpath + "\"  ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (op_Addition:String) [], RuntimeException
        + FullyQualifiedErrorId : MethodNotFound
    

    I guess it is pretty obvious that I don't know what the hell I am doing half the time. But I'm learning and think it is exciting, so that is a positive thing.

    /Jesper

    #38349

    well i've never used filesystemwatcher personally, but it looks like whatever is contained in $folderpath = Get-Item $Event.SourceEventArgs.FullPath

    the .path value is not valid, i'd explore exactly what is contained within $folderpath

    easiest is to put $folderpath.path|out-file -filepath c:\DocsToPrint\outlog.txt -append
    in your catch statement.

    that will let you see exactly what is being passed into your move-item

    #38374
    Profile photo of Jesper Kristensen
    Jesper Kristensen
    Participant

    Thanks again David

    that gives me this error:

    Method invocation failed because [System.IO.FileInfo] does not contain a method named 'op_Addition'.
    At P:\Powershell scripts\PDF_Printout6.ps1:13 char:2
    + Move-Item -Path $folderPath.path -Filter *.pdf -Destination ($folderpath + "\" ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

    /Jesper

    #38376
    Profile photo of Jesper Kristensen
    Jesper Kristensen
    Participant

    Man, I feel like I am SO close.

    It seems that this:
    $folderpath = Get-Item $Event.SourceEventArgs.fullpath

    ...contains both the path AND the filename. So it includes the file name in the path.

    Outlog says:
    file moved to C:\DocsToPrint\Files\Outgoing\xxx.pdf\printed

    I tried to not use the "fullpath" property (if it is infact a property?):
    $folderpath = Get-Item $Event.SourceEventArgs.path
    ...but that doesn't work. Not sure how to get a list of which properties can be used for $Event.SourceEventArgs ??

    /Jesper

    #38379

    someone else will need to chime-in, i do not know exactly what all is contained in the event args.

    #38386
    Profile photo of Jesper Kristensen
    Jesper Kristensen
    Participant

    Hi David

    I know what you mean. My knowledge of Powershell, Objects, properties and so on is simply not deep enough for me to solve this on my own. and since I am from Denmark, once in a while, my understanding of English sometimes add to the confusion as well. ๐Ÿ™‚
    I have been googeling all afternoon to find something usefull.

    I found and tried this: $FileSystemWatcher | gm -membertype *

    which gives me:

    TypeName: System.IO.FileSystemWatcher
    
    Name                      MemberType Definition                                                                                                                                                 
    ----                      ---------- ----------                                                                                                                                                 
    Changed                   Event      System.IO.FileSystemEventHandler Changed(System.Object, System.IO.FileSystemEventArgs)                                                                     
    Created                   Event      System.IO.FileSystemEventHandler Created(System.Object, System.IO.FileSystemEventArgs)                                                                     
    Deleted                   Event      System.IO.FileSystemEventHandler Deleted(System.Object, System.IO.FileSystemEventArgs)                                                                     
    Disposed                  Event      System.EventHandler Disposed(System.Object, System.EventArgs)                                                                                              
    Error                     Event      System.IO.ErrorEventHandler Error(System.Object, System.IO.ErrorEventArgs)                                                                                 
    Renamed                   Event      System.IO.RenamedEventHandler Renamed(System.Object, System.IO.RenamedEventArgs)                                                                           
    BeginInit                 Method     void BeginInit(), void ISupportInitialize.BeginInit()                                                                                                      
    CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)                                                                                            
    Dispose                   Method     void Dispose(), void IDisposable.Dispose()                                                                                                                 
    EndInit                   Method     void EndInit(), void ISupportInitialize.EndInit()                                                                                                          
    Equals                    Method     bool Equals(System.Object obj)                                                                                                                             
    GetHashCode               Method     int GetHashCode()                                                                                                                                          
    GetLifetimeService        Method     System.Object GetLifetimeService()                                                                                                                         
    GetType                   Method     type GetType()                                                                                                                                             
    InitializeLifetimeService Method     System.Object InitializeLifetimeService()                                                                                                                  
    ToString                  Method     string ToString()                                                                                                                                          
    WaitForChanged            Method     System.IO.WaitForChangedResult WaitForChanged(System.IO.WatcherChangeTypes changeType), System.IO.WaitForChangedResult WaitForChanged(System.IO.WatcherC...
    Container                 Property   System.ComponentModel.IContainer Container {get;}                                                                                                          
    EnableRaisingEvents       Property   bool EnableRaisingEvents {get;set;}                                                                                                                        
    Filter                    Property   string Filter {get;set;}                                                                                                                                   
    IncludeSubdirectories     Property   bool IncludeSubdirectories {get;set;}                                                                                                                      
    InternalBufferSize        Property   int InternalBufferSize {get;set;}                                                                                                                          
    NotifyFilter              Property   System.IO.NotifyFilters NotifyFilter {get;set;}                                                                                                            
    Path                      Property   string Path {get;set;}                                                                                                                                     
    Site                      Property   System.ComponentModel.ISite Site {get;set;}                                                                                                                
    SynchronizingObject       Property   System.ComponentModel.ISynchronizeInvoke SynchronizingObject {get;set;}
    

    Which seems useful.

    But this:
    $Folderpath | gm -membertype *

    ...doesn't work.

    gm : You must specify an object for the Get-Member cmdlet.
    At line:1 char:15
    + $Folderpath | gm -membertype *
    +               ~~~~~~~~~~~~~~~~
        + CategoryInfo          : CloseError: (:) [Get-Member], InvalidOperationException
        + FullyQualifiedErrorId : NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand
    

    probably because $Event.SourceEventArgs is not an object that can be piped to gm or??

    I did find another thread on another forum, where NotifyFilter is marketed.
    Any idea if that would be a better way to go when trying to get where I want?

    http://stackoverflow.com/questions/20558212/powershell-how-to-mointor-a-directory-and-move-files-over-to-another-folder

    /Jesper

    #38476
    Profile photo of Jesper Kristensen
    Jesper Kristensen
    Participant

    FINALLY, It works... ๐Ÿ™‚

    Current script:

    # Variables for Watcher
    $folder = "C:\DocsToPrint\Files"
    $filter = '*.pdf'
    
    # Watcher + Settings                     
    $fsw = New-Object IO.FileSystemWatcher $folder, $filter 
    $fsw.IncludeSubdirectories = $true              
    $fsw.NotifyFilter = [IO.NotifyFilters]'FileName', 'DirectoryName'
    
    # Register Event (when file is created)
    $onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
    
    # Foreach file loop - print pdf file
    ForEach ($f in $fsw) {
    if(($File = Get-Item $Event.SourceEventArgs.FullPath | select -Expand Extension) -eq โ€œ.pdfโ€) {
       Start-Process -FilePath $Event.SourceEventArgs.FullPath -Verb Print -PassThru | %{ sleep 10;$_ } | kill
    
    # Variables for move   
    $folderpath = ($Event.SourceEventArgs.FullPath | Split-Path)
    $folderfile = ($Event.SourceEventArgs.FullPath | Split-Path -Leaf)
    $destination = "C:\DocsToPrint\Printed"
         }
    
    # Variables for logging
    $logpath =  'C:\DocsToPrint\outlog.txt'
    
    # Grab current file and move to "printed" folder
    try
    {
       Get-ChildItem -Path $folderpath -Filter $folderfile| Move-Item -Destination $destination | Out-File -FilePath $logpath -Append
    
    # Log move in logfile   
       "file $folderfile moved to $destination"| Out-File -FilePath $logpath -Append
       }
    
    # Log if errors + clear
    catch
    {
    $error|Out-File -FilePath $logpath -Append
    $Error.Clear()
       }
       }
       }
    

    This is probably not the "cleanest" code in history, but it get the job done.

    Two questions!
    If a file with the same name already exists in "printed" folder, it doesn't move the files. I would like to rename the newest file by adding a number and then move. Ideas?

    I would like to place the script in the startup folder on the server, so it executes the ps1 script after reboot etc. I created a .cmd file with these entries:

    powershell -command Set-executionpolicy Unrestricted
    powershell -command ". C:\temp\PDF_Printout13.ps1"
    

    ...but that doesn't Work, like the script isn't running/active?

    Any help or suggestions to make current script better will be greatly appreciated.

    Best Regards, Jesper

Viewing 11 posts - 1 through 11 (of 11 total)

You must be logged in to reply to this topic.