Private/PowerTree/Scanning/Get-TreeSnapshot.ps1
|
function Get-TreeSnapshot { param( [Parameter(Mandatory=$true)] [object]$TreeConfig, [Parameter(Mandatory=$true)] [hashtable]$ChildItemFileParams ) $resolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($TreeConfig.Path) $root = [TreeNode]::new([System.IO.DirectoryInfo]::new($resolvedPath), 0) $root.CanRenderContents = $TreeConfig.MaxDepth -ne 0 $includePatterns = if ($ChildItemFileParams.ContainsKey("Include")) { @($ChildItemFileParams.Include) } else { @() } $excludePatterns = if ($ChildItemFileParams.ContainsKey("Exclude")) { @($ChildItemFileParams.Exclude) } else { @() } $hiddenAttributes = [System.IO.FileAttributes]::Hidden -bor [System.IO.FileAttributes]::System $needFullSizes = $TreeConfig.HeaderTable.HeaderColumns -contains "Size" -or ($TreeConfig.SortFolders -and $TreeConfig.SortBy -eq "Size") $needPostProcessing = $needFullSizes -or $TreeConfig.PruneEmptyFolders $sortDirection = if ($TreeConfig.SortDescending) { -1 } else { 1 } $sortBy = $TreeConfig.SortBy $fileComparison = [System.Comparison[System.IO.FileInfo]] { param($left, $right) $comparison = switch ($sortBy) { "Modification Date" { [datetime]::Compare($left.LastWriteTime, $right.LastWriteTime) } "Creation Date" { [datetime]::Compare($left.CreationTime, $right.CreationTime) } "Last Access Date" { [datetime]::Compare($left.LastAccessTime, $right.LastAccessTime) } "Size" { $left.Length.CompareTo($right.Length) } default { [StringComparer]::CurrentCultureIgnoreCase.Compare($left.Name, $right.Name) } } return $comparison * $sortDirection } $directoryComparison = [System.Comparison[object]] { param($left, $right) $comparison = switch ($sortBy) { "Modification Date" { [datetime]::Compare($left.Item.LastWriteTime, $right.Item.LastWriteTime) } "Creation Date" { [datetime]::Compare($left.Item.CreationTime, $right.Item.CreationTime) } "Last Access Date" { [datetime]::Compare($left.Item.LastAccessTime, $right.Item.LastAccessTime) } "Size" { $left.Size.CompareTo($right.Size) } default { [StringComparer]::CurrentCultureIgnoreCase.Compare($left.Item.Name, $right.Item.Name) } } return $comparison * $sortDirection } $nodes = $null if ($needPostProcessing) { $nodes = [System.Collections.Generic.List[object]]::new() } $pending = [System.Collections.Generic.Stack[object]]::new() $pending.Push($root) while ($pending.Count -gt 0) { $node = $pending.Pop() if ($needPostProcessing) { $nodes.Add($node) } if (-not $node.CanRenderContents -and -not $needFullSizes) { continue } $files = [System.Collections.Generic.List[System.IO.FileInfo]]::new() $directories = [System.Collections.Generic.List[object]]::new() try { foreach ($item in $node.Item.EnumerateFileSystemInfos()) { if (-not $TreeConfig.ShowHiddenFiles -and ($item.Attributes -band $hiddenAttributes)) { continue } if ($item -is [System.IO.DirectoryInfo]) { $child = [TreeNode]::new($item, $node.Depth + 1) $child.IsVisible = $node.CanRenderContents -and $TreeConfig.ExcludeDirectories -notcontains $item.Name $child.CanRenderContents = $child.IsVisible -and ($TreeConfig.MaxDepth -eq -1 -or $child.Depth -lt $TreeConfig.MaxDepth) $directories.Add($child) if (($child.CanRenderContents -or $needFullSizes) -and -not ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint)) { $pending.Push($child) } continue } if ($item -isnot [System.IO.FileInfo]) { continue } if ($needFullSizes) { $node.DirectSize += $item.Length } if (-not $node.CanRenderContents) { continue } $included = $includePatterns.Count -eq 0 foreach ($pattern in $includePatterns) { if ($item.Name -like $pattern) { $included = $true break } } if (-not $included) { continue } $excluded = $false foreach ($pattern in $excludePatterns) { if ($item.Name -like $pattern) { $excluded = $true break } } if ($excluded) { continue } if ($TreeConfig.FileSizeBounds.ShouldFilter) { if ($TreeConfig.FileSizeBounds.LowerBound -ge 0 -and $item.Length -lt $TreeConfig.FileSizeBounds.LowerBound) { continue } if ($TreeConfig.FileSizeBounds.UpperBound -ge 0 -and $item.Length -gt $TreeConfig.FileSizeBounds.UpperBound) { continue } } $node.HasFilteredFiles = $true if (-not $TreeConfig.DirectoryOnly) { $files.Add($item) } } } catch { Write-Verbose "Could not enumerate '$($node.Item.FullName)': $($_.Exception.Message)" } if ($files.Count -gt 1) { $files.Sort($fileComparison) } if ($TreeConfig.FileLimit -eq 0) { $files.Clear() } elseif ($TreeConfig.FileLimit -gt 0 -and $files.Count -gt $TreeConfig.FileLimit) { $files.RemoveRange($TreeConfig.FileLimit, $files.Count - $TreeConfig.FileLimit) } if ($TreeConfig.SortFolders -and $TreeConfig.SortBy -ne "Size" -and $directories.Count -gt 1) { $directories.Sort($directoryComparison) } $node.Files = $files.ToArray() $node.Directories = $directories.ToArray() } if (-not $needPostProcessing) { return $root } $nodeArray = $nodes.ToArray() [array]::Reverse($nodeArray) foreach ($node in $nodeArray) { $node.Size = $node.DirectSize foreach ($child in $node.Directories) { $node.Size += $child.Size if ($child.IsVisible -and $child.HasVisibleContent) { $node.HasVisibleContent = $true } } if ($node.HasFilteredFiles) { $node.HasVisibleContent = $true } if ($TreeConfig.SortFolders -and $TreeConfig.SortBy -eq "Size" -and $node.Directories.Count -gt 1) { $directories = [System.Collections.Generic.List[object]]::new() $directories.AddRange($node.Directories) $directories.Sort($directoryComparison) $node.Directories = $directories.ToArray() } } return $root } |