#Register-ObjectEvent for System.IO.FileSystemWatcher shows garbage for the file name that changed

7 messages · Page 1 of 1 (latest)

edgy ingot
#

Hi! I am trying to write a script that monitors shader file changes that will be built by a separate powershell script. Unfortunately I can't see what file is triggering the change because it is garbled:

ChangeType FullPath                                                            Name
---------- --------                                                            ----
   Changed C:\Users\Bjorn\source\repos\btipling\Rosy\src\shaders\lupkd2td.l4s~ lupkd2td.l4s~



ChangeType : Changed
FullPath   : C:\Users\Bjorn\source\repos\btipling\Rosy\src\shaders\lupkd2td.l4s~
Name       : lupkd2td.l4s~

I tried looking on line through all the documentation and printing all the values and I am not sure what I am doing wrong.

This is my script below, it mostly works but I can't really do anything too interesting with it unless I can actually see the file that triggered the change. Thanks for any help!

$global:should_quit = $false

function Watch-File {
    [cmdletbinding()]
    Param (
        [string]
        $Path
    )
    $fileWatcher = New-Object System.IO.FileSystemWatcher
    $fileWatcher.Path = $Path
    $fileWatcher.Filter = "*.*"
    $fileWatcher.IncludeSubdirectories = $false
    $fileWatcher.EnableRaisingEvents = $true
    Write-Host "Watching $fileWatcher.Path"
    $action = {
        Write-Host ($Event | Format-Table | Out-String)
        Write-Host ($Event | Format-List | Out-String)
        Write-Host ($EventArgs | Format-Table | Out-String)
        Write-Host ($EventArgs | Format-List | Out-String)
        $start = Get-Date
        $message = "Building shaders"
        Write-Host $message 
        try {
            $output = &.\script_compile.ps1
            if ($LASTEXITCODE -ne 0) {
                Write-Host "Shader compilation failed; $output"
                $global:should_quit = $true
                exit 1
            }
        }
        catch {
            Write-Error "Failed to execute shader compilation: $_"
        }
        $done = Get-Date
        $res = $done - $start
        $Error | Get-Error
        $end_message = "Finished in $($res.TotalSeconds) seconds"
        Write-Host $end_message 
    }

$eventJob = Register-ObjectEvent -InputObject $fileWatcher -EventName "Changed" -Action $action

Write-Host "Monitoring shaders for changes at: $Path. Press Ctrl+C to stop."

    try {
        while ($true) {
            Start-Sleep -Seconds 1
            if ($global:should_quit) {
                Write-Host "quitting"
                exit 0
            } 
        }
    }
    finally {
        if ($eventJob) {
             Unregister-Event -SourceIdentifier $eventJob.Name
             Remove-Job -Job $eventJob -Force
        }
        $fileWatcher.EnableRaisingEvents = $false
    }
}
Watch-File $PSScriptRoot

This is the directory contents that I am watching:

ls

    Directory: C:\Users\Bjorn\source\repos\btipling\Rosy\src\shaders

Mode                 LastWriteTime         Length Name
d----           1/18/2025 11:13 PM                out
-a---           1/18/2025 11:39 PM            736 basic.slang
-a---           1/18/2025 11:06 PM           2420 data.slang
-a---           1/17/2025  2:08 AM            645 debug.slang
-a---           1/19/2025 12:38 AM           2467 mesh.slang
-a---           1/17/2025  2:08 AM           1217 pcf.slang
-a---           1/19/2025 12:22 AM            813 script_compile.ps1
-a---           1/19/2025 12:35 AM           2030 script_shader_watcher.ps1
-a---           1/18/2025  9:25 PM            785 shadow.slang
-a---           1/17/2025  2:08 AM            449 skybox_cube.slang
-a---           1/17/2025  2:08 AM            724 skybox.slang
cobalt oxide
#

If that's the paths being output then they sound like temporary files that something like git or some other tool might be adding then immediately removing

#

Just an FYI if you are just wanting to wait for the events you can simplify things by not using -Action. For example

$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = 'C:\temp\test'
$watcher.IncludeSubdirectories = $true

$eventSourceId = (New-Guid).Guid
Register-ObjectEvent -InputObject $watcher -EventName Created -SourceIdentifier $eventSourceId
try {
    # Only enable the watcher after the event is subscribed to
    $watcher.EnableRaisingEvents = $true

    while ($true) {
        # Waits for the event to fire
        $watchEvent = Wait-Event -SourceIdentifier $eventSourceId
        # Remove the event from the queue
        $watchEvent | Remove-Event

        # Process the event as your did normally
        $path = $watchEvent.SourceEventArgs.FullPath
        $changeType = $watchEvent.SourceEventArgs.ChangeType

        Write-Host "Change detected: $changeType - $path"

        # Add in whatever logic here to break the loop if you want
        # to stop watching
    }
}
finally {
    # Will unregister the event watcher subscription at the end
    Unregister-Event -SourceIdentifier $eventSourceId
}
#

No need to mess with $global scoped vars to bring the state from the action back into the main loop and IMO it makes it easier to reason with the code

edgy ingot
#

with regards to the file names, I thought maybe it was a string encoding issue or something, I literally never see the actual files I change show up and am not aware of git writing temporary files in this directory

cobalt oxide
#

If it was an encoding problem typically the characters would probably contain other languages like Chinese characters and so on. The names listed are very similar to what the .NET API [System.IO.Path]::GetRandomFileName() returns which tells me there's some sort of process writing those. Maybe your editor or something else.