1

I only dabble in PS so I'm probably missing something obvious, but this seems like it should work lol

I've got a filewatcher, looks for a specific file in a specific folder, when found it triggers an action. The action first writes to screen, then to logfile then triggers a follow-up script.

Writing to screen works, writing to logfile doesn't, triggering follow up script works too. I actually tried the writing to logfile a few different ways, even building a function before this part and calling it, like a Write-Log instead of Write-Host but it doesn't work either.

Is there a special means to write to log in the manner I'm trying?

$folder = 'D:\InputFiles\'
$filter = 'data.csv'
$LogFile = "D:\APIRead\logs\master.log"

$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property @{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'}

Register-ObjectEvent $fsw Created -SourceIdentifier PaymentsMKFileCreated -Action { 
$name = $Event.SourceEventArgs.Name 
$changeType = $Event.SourceEventArgs.ChangeType 
$timeStamp = $Event.TimeGenerated 
$Output = "The file '$name' was $changeType at $timeStamp"
Write-Host $Output
Out-File -FilePath $LogFile -InputObject $Output -Append
#Invoke-Item 'D:\APIRead\scripts\process.bat'
}

3 Answers 3

2
$LogFile = "D:\APIRead\logs\master.log"

Try moving this line inside of your Event -Action

It could be trying to expand $LogFile, but it is not defined in the Action's scope.

Sign up to request clarification or add additional context in comments.

Comments

2

Grok42's helpful answer offers a pragmatic solution to the problem: defining $LogFile inside the -Action script block by definition makes it available there (but only there).

Indeed, a script block { ... } passed to the -Action parameter of the Register-ObjectEvent cmdlet does not generally see variables defined in the caller's scope (unless those variables happen to be defined in the global scope), because such a script block runs in a dynamic module.

However, you may still want to declare your $LogFile variable in the caller's scope while also allowing it to be referenced in the -Action script block, so that both scopes can act on it.

To that end, you can use Register-ObjectEvent's -MessageData parameter to pass a value to the -Action script block, which it can reference as $Event.MessageData, via the automatic $Event variable:

$folder = 'D:\InputFiles\'
$filter = 'data.csv'
$LogFile = "D:\APIRead\logs\master.log"

$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property @{IncludeSubdirectories = $false; NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite' }

# Note the use of -MessageData
Register-ObjectEvent $fsw Created -SourceIdentifier PaymentsMKFileCreated -MessageData $LogFile -Action { 
  $name = $Event.SourceEventArgs.Name 
  $changeType = $Event.SourceEventArgs.ChangeType 
  $timeStamp = $Event.TimeGenerated
  $logFile = $Event.MessageData # Get the log file path from the -MessageData argument
  $Output = "The file '$name' was $changeType at $timeStamp"
  Write-Host $Output
  Out-File -FilePath $logFile -InputObject $Output -Append
}

Note:

  • For an example of passing multiple values from the caller's scope to the -Action script block, using a hashtable, see this answer.

  • It's even possible to pass the caller's entire state to -MessageData, via $ExecutionContext.SessionState, which allows the -Action block to retrieve any variable from the caller's state via $Event.MessageData.PSVariable.GetValue('varName')

1 Comment

Thank you for explaining in more depth @mklement0 Was end of a busy day, with not much time to respond. I've never used the MessageData parameter, so it was helpful information for me as well.
-1

removed the ** after append and make sure you have permissions to the directory you are writing to.

Adding -Force makes it create the file if it doesn't exist.

Out-File -FilePath $LogFile -InputObject $Output -Append -Force

4 Comments

The asterisks were because I was trying to make that line bold when posting here, but it didn't work and I forgot to remove it. I didn't know about -Force, so I added that and it still doesn't work. Is there any way to turn on added information to see if there's an error? permissions are for the same user that runs it.
-Force is not needed to create the target file - it is always implicitly created. The purpose of the -Force switch is: "Overrides the read-only attribute and overwrites an existing read-only file. The Force parameter does not override security restrictions." - learn.microsoft.com/en-us/powershell/module/…
@mklement0 I should clarify, force creates the path to the file. If the folder APIreads exists, but not the logs folder, it will fail unless the force parameter was set.
That isn't true either - Out-File fundamentally doesn't support on-demand creation of the output file's directory. All that -Force does is what I've cited in my previous comment. (By contrast, New-Item -ItemType File -Force does what you describe )

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.