多用户AD管理GUI日志写入问题:StreamWriter引发权限拒绝
Got it, let's break down what's happening here and fix it.
The root issue is that your current StreamWriter initialization uses the default constructor, which opens the file in exclusive access mode (FileShare.None). Once the first user opens the log file, it gets locked—any subsequent attempts to write to it will throw a permission-denied error (even though it's really a file lock conflict, not a true permission problem).
Here's how to fix this step by step:
1. Replace the StreamWriter setup with shared access
Instead of directly instantiating StreamWriter with just the file path, use [System.IO.File]::Open() to explicitly set a shared access mode that allows multiple users to write to the file simultaneously. We'll use FileMode.Append to avoid overwriting existing logs, and FileShare.ReadWrite to let other processes access the file while we're writing.
Here's the modified code:
$File = Join-Path -Path $LogPath -ChildPath "$LogDate.log" $fileStream = $null $stream = $null try { # Open the file with append mode and shared read/write access $fileStream = [System.IO.File]::Open( $File, [System.IO.FileMode]::Append, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite ) $stream = New-Object System.IO.StreamWriter($fileStream) # Write your log entries $stream.WriteLine("----------------------------------------------------") $stream.WriteLine("$LogTime $ExecUser | Set expire date for user $se...") $stream.Flush() # Ensure all data is written to disk immediately } finally { # Always clean up resources to avoid lingering file locks if ($stream) { $stream.Close() } if ($fileStream) { $fileStream.Close() } }
2. Optional: Prevent log entry interleaving
With shared access, there's a small chance that two users writing at the exact same time could have their log lines mixed together (e.g., half of one line followed by half of another). To fix this, add a global mutex to ensure only one process writes to the file at a time:
$mutexName = "Global\ADToolLogMutex" # The "Global\" prefix makes it visible across user sessions $mutex = New-Object System.Threading.Mutex($false, $mutexName) $File = Join-Path -Path $LogPath -ChildPath "$LogDate.log" $fileStream = $null $stream = $null try { # Wait up to 5 seconds for the mutex (adjust as needed) if ($mutex.WaitOne(5000)) { # Same file opening/writing code as above $fileStream = [System.IO.File]::Open( $File, [System.IO.FileMode]::Append, [System.IO.FileAccess]::Write, [System.IO.FileShare]::ReadWrite ) $stream = New-Object System.IO.StreamWriter($fileStream) $stream.WriteLine("----------------------------------------------------") $stream.WriteLine("$LogTime $ExecUser | Set expire date for user $se...") $stream.Flush() } else { # Handle timeout case (e.g., log to a temporary file or show an error) Write-Error "Could not acquire log write lock within 5 seconds. Log entry may be lost." } } finally { # Clean up all resources if ($stream) { $stream.Close() } if ($fileStream) { $fileStream.Close() } $mutex.ReleaseMutex() $mutex.Close() }
Key Notes:
- Always clean up streams: Failing to close
StreamWriterandFileStreamcan leave the file locked indefinitely, even after your tool exits. Thetry/finallyblock ensures this happens regardless of errors. - Append mode: Using
FileMode.Appendensures you never overwrite existing log data, which is critical for audit trails. - Global mutex: The
Global\prefix is important if your tool is used by users in different terminal services sessions—without it, the mutex would only be visible to the current user's processes.
That should resolve the permission-denied errors and let all users write to the same log file safely!
内容的提问来源于stack exchange,提问作者Kamil Maciejewski

