Fileserver: Herausfinden, wer eine Datei geöffnet hat – auch hinter einem DFS-Namespace
Beim Verschieben einer CSV-Datei auf einer Windows-Freigabe meldete PowerShell, die Datei werde von einem anderen Prozess verwendet. Über Invoke-Command und Get-SmbOpenFile auf dem Fileserver ließ sich in Sekunden sehen, welches Konto sie von welchem Rechner aus geöffnet hatte. Der knifflige Teil war, hinter dem DFS-Pfad überhaupt den richtigen Server zu finden.
$ git log --graph Der Weg zur Lösung
-
Problem
Datei lässt sich auf der Freigabe nicht verschieben
Move-Item meldete, die CSV werde von einem anderen Prozess verwendet – ohne zu sagen, von wem.
-
Irrweg
Server hinter dem DFS-Pfad raten
Der Namensraum-Name war im DNS nicht auflösbar, Test-Path auf den vermuteten Server lieferte False, Get-DfsnRootTarget und dfsutil waren nicht installiert.
-
Erkenntnis
Get-SmbShare auf dem Kandidaten zeigt die Wahrheit
Per Invoke-Command die Freigaben des Servers abfragen: Die gesuchte Freigabe hieß anders als der Namensraum und zeigte auf einen lokalen D:-Pfad.
-
Lösung
Get-SmbOpenFile per WinRM
Gefiltert auf den Dateinamen lieferte es Benutzer, Rechner und lokalen Pfad des offenen Griffs.
-
Irrweg
UNC-Einzeiler aus Git Bash
Der doppelte Backslash ging bei der Übergabe an powershell.exe verloren und erzeugte einen leeren Ordner auf C:. Abhilfe: Skriptdatei mit -File.
-
Lösung
Datei schließen, dann verschieben
Close-SmbOpenFile nur für genau diese Datei, danach lief der Umzug durch.
Ich wollte Laufzeitdaten (ein paar CSV-Dateien) auf einer Windows-Dateifreigabe von einem Ordner in einen anderen verschieben. Fünf Dateien gingen durch, eine nicht:
FEHLER bei NeueBenutzer.csv: Der Prozess kann nicht auf die Datei zugreifen, da sie bereits von einem anderen Prozess verwendet wird.
Die Freigabe wird über einen DFS-Namespace angesprochen (\\domaene\namensraum$\…), auf dem eigenen Admin-PC läuft Windows PowerShell 5.1, der Fileserver ist per WinRM erreichbar.
Das Problem
Die Meldung sagt nur, dass jemand die Datei offen hat – nicht wer. Auf dem eigenen Rechner hilft weder der Task-Manager noch der Ressourcenmonitor, denn der Griff auf die Datei liegt beim Fileserver: Dort hält der SMB-Dienst die Sitzung des anderen Clients offen. Also muss die Frage auf dem Server gestellt werden – und dafür muss man erst einmal wissen, welcher Server hinter dem DFS-Pfad steckt.
Die Lösung
1. Den richtigen Server hinter dem DFS-Pfad bestätigen
Der Name des Namensraums ist kein Rechnername. Ich hatte einen Kandidaten im Kopf und habe mir auf ihm die Freigaben anzeigen lassen. Steht dort die gesuchte Freigabe samt lokalem Pfad, ist es der richtige Server:
$cred = Get-Credential
Invoke-Command -ComputerName fileserver -Credential $cred -ScriptBlock { Get-SmbShare | Where-Object Name -like 'freigabe*' | ForEach-Object { "$($_.Name) -> $($_.Path)" } }
Skripte$ -> D:\Daten\ordner\Skripte
Wichtig für den nächsten Schritt: Der Server kennt nur seinen lokalen Pfad (D:\…), nicht den DFS- oder UNC-Pfad.
2. Offene Dateien auf dem Server abfragen
Get-SmbOpenFile listet alle Dateien, die Clients über SMB geöffnet haben – mit Benutzer, Rechner und lokalem Pfad. Gefiltert wird deshalb auf den Dateinamen, nicht auf den UNC-Pfad:
Invoke-Command -ComputerName fileserver -Credential $cred -ScriptBlock { Get-SmbOpenFile | Where-Object Path -like '*Dateiname.csv' | Select-Object ClientUserName, ClientComputerName, Path, FileId }
ClientUserName ClientComputerName Path
-------------- ------------------ ----
DOMAENE\benutzer 192.0.2.8 D:\DATEN\ORDNER\SKRIPTE\...\NEUEBENUTZER.CSV
Damit war klar, wer die Datei offen hatte – in meinem Fall eine Kollegin bzw. ein Kollege mit der CSV in Excel. Ein Anruf hätte gereicht.
3. Falls nötig: die Datei serverseitig schließen
Wenn niemand erreichbar ist, lässt sich der Griff auf dem Server trennen – nur für genau diese Datei:
Invoke-Command -ComputerName fileserver -Credential $cred -ScriptBlock { Get-SmbOpenFile | Where-Object Path -like '*\ORDNER\DATEINAME.CSV' | Close-SmbOpenFile -Force }
Danach ließ sich die Datei verschieben, der zweite Lauf meldete „verschoben: NeueBenutzer.csv“.
Als kleines Skript
Weil ich das öfter brauche, liegt die Abfrage bei mir als Skript. Es zeigt zur Kontrolle die passenden Freigaben des Servers mit an – steht dort nichts, war es der falsche Server. Es liest nur und schließt nichts. Die Zugangsdaten holt es bei mir aus einem DPAPI-verschlüsselten Speicher; hier steht stattdessen Get-Credential.
param(
[string] $Server = 'fileserver',
[string] $Muster = '*Dateiname.csv'
)
$ErrorActionPreference = 'Stop'
$credential = Get-Credential
Write-Host "Server: $Server | Muster: $Muster" -ForegroundColor Cyan
$ergebnis = Invoke-Command -ComputerName $Server -Credential $credential -ArgumentList $Muster -ScriptBlock {
param($muster)
[PSCustomObject]@{
Freigaben = @(Get-SmbShare | Where-Object { $_.Name -like 'freigabe*' } |
ForEach-Object { "$($_.Name) -> $($_.Path)" })
Offen = @(Get-SmbOpenFile | Where-Object { $_.Path -like $muster } |
Select-Object ClientUserName, ClientComputerName, Path, FileId)
}
}
if ($ergebnis.Freigaben.Count -eq 0) {
Write-Host "Auf $Server gibt es keine passende Freigabe - vermutlich der falsche Server (-Server angeben)." -ForegroundColor Yellow
} else {
Write-Host "Freigaben auf ${Server}: $($ergebnis.Freigaben -join '; ')"
}
if ($ergebnis.Offen.Count -eq 0) {
Write-Host "Niemand hat eine passende Datei geöffnet." -ForegroundColor Green
} else {
$ergebnis.Offen | Format-Table ClientUserName, ClientComputerName, Path -AutoSize | Out-String -Width 250 | Write-Host
}
Warum das funktioniert
Eine über SMB geöffnete Datei ist aus Sicht des Fileservers eine offene Datei der SMB-Sitzung eines Clients. Der SMB-Server führt Buch darüber – Get-SmbOpenFile liest genau diese Liste, Close-SmbOpenFile trennt einen Eintrag. Weil die Cmdlets auf dem Server laufen müssen, kommen sie per Invoke-Command dorthin; auf dem eigenen PC gibt es dazu schlicht nichts zu sehen.
Stolperfallen
- DFS-Namensraum ist kein Server. Der Name im Pfad ließ sich im DNS nicht auflösen, und
Test-Path \\fileserver\namensraum$lieferteFalse– die eigentliche Freigabe auf dem Server heißt anders als der Namensraum. ErstGet-SmbShareauf dem Kandidaten hat Klarheit gebracht. - DFS-Werkzeuge fehlen oft.
Get-DfsnRootTargetwar auf dem Admin-PC nicht vorhanden (die DFS-Verwaltungstools sind nicht installiert),dfsutilebenso wenig. Der Weg überGet-SmbSharebraucht nichts davon. - Lokaler Pfad, Großbuchstaben.
Get-SmbOpenFileliefert den lokalen Pfad des Servers, hier komplett in Großbuchstaben.-likeist unabhängig von der Schreibweise, aber ein Filter auf den UNC-Pfad findet nie etwas. - UNC-Pfade aus Git Bash an
powershell.exe -Command. Ein Einzeiler aus Git Bash heraus kam mit\serverstatt\\serveran. PowerShell las das als Pfad relativ zum Laufwerk und legte prompt einen leeren OrdnerC:\server\…an. UNC-Pfade gehören deshalb in eine Skriptdatei, die mit-Fileaufgerufen wird.