Zum Inhalt springen
>_marc-oltersdorf.de

Fileserver: Herausfinden, wer eine Datei geöffnet hat – auch hinter einem DFS-Namespace

Marc Oltersdorf 3 Min. Lesezeit

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

  1. 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.

  2. 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.

  3. 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.

  4. Lösung Get-SmbOpenFile per WinRM

    Gefiltert auf den Dateinamen lieferte es Benutzer, Rechner und lokalen Pfad des offenen Griffs.

  5. 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.

  6. 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$ lieferte False – die eigentliche Freigabe auf dem Server heißt anders als der Namensraum. Erst Get-SmbShare auf dem Kandidaten hat Klarheit gebracht.
  • DFS-Werkzeuge fehlen oft. Get-DfsnRootTarget war auf dem Admin-PC nicht vorhanden (die DFS-Verwaltungstools sind nicht installiert), dfsutil ebenso wenig. Der Weg über Get-SmbShare braucht nichts davon.
  • Lokaler Pfad, Großbuchstaben. Get-SmbOpenFile liefert den lokalen Pfad des Servers, hier komplett in Großbuchstaben. -like ist 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 \server statt \\server an. PowerShell las das als Pfad relativ zum Laufwerk und legte prompt einen leeren Ordner C:\server\… an. UNC-Pfade gehören deshalb in eine Skriptdatei, die mit -File aufgerufen wird.

Hat dir das geholfen?

RSS abonnieren

$ ls ../ Passt dazu