2

New to Powershell. I am writing a script that watches files in a directory and reports the changes to the console.

I am noticing quite a bit of code duplication in the script blocks I'm using for the FS "watchers".

Here is a snippet of the script blocks. I can post the whole script if needed, it's a little longer and there's a little more going on.

# Filter all files
$filter = "*.*"
$watcher = New-Object IO.FileSystemWatcher $watchdir, $filter -Property @{
    IncludeSubdirectories = $true
    EnableRaisingEvents = $true
}

# File creation
Register-ObjectEvent $watcher Created -SourceIdentifier Created -Action {
    $path = $Event.SourceEventArgs.FullPath
    $name = $Event.SourceEventArgs.Name
    $changeType = $Event.SourceEventArgs.ChangeType
    $timeStamp = $Event.TimeGenerated
    $message = "The file '$name' was '$changeType' at '$timeStamp'"
    Write-Host $message
}

# File change
Register-ObjectEvent $watcher Changed -SourceIdentifier Changed -Action {
    $path = $Event.SourceEventArgs.FullPath
    $name = $Event.SourceEventArgs.Name
    $changeType = $Event.SourceEventArgs.ChangeType
    $timeStamp = $Event.TimeGenerated
    $message = "The file '$name' was '$changeType' at '$timeStamp'"
    Write-Host $message
}

# File rename
...

# File delete
...

Is there a good pattern or nicer way of writing this to reduce the amount of code?

jmreicha
  • 3,155
  • 7
  • 32
  • 39
  • 1
    Wrap redundant code in a function. Then call that function however often you need. – Ansgar Wiechers Jan 15 '17 at 23:29
  • Basically I'm wondering if there is an idiomatic way of doing this. For example, how do you handle scoping for the `$watcher` variable, and passing in params, etc. – jmreicha Jan 16 '17 at 00:10

2 Answers2

3

In your examples, the script blocks are exactly the same, so in that case, just put them in a variable and pass that along:

$action = {
    $path = $Event.SourceEventArgs.FullPath
    $name = $Event.SourceEventArgs.Name
    $changeType = $Event.SourceEventArgs.ChangeType
    $timeStamp = $Event.TimeGenerated
    $console_message = "The file '$name' was '$changeType' at '$timeStamp'"
    Write-Host message
}

# File creation
Register-ObjectEvent $watcher Created -SourceIdentifier Created -Action $action

# File change
Register-ObjectEvent $watcher Changed -SourceIdentifier Changed -Action $action

If you post an example where there is redundancy in the script blocks but they aren't exactly the same, then it would be easier to show an example of how to best abstract that. There may not be a one-size-fits-all solution.

briantist
  • 45,546
  • 6
  • 82
  • 127
-1

You should be wrapping reused code into functions, see here for an explanation on how to do so: http://windowsitpro.com/windows/create-your-own-powershell-functions

In your case, I would create the following function:

function FileChange {
  Register-ObjectEvent $watcher Created -SourceIdentifier Created -Action {
  $path = $Event.SourceEventArgs.FullPath
  $name = $Event.SourceEventArgs.Name
  $changeType = $Event.SourceEventArgs.ChangeType
  $timeStamp = $Event.TimeGenerated
  $console_message = "The file '$name' was '$changeType' at '$timeStamp'"
  Write-Host message
}

Then use it to replace repeated code:

# Filter all files
$filter = "*.*"
$watcher = New-Object IO.FileSystemWatcher $watchdir, $filter -Property @{
IncludeSubdirectories = $true
EnableRaisingEvents = $true
}

# File creation
FileChange()

# File change
FileChange()
grorkster
  • 42
  • 1
  • 5