From ee8bc83baf99c450cc88c0500df3c3fd9d541be4 Mon Sep 17 00:00:00 2001 From: Gabe Date: Wed, 1 Jul 2026 18:53:46 +0000 Subject: [PATCH] Upload files to "Test Scripts" --- ...ng powershell version of filetree size.ps1 | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 Test Scripts/testing powershell version of filetree size.ps1 diff --git a/Test Scripts/testing powershell version of filetree size.ps1 b/Test Scripts/testing powershell version of filetree size.ps1 new file mode 100644 index 0000000..e7f9c3a --- /dev/null +++ b/Test Scripts/testing powershell version of filetree size.ps1 @@ -0,0 +1,215 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Tree-style folder size analysis with depth + minimum size filtering. +.DESCRIPTION + Scans a starting path, calculates folder sizes up to a specified depth, + and outputs a readable tree list (indented paths) for folders >= MinSize. + + Defaults: + - Path : C:\ + - Depth : 3 + - MinSize: 500MB + + Supports MinSize as: + - numeric bytes (e.g., 1073741824) + - string with units (e.g., "1GB", "750MB", "200KB") + + Optional environment-variable overrides (RMM friendly): + - ROOT_PATH + - DEPTH + - MIN_SIZE +#> + +[CmdletBinding()] +param( + [Parameter(Position = 0)] + [string] $Path = "C:\", + + [ValidateRange(1, 256)] + [int] $Depth = 3, + + [object] $MinSize = "500MB" +) + +begin { + + function Test-IsAdminOrSystem { + try { + $id = [Security.Principal.WindowsIdentity]::GetCurrent() + + # SYSTEM check (PS 5.1 safe) + if ($id.Name -eq 'NT AUTHORITY\SYSTEM') { + return $true + } + + $principal = New-Object Security.Principal.WindowsPrincipal($id) + return $principal.IsInRole( + [Security.Principal.WindowsBuiltInRole]::Administrator + ) + } + catch { + return $false + } + } + + function Convert-ToBytes { + param([Parameter(Mandatory)][object]$Value) + + if ($null -eq $Value) { return [int64]0 } + + if ($Value -is [byte] -or + $Value -is [int] -or + $Value -is [long] -or + $Value -is [int64] -or + $Value -is [double] -or + $Value -is [decimal]) { + return [int64]$Value + } + + $s = ($Value.ToString()).Trim() + + $m = [regex]::Match( + $s, + '^\s*(?\d+(\.\d+)?)\s*(?bytes|b|kb|mb|gb|tb|pb)?\s*$', + 'IgnoreCase' + ) + + if (-not $m.Success) { + throw "Invalid MinSize value: $s" + } + + $num = [double]$m.Groups['num'].Value + $unit = $m.Groups['unit'].Value.ToLower() + + switch ($unit) { + '' { return [int64]$num } + 'b' { return [int64]$num } + 'bytes' { return [int64]$num } + 'kb' { return $num * 1KB } + 'mb' { return $num * 1MB } + 'gb' { return $num * 1GB } + 'tb' { return $num * 1TB } + 'pb' { return $num * 1PB } + default { return [int64]$num } + } + } + + function Format-Bytes { + param([int64]$Bytes) + + $units = @("Bytes","KB","MB","GB","TB","PB") + $value = [double]$Bytes + $i = 0 + + while ($value -ge 1024 -and $i -lt ($units.Count - 1)) { + $value /= 1024 + $i++ + } + + if ($i -eq 0) { + return "{0:0} {1}" -f $value, $units[$i] + } + + return "{0:N2} {1}" -f $value, $units[$i] + } + + # Environment overrides + if ($env:ROOT_PATH) { $Path = $env:ROOT_PATH } + if ($env:DEPTH) { $Depth = [int]$env:DEPTH } + if ($env:MIN_SIZE) { $MinSize = $env:MIN_SIZE } + + try { + $Path = (Get-Item -LiteralPath $Path -ErrorAction Stop).FullName + } + catch { + throw "Path '$Path' does not exist or is not accessible." + } + + if (-not $Path.EndsWith('\')) { + $Path += '\' + } + + $MinBytes = Convert-ToBytes $MinSize + + if (-not (Test-IsAdminOrSystem)) { + Write-Warning "Not running as Administrator or SYSTEM. Sizes may be understated." + } + + function Get-FolderSizeAtDepth { + param( + [string] $Folder, + [int] $DepthLeft + ) + + $node = [PSCustomObject]@{ + Name = $Folder + Bytes = 0 + Children = @() + } + + if ($DepthLeft -le 1) { + try { + $node.Bytes = ( + Get-ChildItem -LiteralPath $Folder -File -Recurse -Force -ErrorAction SilentlyContinue | + Measure-Object -Property Length -Sum + ).Sum + } + catch { + $node.Bytes = 0 + } + + return $node + } + + $items = Get-ChildItem -LiteralPath $Folder -Force -ErrorAction SilentlyContinue | + Where-Object { -not ($_.Attributes -band [IO.FileAttributes]::ReparsePoint) } + + foreach ($item in $items) { + if ($item.PSIsContainer) { + $child = Get-FolderSizeAtDepth -Folder $item.FullName -DepthLeft ($DepthLeft - 1) + $node.Bytes += $child.Bytes + $node.Children += $child + } + else { + $node.Bytes += $item.Length + } + } + + return $node + } + + function Emit-Tree { + param( + $Node, + [string] $BasePath, + [int] $Level + ) + + $relative = $Node.Name + if ($relative.StartsWith($BasePath, 'OrdinalIgnoreCase')) { + $relative = ".\" + $relative.Substring($BasePath.Length) + } + + $indent = ' ' * (($Level + 1) * 2) + + [PSCustomObject]@{ + Path = $indent + $relative + Size = Format-Bytes $Node.Bytes + Bytes = $Node.Bytes + Depth = $Level + } + + foreach ($child in $Node.Children) { + Emit-Tree -Node $child -BasePath $BasePath -Level ($Level + 1) + } + } +} + +process { + $root = Get-FolderSizeAtDepth -Folder $Path -DepthLeft $Depth + + Emit-Tree -Node $root -BasePath $Path -Level 0 | + Where-Object { $_.Bytes -ge $MinBytes } | + Select-Object Path, Size +} \ No newline at end of file