I'm working on a script that monitors an error folder and sends e-mail when an error occurs. For each error we get two files in the folder, one text file and one xml. In the e-mail I want to include the entire content of the text file and part of the content of the xml file.
In the following script I get only the content of the text file. (Lines for sending the email are commented out for testing purposes). I have read about variables and foreach and I guess this may be the problem, but I'm still not sure how to fix this in my script. Or maybe there is a much easier way to do this?
$Foldertowatch = 'C:\lpos\invalidArts'
$FilterXML = '*.xml'
$FilterTXT = '*.txt'
Unregister-Event -SourceIdentifier CreatedEventXML
$fswXML = New-Object System.IO.FileSystemWatcher $Foldertowatch, $FilterXML
$fswXML.EnableRaisingEvents=$true
$fswXML.IncludeSubdirectories=$false
Register-ObjectEvent -InputObject $fswXML -EventName Created -SourceIdentifier CreatedEventXML -Action {
$Filename = $Event.SourceEventArgs.Name
[XML]$XMLFile = (Get-Content $Foldertowatch\$Filename)
$XMLtmp = foreach ($user in $XMLFile.POSLog.POSLogTransaction)
{
$user.RetailStoreID
$user.WorkStationID
$user.OperatorID
$user.SequenceNumber
}
}
Unregister-Event -SourceIdentifier CreatedEventTXT
$fswTXT = New-Object System.IO.FileSystemWatcher $Foldertowatch, $FilterTXT
$fswTXT.EnableRaisingEvents=$true
$fswTXT.IncludeSubdirectories=$false
Register-ObjectEvent -InputObject $fswTXT -EventName Created -SourceIdentifier CreatedEventTXT -Action {
$FilenameTXT = $Event.SourceEventArgs.Name
$ContentTXT = (Get-Content $Foldertowatch\$FilenameTXT) -join "`n"
write-host $user.retailstoreid
Write-Host $contenttxt
<#$From = "from#mail.com"
$To = "to#mail.com"
$SMTPServer = "mailserver.com"
$subject = $env:COMPUTERNAME + " contains invalid ARTSXML"#>
<#Write-Host "Store:" + $ContentXML.RetailStoreID + "`n" + "Workstation:" + $ContentXML.WorkStationID + "`n" +"Operator:" + $ContentXML.OperatorID + "`n" +"Receiptnumber:" + $ContentXML.sequencenumber + "`n" + "`n" + "Filelocation: $Foldertowatch\$FilenameTXT" + "`n" + "`n" + <#$ContentTXT##>
<#$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer);
$smtp.Send($From, $To, $subject, $body);#>
}
The $ContentXML is from an early try, it should be $user now.
I manage to get content from XML if I run first part of script like this:
$Foldertowatch = 'C:\lpos\invalidArts' <# Folder to watch #>
$FilterXML = '*.xml' <# Use *.xml #>
$FilterTXT = '*.txt' <# Use *.txt for poslog2arts, use *.log for POS Reporting #>
Unregister-Event -SourceIdentifier CreatedEventXML
$fswXML = New-Object System.IO.FileSystemWatcher $Foldertowatch, $FilterXML
$fswXML.EnableRaisingEvents=$true
$fswXML.IncludeSubdirectories=$false
Register-ObjectEvent -InputObject $fswXML -EventName Created -SourceIdentifier CreatedEventXML -Action {
$Filename = $Event.SourceEventArgs.Name
[XML]$XMLFile = (Get-Content $Foldertowatch\$Filename)
$XMLtmp = foreach ($user in $XMLFile.POSLog.POSLogTransaction)
{
write-host $user.RetailStoreID
write-host $user.WorkStationID
write-host $user.OperatorID
write-hosts $user.SequenceNumber
}
}
I'm not sure of your intent, but I see a possible solutions. First, this code:
$XMLtmp = foreach ($user in $XMLFile.POSLog.POSLogTransaction)
{
$user.RetailStoreID
$user.WorkStationID
$user.OperatorID
$user.SequenceNumber
}
You never seem to use $XMLtmp again. Also, it's just going to contain an array of strings, not something that has properties like $user.RetailStoreID
What you can do is this:
$users = #()
Register-ObjectEvent -InputObject $fswXML -EventName Created -SourceIdentifier CreatedEventXML -Action {
$Filename = $Event.SourceEventArgs.Name
[XML]$XMLFile = (Get-Content $Foldertowatch\$Filename)
foreach ($user in $XMLFile.POSLog.POSLogTransaction) {
$users += $user
}
}
Then later you can index that array. Are there more than one user? Do you want to send more than one email?
At that point you can do the following:
$users | % { Write-Host $_.RetailStoreId }
The $user variable you create in the foreach () {} goes out of scope (aka "disappears") when the } is hit. The $XMLtmp is unnecessary. Declaring $users outside of the scope of the Action and foreach ensures it is global to the entire script.
Related
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
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
}
I have a FileSystemWatcher Script which does create a FileSystemWatcher for each Subfolder that matches a regex. This works like a charm.
Here's my script
$Folders = gci $Dir -Dir | ? Name -match '^\d{5}$' | % {
$source = $_.FullName
$watcher = [System.IO.FileSystemWatcher]::new()
$watcher.IncludeSubdirectories = $false
$watcher.Path = $source
$watcher.Filter = "*.csv"
$watcher.EnableRaisingEvents = $true
New-Variable -Name $_.Name -Value $watcher
}
$action = { stuff }
Get-Variable | ? Name -match '^\d{5}$' | % {
Register-ObjectEvent $_.Value Created -Action $action -SourceIdentifier $_.Name > $null
}
This leaves me with some FileSystemWatchers in different Variables like $70447, $78900, $13450 etc.
but I also have one watcher in $watcher, but this variable is only used to pass my FileSystemWatcher Object to the "productive" 5-digit variables
I wanted to get rid of $watcher by doing a $watcher.dispose() after the New-Variable Command. But when I do this, all of my watchers throw an error.
Why does this happen? $watcher is not in use anymore since the object is already passed on to a new variable. Can someone explain this?
Thanks!
Edit:
Register-ObjectEvent : Cannot access thrown Object.
Objektname: "FileSystemWatcher".
In Z:\Powershell-Scripts\FSW.ps1:43 Zeichen:5
+ Register-ObjectEvent $_.Value Created -Action $action -SourceIden ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.IO.FileSystemWatcher:FileSystemWatcher) [Register-ObjectEvent], ObjectDisposedException
+ FullyQualifiedErrorId : INVALID_REGISTRATION,Microsoft.PowerShell.Commands.RegisterObjectEventCommand
If I had to guess, the references are getting tied to the variables somehow and disposing is causing some kind of scope issue. I'm unable to replicate your problem, but consider not having in-between variable assignments and see if it resolves your issue:
Get-ChildItem -Path $dir -Directory | ? Name -match '^\d{5}$' | % {
New-Variable -Name $_.Name -Value (New-Object -TypeName System.IO.FileSystemWatcher -Property #{
IncludeSubdirectories = $false
Path = $_.FullName
Filter = '*.csv'
EnableRaisingEvents = $true
})
}
$action = { stuff }
Get-Variable | ? Name -match '^\d{5}$' | % {
$null = $_.Value | Register-ObjectEvent -EventName Created -Action $action -SourceIdentifier $_.Name
}
The script uses file system watcher to monitor a honeypot folder, and report back any changes (edit, rename, delete or create), then performs some actions.
The actions work fine when creating, renaming and deleting.
But when editing, I can only make the script trigger the actions once. So for example, if a test device tries to edit a file on honeypot folder, the actions are triggered. But is the same device tries to edit again the same file or a different file, the watcher for editing seems to not work because the actions are not triggered.
So I tried to reset the script every 5 minutes via task scheduler (start the script every 5 minutes), but still same results.
Here's the code:
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "\\vmserver2\_Do_Not_Delete_Or_Rename"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = {
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$logline = "$(Get-Date), $changeType, $path"
#Add-content "D:\log.txt" -value $logline
#write-host $logline
$targetdevice = Get-SmbOpenFile |
select clientusername, clientcomputername, path |
where {$_.Path -like 'E:\Data\Archive\_Do_Not_Delete_Or_Rename' }
$targetIP = $targetdevice.clientcomputername
$targetUser = $targetdevice.clientusername
Send-ToEmail -email "edu.bit.es#gmail.com" $targetIP
$targetUser
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Created" -Action $action
Register-ObjectEvent $watcher "Changed" -Action $action
Register-ObjectEvent $watcher "Deleted" -Action $action
Register-ObjectEvent $watcher "Renamed" -Action $action
while ($true) {sleep 5}
I'm pretty new to powershell so I don't understand while the watchers for the rest of events work and only editing does not work.
Your core logic is sound.
If you simplify your action block to only do the Write-host part, it should always work.
I believe your problem is that on the second call, you get a terminating error that you didn't catch and in return, it stop the events from triggering.
Try replacing your action scriptblock with the following
$action = {
try {
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$logline = "$(Get-Date), $changeType, $path"
#Add-content "D:\log.txt" -value $logline
#write-host $logline
$targetdevice = Get-SmbOpenFile |
select clientusername, clientcomputername, path |
where {$_.Path -like 'E:\Data\Archive\_Do_Not_Delete_Or_Rename' }
$targetIP = $targetdevice.clientcomputername
$targetUser = $targetdevice.clientusername
Send-ToEmail -email "edu.bit.es#gmail.com" $targetIP
$targetUser
}
catch {
Write-Host 'an error was thrown :(... Fortunately, it was caught.'
}
}
This should correct your issue of the changed event triggering only once.
Here's an example using 3 watchers that check for a file change over the same directory.
You will notice that after the counter reached 5, only 2 of the 3 watchers continue to work properly. The one that do not produce any errors watcherNoError and the one that produce a terminating error but was caught in a Try catch watcherErrorsTryCatch.
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$PathToWatch = "\\127.0.0.1\c$\_"
$watcherNoError = New-Object System.IO.FileSystemWatcher -Property #{Path = $PathToWatch;Filter = '*.*';IncludeSubdirectories=$true;EnableRaisingEvents = $true}
$watcherWithErrors = New-Object System.IO.FileSystemWatcher -Property #{Path = $PathToWatch;Filter = '*.*';IncludeSubdirectories=$true;EnableRaisingEvents = $true}
$watcherErrorsTryCatch = New-Object System.IO.FileSystemWatcher -Property #{Path = $PathToWatch;Filter = '*.*';IncludeSubdirectories=$true;EnableRaisingEvents = $true}
$Global:Counter = #{
watcherNoError = 0
watcherWithErrors = 0
watcherErrorsTryCatch = 0
}
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = {
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
Switch ($Event.MessageData.Name) {
"NoErrors" {
$Global:Counter.watcherNoError +=1
$count = $Global:Counter.watcherNoError
}
"WithErrors" {
$Global:Counter.watcherWithErrors +=1
$count = $Global:Counter.watcherWithErrors
if ($count -eq 5) {
Write-Host 'A terminated errow will be thrown...' -ForegroundColor DarkMagenta
Throw 'oh no !'
}
}
"WithErrorsTryCatch" {
$Global:Counter.watcherErrorsTryCatch +=1
$count = $Global:Counter.watcherErrorsTryCatch
if ($count -eq 5) {
try {
Throw 'oh no !'
}
catch {
Write-Host 'error was caught... You are safe ;)' -ForegroundColor Green
}
}
}
}
$logline = "Count: $Count - $($event.MessageData.Name): $changeType, $path"
write-host $logline -ForegroundColor $Event.MessageData.ForegroundColor
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcherNoError "Changed" -Action $action -MessageData #{Name='NoErrors';ForegroundColor='Yellow'}
Register-ObjectEvent $watcherWithErrors "Changed" -Action $action -MessageData #{Name='WithErrors';ForegroundColor='DarkMagenta'}
Register-ObjectEvent $watcherErrorsTryCatch "Changed" -Action $action -MessageData #{Name='WithErrorsTryCatch';ForegroundColor='Green'}
while ($true) {sleep 5}
$action = {
try {
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$logline = "$(Get-Date), $changeType, $path"
#Add-content "D:\log.txt" -value $logline
#write-host $logline
$targetdevice = Get-SmbOpenFile |
select clientusername, clientcomputername, path |
where {$_.Path -like 'E:\Data\Archive\_Do_Not_Delete_Or_Rename' }
$targetIP = $targetdevice.clientcomputername
$targetUser = $targetdevice.clientusername
Send-ToEmail -email "edu.bit.es#gmail.com" $targetIP
$targetUser
}
catch {
Write-Host 'an error was thrown :(... Fortunately, it was caught.'
}
}
Additional note:
Even if it was not the solution to your problem, you should still put a try / catch in that Action scriptblock as a terminating error will stop further processing on the next changes.
Either you'll need to use
Remove-Event $watcher "Changed"
at the end of the $Action scriptblock
OR
use
Unregister-Event $watcher "Changed"
Register-ObjectEvent $watcher "Changed -Action $action
at the end of the $Action scriptblock.
I have researched this question quite a bit and have found others with similar issues, but no fix that works for us.
We have built a power shell script to monitor a folder for new images, check their color profile with exiftool and convert when needed with image magick. All of this functionality works well enough when the script is run in ISE, but will not work if the script is executed from a .exe or ran manually.
I have read that FileSystemWatcher requires the script be ran in STA which I have attempted to do a few times by including -STA in the target for the .exe shortcut. Doing so proves unsuccessful.
#----------------------------------------------------------------------------
Unregister-Event -SourceIdentifier FileCreated
Clear
#----------------------------------------------------------------------------
$description = Get-WmiObject -Class Win32_OperatingSystem |Select Description
$description = $description -Replace "#{Description=",""
$description = $description -Replace "}",""
$assetsFolder = "E:\" + $description + "\Capture One Session\Output"
$conversionStage = "C:\Profile_Pro\conversionStage"
#----------------------------------------------------------------------------
New-Item -ItemType directory -Force -Path "$assetsFolder" | Out-Null
New-Item -ItemType directory -Force -Path "$assetsFolder" | Out-Null
#----------------------------------------------------------------------------
$filter = "*.*"
$srgb = "sRGB IEC61966-2.1"
$isTif = "tif"
#----------------------------------------------------------------------------
$monitor = New-Object IO.FileSystemWatcher $assetsFolder, $filter -Property #{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
#----------------------------------------------------------------------------
$onCreated = Register-ObjectEvent $monitor Created -SourceIdentifier FileCreated -Action {
#----------------------------------------------------------------------------
Add-Type -AssemblyName System.Windows.Forms
#----------------------------------------------------------------------------
$path = $event.SourceEventArgs.FullPath
$name = $event.SourceEventArgs.Name
Write-Host $path
Write-Host $name
If ($name -Match $isTif)
{
$BOX = [System.Windows.Forms.MessageBox]::Show('TIFF FILE DETECTED. PLEASE CHECK RECIPE.', 'Warning', 'ok', 'Warning')
$path = $path -Replace ".tif.tmp",".tif"
Start-Sleep -s 2
Remove-Item "$path" -Force
}
Else
{
$colorSpace = C:\Profile_Pro\tools\exiftool.exe -T -ProfileDescription $path
$profileConvert = 'C:\Profile_Pro\tools\sRGB_Color_Space_Profile.icm'
If ($colorSpace -Match $srgb)
{
}
Else
{
Start-Sleep -s 3
$name = $name -Replace ".jpg.tmp",".jpg"
$path = $path -Replace ".jpg.tmp",".jpg"
Move-Item -Path $path -Destination $conversionStage -Force
convert $conversionStage\$name -profile $profileConvert $path
Start-Sleep -s 1
Remove-Item "$conversionStage\$name" -Force
#----------------------------------------------------------------------------
$BOX = [System.Windows.Forms.MessageBox]::Show('COLOR PROFILE ERROR. PLEASE CHECK RECIPE.', 'Warning', 'ok', 'Warning')
#----------------------------------------------------------------------------
$TO = $env:USERNAME + "#biz.com"
$Outlook = New-Object -ComObject Outlook.Application
$Mail = $Outlook.CreateItem(0)
$Mail.To = $TO
$Mail.Subject = "COLOR PROFILE DEFECT: " + $name
$Mail.importance = 2
$Mail.Body = "A COLOR PROFILE DEFECT HAS BEEN DETECTED WITH FILE:`r`n`r`n$name`r`n`r`nTHIS FILE IS FIXED.`r`n`r`nPLEASE CHECK YOUR PROCESS RECIPE."
$Mail.Send()
}
}
}
#----------------------------------------------------------------------------
#Unregister-Event -SourceIdentifier FileCreated
#----------------------------------------------------------------------------
Any ideas to keep this script running as a .exe or outside of ISE would be greatly appreciated.
with powershell v2 and pushbullet, I try to send push notification when a file in modified
$folder = 'c:\path\to\file'
$filter = '*.*'
$user = "pushbullet_token"
$url = "https://api.pushbullet.com/v2/pushes"
$fsw = New-Object IO.FileSystemWatcher $folder, $filter
$fsw.IncludeSubdirectories = $true
$fsw.NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$name = $Event.SourceEventArgs.Name
$path = $Event.SourceEventArgs.FullPath
Out-File -FilePath c:\path\to\file\outlog.txt -Append -InputObject "$path"
$title = $path
Add-Type -AssemblyName System.Web
$title = [System.Web.HttpUtility]::UrlEncode($title)
$data = "type=note&title=" + $title + "&body=body"
$webclient = new-object System.Net.WebClient
$webclient.Credentials = new-object System.Net.NetworkCredential($user, "")
Out-File -FilePath c:\path\to\file\outlog.txt -Append -InputObject "$data"
$result = $webclient.UploadString($url, "POST", $data)
Out-File -FilePath c:\path\to\file\outlog.txt -Append -InputObject "$result"
}
#Unregister-Event FileCreated
for check the script a outlog.txt file is write, but only the two first messages are writen and the notification never is submitted.
when I launch uploadstring manually
$user = "pushbullet_token"
$url = "https://api.pushbullet.com/v2/pushes"
$data = "type=note&title=title&body=body"
$webclient = new-object System.Net.WebClient
$webclient.Credentials = new-object System.Net.NetworkCredential($user, "")
$result = $webclient.UploadString($url, "POST", $data)
work ok.
The global variable $url is not available inside your event handler script block. Change your Register-ObjectEvent like so:
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -MessageData $url -Action {
$name = $Event.SourceEventArgs.Name
$path = $Event.SourceEventArgs.FullPath
$url = $Event.MessageData
...
}
The call to $webclient.UploadString(...) in the event handler is throwing an exception, which terminates the EventJob context it's running in. You can verify this by typing:
Get-Job
and looking for the failed job. You can then do Recieve-Job on the failed job to get the error message. Its probably an authentication error. By putting a valid authentication token, I was able to get your code to work.
If you want to have event handler continue even in the event of an error you'll have to use a try/catch, for example:
$result = try { $webclient.UploadString($url, "POST", $data) }
catch { $_.Exception.InnerException.Response }