|
Open the start menu, search for "Powershell" and right-click on "Windows Powershell ISE", click "Run as Administrator". Paste the below commands into it, click on the green Play icon in the toolbar or press F5 to run it. Enter the drive letter for the drive you want to check like "C" or "D" and hit enter.
Copy to Clipboard
param (
[Parameter(Mandatory=$true)]
[string]$DriveLetter = "D"
)
# Ensure the drive letter ends with a backslash
if ($DriveLetter -notlike "*:\") { $DriveLetter = "$($DriveLetter):\" }
if (-not (Test-Path $DriveLetter)) {
Write-Host "Drive $DriveLetter not found. Make sure the drive is connected and the letter is correct." -ForegroundColor Red
return
}
$UserBasePath = Join-Path $DriveLetter "Users"
if (-not (Test-Path $UserBasePath)) {
Write-Host "No Users folder found on $DriveLetter. This may not be a Windows system drive." -ForegroundColor Red
return
}
$UserFolders = Get-ChildItem -Path $UserBasePath -Directory
foreach ($UserFolder in $UserFolders) {
$UserName = $UserFolder.Name
$UserPath = $UserFolder.FullName
$NtUserPath = Join-Path $UserPath "NTUSER.DAT"
Write-Host "`n--- Checking Profile: $UserName ---" -ForegroundColor Cyan
# 1. Get Folder Breakdown & Disk Usage
Write-Host "Calculating Disk Usage (Size on Disk)..."
$FolderStats = Get-ChildItem -Path $UserPath -Directory | ForEach-Object {
$Files = Get-ChildItem -Path $_.FullName -Recurse -File -ErrorAction SilentlyContinue
# 'Length' is the actual file size (Total Usage)
$TotalSize = ($Files | Measure-Object -Property Length -Sum).Sum / 1GB
# Note: In PowerShell, measuring "Size on Disk" for dehydrated cloud files
# usually returns 0 or a very small header size if the file isn't local.
$LocalSize = ($Files | Where-Object { $_.Attributes -notmatch "Offline" } | Measure-Object -Property Length -Sum).Sum / 1GB
[PSCustomObject]@{
FolderName = $_.Name
TotalSizeGB = [math]::Round($TotalSize, 2)
LocalSizeGB = [math]::Round($LocalSize, 2)
}
}
$FolderStats | Format-Table -AutoSize
# 2. Extract OneDrive Email (Offline Registry Load)
if (Test-Path $NtUserPath) {
$HiveLoaded = $false
# If scanning C:\ and this folder belongs to the current user, the hive is
# already loaded by Windows under the user's SID — load it again would fail.
$IsCurrentUser = ($DriveLetter -eq "C:\") -and ($UserName -eq $env:USERNAME)
if ($IsCurrentUser) {
$HiveName = [System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
Write-Host "Using existing loaded hive (current user: SID $HiveName)" -ForegroundColor DarkGray
} else {
# Use Win32 API to check for a stale key — avoids opening a PS provider handle
$HiveName = "TempHive_$UserName"
$Counter = 0
while ($true) {
$checkKey = [Microsoft.Win32.Registry]::Users.OpenSubKey($HiveName)
if ($null -eq $checkKey) { break }
$checkKey.Close(); $checkKey.Dispose()
$Counter++
$HiveName = "TempHive_${UserName}_$Counter"
}
}
try {
if (-not $IsCurrentUser) {
reg load "HKU\$HiveName" "$NtUserPath" 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
Write-Warning "Could not load registry hive for $UserName (file may be locked by an active session)."
} else {
$HiveLoaded = $true
}
}
if ($IsCurrentUser -or $HiveLoaded) {
# Use Win32 RegistryKey directly so every handle can be explicitly closed
# before the unload attempt — the PS registry provider caches handles
# internally and ignores GC, which is what causes the unload to fail.
$personalKey = [Microsoft.Win32.Registry]::Users.OpenSubKey(
"$HiveName\Software\Microsoft\OneDrive\Accounts\Personal")
if ($null -ne $personalKey) {
$foundEmail = $false
$email = $personalKey.GetValue("UserEmail")
if ($email) {
Write-Host "OneDrive Logged in as: $email" -ForegroundColor Green
$foundEmail = $true
}
foreach ($subKeyName in $personalKey.GetSubKeyNames()) {
$subKey = $personalKey.OpenSubKey($subKeyName)
$subEmail = $subKey.GetValue("UserEmail")
$subKey.Close(); $subKey.Dispose()
if ($subEmail) {
Write-Host "OneDrive Logged in as: $subEmail" -ForegroundColor Green
$foundEmail = $true
}
}
if (-not $foundEmail) {
Write-Host "OneDrive key found but no email address stored." -ForegroundColor Yellow
}
$personalKey.Close()
$personalKey.Dispose()
} else {
Write-Host "OneDrive account info not found in registry." -ForegroundColor Yellow
}
}
}
catch {
Write-Warning "Could not read registry hive for $UserName`: $_"
}
finally {
if ($HiveLoaded) {
$MaxRetries = 5
$Unloaded = $false
for ($i = 0; $i -lt $MaxRetries; $i++) {
[gc]::Collect()
[gc]::WaitForPendingFinalizers()
reg unload "HKU\$HiveName" 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) {
$Unloaded = $true
break
}
Start-Sleep -Milliseconds 500
}
if (-not $Unloaded) {
Write-Warning "Could not unload hive HKU\$HiveName after $MaxRetries attempts. Run: reg unload `"HKU\$HiveName`""
}
}
}
}
else {
if ($UserName -ne "Public") {
Write-Warning "NTUSER.DAT not found for $UserName."
}
}
}
|