Last active
October 19, 2023 02:36
-
-
Save jschlackman/05957a2a769ed17846e8e4c0a0feb23c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Name: Get-HtmlFolderReport.ps1 | |
# Author: James Schlackman | |
# Last Modified: October 18 2023 | |
# | |
# Outputs an HTML listing of all files in a specified folder, grouped in order by subfolder | |
Param( | |
[Parameter(Mandatory)] [String] $SearchPath, | |
[Parameter()] [String] $OutputPath = "$((Get-Date).ToString("yyMMdd")) $((Get-Item -Path $SearchPath).Name).html" | |
) | |
# Format file sizes with sensible units | |
Function Format-FileSize() { | |
Param ([int64]$size) | |
If ($size -gt 1TB) {[string]::Format("{0:0.00} TB", $size / 1TB)} | |
ElseIf ($size -gt 1GB) {[string]::Format("{0:0.00} GB", $size / 1GB)} | |
ElseIf ($size -gt 1MB) {[string]::Format("{0:0.0} MB", $size / 1MB)} | |
ElseIf ($size -gt 1KB) {[string]::Format("{0:0} KB", $size / 1KB)} | |
Else {[string]::Format("{0:0} B", $size)} | |
} | |
$fileTypeCache = @{} | |
# Get file type description from registry | |
function Get-FileType() { | |
param( | |
[Parameter(Mandatory)] [string] $extension | |
) | |
# Check if the file type description is already cached | |
If (!($fileTypeCache.ContainsKey($extension))) { | |
# If not, get it from the registry | |
$typeDesc = (Get-ItemProperty "Registry::HKEY_CLASSES_ROOT\$((Get-ItemProperty "Registry::HKEY_Classes_root\$($extension)")."(default)")")."(default)" | |
If ([bool]$typeDesc) | |
{ | |
$fileTypeCache.Add($extension, $typeDesc) | |
} Else { | |
# Generate a default description if there is no file type association | |
$fileTypeCache.Add($extension, "$extension File".Trim()) | |
} | |
} | |
# Return the description from the cache | |
$fileTypeCache[$extension] | |
} | |
# Get HTML representation of file listing for a single folder | |
function Export-HtmlFileList() { | |
param( | |
[Parameter(Mandatory)] [string] $DirectoryPath | |
) | |
$folderName = $DirectoryPath | |
If ($folderName -eq $SearchPath) { | |
$folderName = '(Root)' | |
} Else { | |
$folderName = $folderName.Substring($SearchPath.Length + 1) | |
} | |
# Return folder name heading | |
"<h2 id=""$($DirectoryPath.GetHashCode())"">📂 $folderName</h2>" | |
# Get listings of files in this folder and dirext subfolders | |
$subFolders = $allFolders | Where-Object {$_.Parent.FullName -eq $DirectoryPath} | |
$subFiles = $allFiles | Where-Object {$_.DirectoryName -eq $DirectoryPath} | |
# If the folder is not empty | |
If ([bool]$subFolders -or [bool]$subFiles) { | |
# Return a list of links to subfolders | |
If ([bool]$subFolders) { | |
"<p>Subfolders: $($subFolders.Count)<ul class=""folders"">`n" | |
$subFolders | ForEach-Object { | |
"<li><a href=#$($_.FullName.GetHashCode())>$($_.Name)</a></li>" | |
} | |
"</ul></p>" | |
} | |
If ([bool]$subFiles) { | |
$fileProperties = ` | |
@{Name='File Name';Expression={"📄 $($_.BaseName)"}}, | |
@{Name='File Type';Expression={Get-FileType($_.Extension)}}, | |
@{Name='Size';Expression={Format-FileSize $_.Length}}, | |
@{Name='Created';Expression={Get-Date -UFormat '%D' $_.CreationTime}}, | |
@{Name='Modified';Expression={Get-Date -UFormat '%D' $_.LastWriteTime}} | |
# Return file listing summary | |
"<p>Files: $($subFiles.Count)</br>Total size: $($(Format-FileSize ($subFiles | Measure-Object -Property Length -Sum).Sum))</p>" | |
# Return file listing table | |
"$(($subFiles | Select $fileProperties | ConvertTo-Html -Fragment))" | |
} | |
} Else {"<p><em>Empty folder</em></p>"} | |
} | |
If (!(Test-Path $SearchPath)) { | |
Write-Host "Folder not found: $SearchPath" -ForegroundColor Red | |
} Else { | |
# Search the entire specified folder | |
$searchResults = Get-ChildItem -Path $SearchPath -Recurse | |
# Get file listing for totals | |
$allFiles = $searchResults | Where-Object {$_.Attributes -notcontains 'Directory'} | |
# Get all subfolders | |
$allFolders = $searchResults | Where-Object {$_.Attributes -contains 'Directory'} | |
# Build report header and intro | |
$reportHead = @" | |
<head><style> | |
body {font-family: Calibri,sans-serif; font-size: 11pt} | |
h1 {font-family: Segoe UI Light,sans-serif} | |
p.footer {margin-top: 3em; font-size: 9pt; font-style: italic; color: gray} | |
table {background-color: #e6e6e6} | |
td,th {background-color: white; padding: 3px} | |
th {background-color: #f2f2f2} | |
ul.folders {list-style: none; padding: 0; margin: 0;} | |
ul.folders li {padding-left: 1rem; text-indent: -0.7rem} | |
ul.folders li::before {content: "📁 "} | |
</style></head> | |
"@ | |
$reportIntro = "<h1>Report: $((Get-Item -Path $SearchPath).Name)</h1><p><p><ul><li>Total files found: $($allFiles.Count.ToString("N0"))</li><li>Subfolders: $($allFolders.Count.ToString("N0"))</li><li>Total size: $(Format-FileSize ($allFiles | Measure-Object -Property Length -Sum).Sum)</li></ul></p>" | |
# Get the file listing for the root folder | |
$reportBody = Export-HtmlFileList -DirectoryPath $SearchPath | |
# Append the file listings for each subfolder | |
$allFolders | Sort-Object -Property FullName | ForEach-Object { | |
$reportBody += Export-HtmlFileList -DirectoryPath $_.FullName | |
} | |
# Output the report to disk | |
"$reportHead`n$reportIntro`n$reportBody" | Out-File -FilePath $OutputPath -Encoding UTF8 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment