Files
infra-phytron/server/phy-srv-gpu01/scripts/list-shares.ps1
T
CubelaPetarandClaude Opus 4.8 75296ce58c Rename phy-z-srv-gpu01 to phy-srv-gpu01; fix share analysis scripts
- rename host/group/folder everywhere to match the server's actual
  hostname and physical label
- share-analysis.ps1: sanitize the output filename prefix — '-Paths "D:"'
  produced 'D:-file-types.csv' and Export-Csv failed with 'path format
  not supported', so no CSVs were written
- share-analysis.ps1: new -FolderDepth so folders can be aggregated at
  D:\Abteilungen\<Share> level, which matches the share layout
- list-shares.ps1: -WithSize walks local paths instead of UNC when run on
  the server itself (UNC was orders of magnitude slower and looked stuck)
  and prints progress every 50k files

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 14:47:07 +02:00

128 lines
4.9 KiB
PowerShell

<#
.SYNOPSIS
Lists all SMB shares of a Windows file server incl. local path, size and
permissions — the basis for the include/exclude decision (projektplan §2.6).
.DESCRIPTION
Run ON the file server (or against a remote one via -ComputerName). Reports
per share: name, local path, description, share-level permissions, NTFS
groups, plus optional size/file count. Admin shares (C$, ADMIN$, IPC$) are
skipped unless -IncludeAdminShares is given.
Purely read-only. Requires local admin for Get-SmbShare (part of Windows
Server, no extra module needed).
.EXAMPLE
.\list-shares.ps1
.EXAMPLE
# with size per share — run this ON the file server, it then walks the local
# paths instead of the UNC paths (far faster). Still minutes to hours on
# millions of files; progress is printed every 50k files.
.\list-shares.ps1 -WithSize
.NOTES
Faster alternative when all shares live under one drive (as on Z-FILESERVER,
where everything sits under D:): run share-analysis.ps1 once with a matching
folder depth instead of measuring every share separately, e.g.
.\share-analysis.ps1 -Paths "D:" -FolderDepth 2
That produces size/count per D:\Abteilungen\<Share> in a single pass over
the disk, which is what the share list here maps onto.
#>
param(
[string]$ComputerName = $env:COMPUTERNAME,
[switch]$IncludeAdminShares,
[switch]$WithSize,
[string]$OutDir = (Join-Path (Get-Location) "share-list")
)
$ErrorActionPreference = 'Continue'
New-Item -ItemType Directory -Path $OutDir -Force | Out-Null
Write-Host "=== SMB shares on $ComputerName ===" -ForegroundColor Cyan
$shares = Get-SmbShare -CimSession $ComputerName -ErrorAction Stop
if (-not $IncludeAdminShares) {
$shares = $shares | Where-Object { -not $_.Name.EndsWith('$') }
}
$result = foreach ($sh in $shares) {
Write-Host (" {0,-25} {1}" -f $sh.Name, $sh.Path)
# share-level permissions
$sharePerms = try {
(Get-SmbShareAccess -Name $sh.Name -CimSession $ComputerName -ErrorAction Stop |
ForEach-Object { "$($_.AccountName)=$($_.AccessRight)" }) -join '; '
} catch { 'n/a' }
# NTFS permissions (top level only) — who actually has access
$ntfsPerms = try {
$uncPath = "\\$ComputerName\$($sh.Name)"
((Get-Acl -LiteralPath $uncPath -ErrorAction Stop).Access |
ForEach-Object { "$($_.IdentityReference)=$($_.FileSystemRights)" } |
Select-Object -Unique | Select-Object -First 10) -join '; '
} catch { 'n/a' }
$sizeGB = $null; $fileCount = $null
if ($WithSize) {
# Walk the LOCAL path when we are on the server itself — going through
# the UNC path (\\server\share) routes every single file through the SMB
# stack and is slower by orders of magnitude on large shares.
$scanPath = if ($ComputerName -eq $env:COMPUTERNAME -and $sh.Path) {
$sh.Path
} else {
"\\$ComputerName\$($sh.Name)"
}
$sw = [System.Diagnostics.Stopwatch]::StartNew()
$n = 0L; $bytes = 0L
Get-ChildItem -LiteralPath $scanPath -Recurse -File -Force -ErrorAction SilentlyContinue |
ForEach-Object {
$n++; $bytes += $_.Length
if ($n % 50000 -eq 0) {
Write-Host (" ... {0:N0} files, {1:N1} GB ({2:N0}s)" -f $n, ($bytes / 1GB), $sw.Elapsed.TotalSeconds) -ForegroundColor DarkGray
}
}
$sw.Stop()
$sizeGB = [Math]::Round($bytes / 1GB, 2)
$fileCount = $n
Write-Host (" {0:N0} files, {1:N1} GB in {2:N0}s" -f $n, ($bytes / 1GB), $sw.Elapsed.TotalSeconds) -ForegroundColor DarkGray
}
[PSCustomObject]@{
Name = $sh.Name
Path = $sh.Path
Description = $sh.Description
SharePermissions = $sharePerms
NtfsPermissions = $ntfsPerms
SizeGB = $sizeGB
FileCount = $fileCount
}
}
$csv = Join-Path $OutDir "smb-shares.csv"
$result | Export-Csv $csv -NoTypeInformation -Encoding UTF8
$result | Format-Table Name, Path, SizeGB, FileCount -AutoSize
# DFS namespaces (if used) — often the path users actually see
Write-Host "`n=== DFS namespaces ===" -ForegroundColor Cyan
try {
$roots = Get-DfsnRoot -ErrorAction Stop
if ($roots) {
$dfs = foreach ($r in $roots) {
Get-DfsnFolder -Path "$($r.Path)\*" -ErrorAction SilentlyContinue | ForEach-Object {
$t = Get-DfsnFolderTarget -Path $_.Path -ErrorAction SilentlyContinue
[PSCustomObject]@{ DfsPath = $_.Path; Targets = ($t.TargetPath -join '; ') }
}
}
$dfs | Export-Csv (Join-Path $OutDir "dfs-namespaces.csv") -NoTypeInformation -Encoding UTF8
$dfs | Format-Table -AutoSize
} else { Write-Host " none" }
} catch {
Write-Host " no DFS role / not available on this host"
}
Write-Host "`nResults in: $OutDir" -ForegroundColor Green