2️⃣. PS – Get-MappedDrives

Das Skript dient dazu die Laufwerke remote, mittels RemoteRegistry, von einem Client in der Domäne auszulesen .

PowerShell
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $computer)

Das Grundskript ist recht simple aufgebaut. Es wird Remote auf dem Client unter HKEY_USERS nachgesehen. Diese Hive enthält Benutzerprofile (SIDs) und damit auch deren gemappte Laufwerke.

PowerShell
$reg.GetSubKeyNames() | ? {$_ -match '\d{4,5}$'}

Der Bereich filtert nur SIDs (Security Identifier), die auf eine Ziffernfolge enden, z. B. S-1-5-21-...-1001. Das sind in der Regel die aktiven Benutzerprofile (statt z. B. .DEFAULT oder Classes).

🚀 Die erste Version vom Skript

PowerShell
function Get-MappedDrives {
    param (
        $computer = $env:COMPUTERNAME
    )

    $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $computer)
    $reg.GetSubKeyNames() | ? {$_ -match '\d{4,5}$'} | % {
        $sid = $_
        $reg.OpenSubKey("$sid\Network").GetSubKeyNames() | % {
            New-Object psobject -Property @{
                Computer = $computer
                User = ([System.Security.Principal.SecurityIdentifier]($sid)).Translate([System.Security.Principal.NTAccount]).Value
                DriveLetter = $_
                Map = $reg.OpenSubKey("$sid\Network\$_").GetValue('RemotePath')
            }
        }
    }
}

📖Legende zur Funktion Get-MappedDrives

PowerShell
- 'param ($computer = $env:COMPUTERNAME)' -- Standardmäßig wird der lokale Computer verwendet, kann aber überschrieben werden
- '[Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $computer)' -- Öffnet die Registry-Hive HKEY_USERS des angegebenen Computers (lokal oder remote)
- '?' -- ist ein Alias für Where-Object. Es filtert also die Liste.
- '%' -- ist ein Alias für foreach
- '$_' -- ist das aktuelle Element in der Pipeline (also ein Schlüsselname wie S-1-5-  21-...-1000).
- "-match '\d{4,5}$'" --  prüft per Regulärem Ausdruck (Regex), ob das Ende des Strings aus genau 4 oder 5 Ziffern besteht
- '$reg.GetSubKeyNames()' = Listet alle SIDs (Benutzer und Systemkonten), die in der Registry vertreten sind
- '$reg.OpenSubKey("$sid\Network")' -- Greift auf Registry-Schlüssel zu, in denen Windows Netzlaufwerk-Zuordnungen speichert
- '.GetSubKeyNames()' -- Holt die Laufwerksbuchstaben, z. B. Z, P, etc.
- '([SecurityIdentifier]$sid).Translate([NTAccount])' -- Wandelt die SID in einen Benutzernamen um (z. B. DOMAIN\Max.Mustermann)
- ".GetValue('RemotePath')" -- Liest den Pfad des gemappten Netzlaufwerks aus, z. B. \\server\freigabe
- 'New-Object psobject -Property @{ ... }' -- Baut ein Objekt mit den Informationen: Computer, Benutzer, Laufwerksbuchstabe, Pfad


regex:
- '\d' -- eine Ziffer (09)
- '{4,5}' -- genau 4 oder 5 Ziffern
- '$' -- Am ende des Strings

Da das Skript noch sehr rudimentär ist, sollte man dieses noch erweitern und Fehlerhandling, sowie Performance verbessern. Die Perfomance kann man alleine dadurch verbessern, dass wir vorher einen Ping an den Host senden, bevor wir versuchen Remote auf die Registry zuzugreifen.

🔍 Die Komplette Funktion

PowerShell
function Get-MappedDrives {
    param (
        [string]$computer = $env:COMPUTERNAME
    )

    # Prüfe ob der Host erreichbar ist, bevor weitermachen
    try {
        if (-not (Test-Connection -ComputerName $computer -Count 1 -Quiet -ErrorAction Stop)) {
            Write-Warning "Computer '$computer' ist nicht erreichbar."
            return
        }
    }
    catch {
        Write-Warning "Verbindungsfehler zu '$computer': $_"
        return
    }

    # Sammle zuerst alle Daten in einer Hashtable, gruppiert nach Benutzern
    $userDrives = @{}

    try {
        $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $computer)
        
        $reg.GetSubKeyNames() | ? {$_ -match '\d{4,5}$'} | % {
            $sid = $_
            $networkKey = $reg.OpenSubKey("$sid\Network")
            
            if ($networkKey) {
                try {
                    # Wandle SID in Benutzername um - nur einmal pro Benutzer
                    $userName = ([System.Security.Principal.SecurityIdentifier]($sid)).Translate([System.Security.Principal.NTAccount]).Value
                    
                    # Erstelle einen Eintrag für diesen Benutzer, falls noch nicht vorhanden
                    if (-not $userDrives.ContainsKey($userName)) {
                        $userDrives[$userName] = @()
                    }
                    
                    $networkKey.GetSubKeyNames() | % {
                        $driveLetter = $_
                        $driveKey = $networkKey.OpenSubKey($driveLetter)
                        
                        if ($driveKey) {
                            $driveInfo = New-Object psobject -Property @{
                                Computer = $computer
                                User = $userName
                                DriveLetter = $driveLetter
                                Map = $driveKey.GetValue('RemotePath')
                            }
                            
                            # Füge die Laufwerksinformation zum Array dieses Benutzers hinzu
                            $userDrives[$userName] += $driveInfo
                            
                            # Ressourcen freigeben
                            $driveKey.Close()
                        }
                    }
                }
                catch {
                    Write-Verbose "Fehler bei Verarbeitung von SID '$sid': $_"
                }
                
                # Ressourcen freigeben
                $networkKey.Close()
            }
        }
        
        # Ausgabe der nach Benutzern gruppierten Daten
        $userDrives.GetEnumerator() | % {
            $userName = $_.Key
            Write-Output "Netzlaufwerke für Benutzer: $userName"
            Write-Output "----------------------------------------"
            $_.Value | Format-Table -AutoSize
            Write-Output ""
        }
    }
    catch {
        Write-Error "Fehler beim Zugriff auf den Computer '$computer': $_"
    }
    finally {
        if ($reg) { $reg.Close() }
    }
}

Da man im Best Practice die Verwendung von Aliasen vermeidet. Hier noch mal das Skript mit volle Cmdlet-Schreibweise. Und natürlich das Kommentarbasiertes Help-System um die Bedienung für neue Benutzer zu erleichtern.

📃Das Fertige Skript

PowerShell
function Get-MappedDrives {
<#
.SYNOPSIS
    Retrieves mapped network drives for all users on a remote computer.

.DESCRIPTION
    Connects to the remote registry of a specified computer to enumerate network drives
    mapped under all user SIDs found in the HKU hive.

.PARAMETER ComputerName
    The target computer name. Defaults to the local computer.

.EXAMPLE
    Get-MappedDrives -ComputerName SRV-01

.NOTES
    Requires the Remote Registry service to be running on the target machine.
    Dateiname:      Get-MappedDrives.ps1
    Autor:          Ismahil Ahmed
    Erstelldatum:   19.02.2022
    Version:        1.0
    

#>

    [CmdletBinding()]  
    param (
        [Parameter(Position = 0)]
        [string]$ComputerName = $env:COMPUTERNAME  
    )

    try {
        if (-not (Test-Connection -ComputerName $ComputerName -Count 1 -Quiet -ErrorAction Stop)) {
            Write-Warning "Computer '$ComputerName' is not reachable."
            return
        }
    }
    catch {
        Write-Warning "Connection error to '$ComputerName': $_"
        return
    }

    $userDrives = @{}

    try {
        $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Users', $ComputerName)

        $reg.GetSubKeyNames() | Where-Object { $_ -match '\d{4,5}$' } | ForEach-Object {  
            $sid = $_
            $networkKey = $reg.OpenSubKey("$sid\Network")

            if ($networkKey) {
                try {
                    $userName = ([System.Security.Principal.SecurityIdentifier]$sid).Translate([System.Security.Principal.NTAccount]).Value

                    if (-not $userDrives.ContainsKey($userName)) {
                        $userDrives[$userName] = @()
                    }

                    $networkKey.GetSubKeyNames() | ForEach-Object {
                        $driveLetter = $_
                        $driveKey = $networkKey.OpenSubKey($driveLetter)

                        if ($driveKey) {
                            $driveInfo = [PSCustomObject]@{
                                Computer    = $ComputerName
                                User        = $userName
                                DriveLetter = $driveLetter
                                Map         = $driveKey.GetValue('RemotePath')
                            }

                            $userDrives[$userName] += $driveInfo
                            $driveKey.Close()
                        }
                    }
                }
                catch {
                    Write-Verbose "Error processing SID '$sid': $_"  
                }
                $networkKey.Close()
            }
        }

        $userDrives.GetEnumerator() | ForEach-Object {
            $userName = $_.Key
            Write-Output "Mapped drives for user: $userName"
            Write-Output "----------------------------------------"
            $_.Value | Format-Table -AutoSize
            Write-Output ""
        }
    }
    catch {
        Write-Error "Error accessing computer '$ComputerName': $_"
    }
    finally {
        if ($reg) { $reg.Close() }
    }
}

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert