Das Skript dient dazu die Laufwerke remote, mittels RemoteRegistry, von einem Client in der Domäne auszulesen .
$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.
$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
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
- '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 (0–9)
- '{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
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
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() }
}
}