From 4ddc28df7214329921a02e75798c6c47dfd7cfd8 Mon Sep 17 00:00:00 2001 From: Scott Sutherland Date: Tue, 23 Jul 2024 16:28:13 -0500 Subject: [PATCH] Added interesting files page DEFAULT PARAMETER - Changed default share name sample reporting to 200 (That's 100% for most companies) TOP FOLDER GROUPS PAGE - Added pagination. - Added unique share name count column. - Added column sorting. - Added search. TOP SHARE NAME PAGE - Added pagination. INTERESTING FILES PAGE 0. All interesting files are now saved to the [domain]-Shares-Interesting-Files.csv file when PowerHuntShares is run. 1. Added interesting files page. 2. Added view total interesting files display. 3. Added bar chart showing interesting file category summary. Note: apexcharts.js requires internet access, but may ship with PowerHuntShares in future versions. 3. Added ability to view uncpaths for interesting files via expandable div. 4. Added ability to filter results with search. 5. Added ability to export uncpaths associated with filtered results to a csv file. 6. Added ability to import a file that allows users to define their work interesting file keywords and categories. Example: Invoke-HuntSMBShares -OutputDirectory 'c:\temp' -DomainController 'dc1.domain.com' -Username 'domain.com\user' -Password 'YourPassword' -FileKeywordsPath "C:\temp\interesting-files-template.csv" 7. Added template file for interesting file definition: https://raw.githubusercontent.com/NetSPI/PowerHuntShares/main/interesting-files-template.csv --- PowerHuntShares.psm1 | 1221 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 983 insertions(+), 238 deletions(-) diff --git a/PowerHuntShares.psm1 b/PowerHuntShares.psm1 index e653062..ed4e4c7 100644 --- a/PowerHuntShares.psm1 +++ b/PowerHuntShares.psm1 @@ -4,7 +4,7 @@ #-------------------------------------- # Author: Scott Sutherland, 2024 NetSPI # License: 3-clause BSD -# Version: v1.80 +# Version: v1.85 # References: This script includes custom code and code taken and modified from the open source projects PowerView, Invoke-Ping, and Invoke-Parrell. function Invoke-HuntSMBShares { @@ -165,7 +165,7 @@ function Invoke-HuntSMBShares [Parameter(Mandatory = $false, HelpMessage = 'Number of items to sample for summary report.')] - [int]$SampleSum = 5, + [int]$SampleSum = 200, [Parameter(Mandatory = $false, HelpMessage = 'Runspace time out.')] @@ -196,12 +196,8 @@ function Invoke-HuntSMBShares [int] $DirLevel = 3, [Parameter(Mandatory = $false, - HelpMessage = 'Search for common files containing passwords on the c$ shares.')] - [switch] $FindFiles, - - [Parameter(Mandatory = $false, - HelpMessage = 'Path to file of file paths to search for. One path per line.')] - [string] $FindFilesList, + HelpMessage = 'Path to interesting files template to import file keywords to search for.')] + [string] $FileKeywordsPath, [Parameter(Mandatory = $false, HelpMessage = 'Do not perform ping scan.')] @@ -267,6 +263,18 @@ function Invoke-HuntSMBShares break } + # Check for keyword file path + If($FileKeywordsPath){ + + if(Test-Path $FileKeywordsPath){ + #Write-Output " [x]The target directory exists." + }else{ + Write-Output " [x] The $FileKeywordsPath did not exist." + Write-Output " [!] Aborting operation." + break + } + } + # ---------------------------------------------------------------------- # Import computers from file # ---------------------------------------------------------------------- @@ -1445,7 +1453,395 @@ function Invoke-HuntSMBShares #Write-Output " [*][$Time] - Summary report data generated." #Write-Output " [*][$Time] - $Top5ShareCountTotal of $AllAccessibleSharesCount ($DupPercent) shares are associated with the top 5 share names." + # ---------------------------------------------------------------------- + # Create Interesting Files Table + # ---------------------------------------------------------------------- + Write-Output " [*][$Time] Finding interesting files..." + + # Define common image and other formats to filter out later + $ImageFormats = @("*.jpg", "*.jpeg", "*.png", "*.gif", "*.bmp", "*.ico", "*.svg", "*.webp", "*.mif", "*.heic", "*.msi") + + # Create data table to hold interesting file keywords + $FileNamePatternsAll = New-Object system.data.datatable + $FileNamePatternsAll.Columns.Add("Keyword") | Out-Null # Keyword + $FileNamePatternsAll.Columns.Add("Description") | Out-Null # Summary of keyword. + $FileNamePatternsAll.Columns.Add("Instructions") | Out-Null # Used to instruct testing how to attack match. + $FileNamePatternsAll.Columns.Add("Category") | Out-Null # File name category: Secret (password), sensitive (data), binaries, script, backup, database + $FileNamePatternsAll.Columns.Add("SampleRegex") | Out-Null # Used to parse sample data from file matches. + + # Add rows to data table - Sensitive data + $FileNamePatternsAll.Rows.Add("*credit*","Credit card number and/or PII.","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*pci*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*social*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*ssn*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("human*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("finance*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("Health*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("Billing*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("patient*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("HR*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*ftp*","","None.","Sensitive","") | Out-Null + $FileNamePatternsAll.Rows.Add("*Program Files*","","None.","Sensitive","") | Out-Null + + # Add rows to data table - Files containing passwords + $FileNamePatternsAll.Rows.Add("context.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("db2cli.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("ftpd.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("ftpusers*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("httpd.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("hudson.security.HudsonPrivateSecurityRealm.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("jboss-cli.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("jboss-logmanager.properties*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("jenkins.model.JenkinsLocationConfiguration.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("machine.config*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("my.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("mysql.user*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("nginx.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*ntds.dit*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("pg_hba.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("php.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("putty.reg*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("postgresql.conf*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM-*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SAM_*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("SYSTEM","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("server.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("shadow*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("standalone.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("tnsnames.ora*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("tomcat-users.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("sitemanager.xml*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("users.*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmx*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmdk*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.nvram*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmsd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmsn*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmss*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vmem*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vhd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vhdx*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.avhd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.avhdx*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vsv*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vbox*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vbox-prev*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vdi*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.hdd*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sav*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pvm*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.pvs*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.qcow*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.qcow2*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.img*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*vcenter*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*vault*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*DefaultAppPool*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*WinSCP.ini*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.kdbx","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("wp-config.php*","","None.","Secret","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.config","","None.","Secret","") | Out-Null + + # Add rows to data table - Database files + $FileNamePatternsAll.Rows.Add("*database*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sql*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sqlite*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.idf*","","None.","Database","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.mdf*","","None.","Database","") | Out-Null + + # Add rows to data table - Backup files + $FileNamePatternsAll.Rows.Add("*.bak*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.bkf*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*backup*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.tar*","","None.","Backup","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.zip*","","None.","Backup","") | Out-Null + + # Add rows to data table - Scripts + $FileNamePatternsAll.Rows.Add("*.ps1*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.psm1*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.bat*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.sh*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.vbs*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.cmd*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.wsh*","","None.","Script","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.wsf*","","None.","Script","") | Out-Null + + # Add rows to data table - Binaries + $FileNamePatternsAll.Rows.Add("*.dll","","None.","Binaries","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.exe","","None.","Binaries","") | Out-Null + $FileNamePatternsAll.Rows.Add("*.msi","","None.","Binaries","") | Out-Null + + # Use keyword from define file instead + if($FileKeywordsPath){ + $FileNamePatternsAllTest = import-csv "$FileKeywordsPath" + $CheckFieldKeyword = $FileNamePatternsAllTest | gm | where name -like "keyword" | select name -ExpandProperty name + $CheckFieldCategory = $FileNamePatternsAllTest | gm | where name -like "category" | select name -ExpandProperty name + if($CheckFieldKeyword -and $CheckFieldCategory){ + # File found and columns exist + $FileNamePatternsAll = $FileNamePatternsAllTest + }else{ + # File columns do not exist + # Do nothing and fail back to hard coded list + } + } + + # Get unqiue categories + $FileNamePatternCategories = $FileNamePatternsAll | select Category -Unique + $FileNamePatternCategoriesCount = $FileNamePatternsAll | select Category -Unique | measure | select count -ExpandProperty count + + # Generate chart categories - Individual rows + # for each category - "var MyScriptsCount = countStringInDisplayedRows('Scripts');" + $ChartCategoryCatVars = $FileNamePatternCategories | + foreach{ + $ChartCatGenCat = $_.category + $ChartCatGenVar = "My"+ $ChartCatGenCat + "Count" + "var $ChartCatGenVar = countStringInDisplayedRows('$ChartCatGenCat');" + } + $ChartCategoryCatVarsFlat = $ChartCategoryCatVars -join "`n" + + # Generate chart categories - Category list + # once - categories: ['Sensitive', 'Secrets', 'Scripts'], + $ChartCategoryCommas = ($FileNamePatternCategories | Select-Object -ExpandProperty category | ForEach-Object { "'$_'" }) -join ", " + $ChartCategoryCat = "categories: [$ChartCategoryCommas]," + + # Generate chart categories - + # once - data: [MySensitiveCount, MySecretCount, MyScriptsCount] + $ChartCategoryCountFormat = ($FileNamePatternCategories | Select-Object -ExpandProperty category | ForEach-Object {"My"+ $_ + "Count"}) -join ", " + $ChartCategoryDat = "data: [$ChartCategoryCountFormat]" + + # Get a list of file names from each folder group for the target share name + $InterestingFilesAllFileNames = $ExcessiveSharePrivs | select FileList -Unique | foreach {$_.FileList -split "`r`n"} | Where-Object {$_ -ne ''} | foreach {$_.ToLower()}| select -Unique + + # Identify keyword matches in filenames + $InterestingFilesAllMatches = New-Object system.data.datatable + $InterestingFilesAllMatches.Columns.Add("FileName") | Out-Null + $InterestingFilesAllMatches.Columns.Add("Category") | Out-Null + $FileNamePatternsAll | + foreach { + $TargetKeywordValue = $_.Keyword + $TargetKeywordCategory = $_.Category + $InterestingFilesAllFileNames | + foreach { + + if($_ -like "$TargetKeywordValue"){ + + # check if file has already been labeled + $CheckForFile = $InterestingFilesAllMatches | where Filename -like "$_" + if(-not $CheckForFile){ + + # Add file + $InterestingFilesAllMatches.Rows.Add("$_","$TargetKeywordCategory")| Out-Null + } + } + } + } + + # Query for a list of information for each file name match + $InterestingFilesAllObjects = $InterestingFilesAllMatches | + foreach{ + + # Set variables + $TargetFileNameValue = $_.FileName + $TargetCategoryValue = $_.Category + + # Filter for records with the target file + $TargetKeywordMatches = $ExcessiveSharePrivs | where FileList -like "*$TargetFileNameValue*" | select ComputerName,ShareName,SharePath -Unique + + # Extend object to include a unc path to file + $TargetKeywordMatches | + foreach { + + # Select the propertity and make new ones + $TargetKeywordComputer = $_.ComputerName + $TargetKeywordShareName = $_.ShareName + $TargetKeywordSharePath = $_.SharePath + $TargetKeywordUNCPath = "$TargetKeywordSharePath\$TargetFileNameValue" + $TargetKeywordCategory = $TargetCategoryValue + + # Create updated object + $object = New-Object psobject + $object | add-member noteproperty ComputerName $TargetKeywordComputer + $object | add-member noteproperty ShareName $TargetKeywordShareName + $object | add-member noteproperty SharePath $TargetKeywordSharePath + $object | add-member noteproperty UncPath $TargetKeywordUNCPath + $object | add-member noteproperty FileName $TargetFileNameValue + $object | add-member noteproperty Category $TargetKeywordCategory + + # Return object + $object + } + } | select ComputerName,ShareName,SharePath,UncPath,FileName,Category -Unique + + <# + + # Define list of words associated with sensitive data + $FileNamePatternsSecrets = $FileNamePatternsAll | where category -like "*Secret*" | select Keyword -ExpandProperty keyword + + # Define list of words associated with password files + $FileNamePatternsData = $FileNamePatternsAll | where category -like "*Sensitive*" | select Keyword -ExpandProperty keyword + + # Get a list of file names from each folder group for the target share name + $InterestingFilesAllFileNames = $ExcessiveSharePrivs | select FileList -Unique | foreach {$_.FileList -split "`r`n"} | Where-Object {$_ -ne ''} | foreach {$_.ToLower()}| select -Unique + + # Identify Secrets + $InterestingFilesAllSecrets = $FileNamePatternsSecrets | + foreach { + $TargetSecret = $_ + $InterestingFilesAllFileNames | + foreach { + if($_ -like "$TargetSecret"){ + + # return file name match + $_ + } + } + } + + # Create new secret files objects + $InterestingFilesAllSecretsObjects = $InterestingFilesAllSecrets | + foreach{ + + # Set target file + $TargetSecretFile = $_ + + # Filter for record with the target file + $TargetSecretMatches = $ExcessiveSharePrivs | where FileList -like "*$TargetSecretFile*" | select ComputerName,ShareName,SharePath -Unique + $TargetSecretMatches | + foreach { + + # Select the propertity and make new ones + $TargetSecretComputer = $_.ComputerName + $TargetSecretShareName = $_.ShareName + $TargetSecretSharePath = $_.SharePath + $TargetSecretUNCPath = "$TargetSecretSharePath\$TargetSecretFile" + $TargetSecretType = "Secrets" + + # Create updated object + $object = New-Object psobject + $object | add-member noteproperty ComputerName $TargetSecretComputer + $object | add-member noteproperty ShareName $TargetSecretShareName + $object | add-member noteproperty SharePath $TargetSecretSharePath + $object | add-member noteproperty UncPath $TargetSecretUNCPath + $object | add-member noteproperty FileName $TargetSecretFile + $object | add-member noteproperty DataType $TargetSecretType + + # Return object + $object + } + } | select ComputerName,ShareName,SharePath,UncPath,FileName,DataType -Unique + + # Identify Data + $InterestingFilesAllData = $FileNamePatternsData | + foreach { + $TargetSecret = $_ + $InterestingFilesAllFileNames | + foreach { + if($_ -like "$TargetSecret"){ + + # return file name match + $_ + } + } + } + + # Create new data files objects + $InterestingFilesAllDataObjects = $InterestingFilesAllData | + foreach{ + + # Set target file + $TargetSecretFile = $_ + + # Filter for record with the target file + $TargetSecretMatches = $ExcessiveSharePrivs | where FileList -like "*$TargetSecretFile*" | select ComputerName,ShareName,SharePath -Unique + $TargetSecretMatches | + foreach { + + # Select the propertity and make new ones + $TargetSecretComputer = $_.ComputerName + $TargetSecretShareName = $_.ShareName + $TargetSecretSharePath = $_.SharePath + $TargetSecretUNCPath = "$TargetSecretSharePath\$TargetSecretFile" + $TargetSecretType = "Sensitive" + + # Create updated object + $object = New-Object psobject + $object | add-member noteproperty ComputerName $TargetSecretComputer + $object | add-member noteproperty ShareName $TargetSecretShareName + $object | add-member noteproperty SharePath $TargetSecretSharePath + $object | add-member noteproperty UncPath $TargetSecretUNCPath + $object | add-member noteproperty FileName $TargetSecretFile + $object | add-member noteproperty DataType $TargetSecretType + + # Return object + $object + } + } | select ComputerName,ShareName,SharePath,UncPath,FileName,DataType -Unique + + # Combine objects + $InterestingFilesAllObjects = $InterestingFilesAllSecretsObjects + $InterestingFilesAllDataObjects + + + # Count objects + $InterestingFilesAllSecretsFullCount = $InterestingFilesAllSecretsObjects | measure | select count -ExpandProperty count + $InterestingFilesAllSecretsFullCountU = $InterestingFilesAllSecretsObjects | select FileName -Unique | measure | select count -ExpandProperty count + $InterestingFilesAllDataFullcount = $InterestingFilesAllDataObjects | measure | select count -ExpandProperty count + $InterestingFilesAllDataFullcountU = $InterestingFilesAllDataObjects | select FileName -Unique | measure | select count -ExpandProperty count + #> + + # Outbout objects to file + $InterestingFilesAllObjects | Export-Csv -NoTypeInformation "$OutputDirectory\$TargetDomain-Shares-Interesting-Files.csv" + + # Get order list of interesting file names by count + $InterestingFilesAllFilesCount = $InterestingFilesAllObjects | measure | select count -ExpandProperty count + $InterestingFilesAllFilesCountU = $InterestingFilesAllObjects | select filename -Unique | measure | select count -ExpandProperty count + $InterestingFilesAllFilesGrouped = $InterestingFilesAllObjects | group filename | select count,name | sort count -Descending + + # Generate a row for each one + # Headers are Instance Count, FileName, Type, File Paths,Affected Computers, Affected Shares + $InterestingFilesAllFilesRows = $InterestingFilesAllFilesGrouped | + foreach{ + + # Get count + $IfFinalCount = $_.count + + # Get File Name + $IfFinalName = $_.name + + # Category + $IfFinalType = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | select Category -First 1 -ExpandProperty Category + + # Get File Paths + $IfFinalPaths = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | ForEach-Object { $ASDF = $_.UncPath; "$ASDF
" } | Out-String + + # Get Share Count for Name + # $IfFinalShareCount + $IfFinalShareCount = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | select SharePath -Unique | measure | select count -ExpandProperty count + + # Get Computer Count for Name + # $IfFinalcomputerCount + $IfFinalcomputerCount = $InterestingFilesAllObjects | Where-Object { $_.FileName -like "$IfFinalName" } | select ComputerName -Unique | measure | select count -ExpandProperty count + + # Create Row + + $IfRow = @" + + $IfFinalCount + $IfFinalName + $IfFinalType + + +
+ $IfFinalPaths +
+ + +"@ + + # Return row + $IfRow + } # ---------------------------------------------------------------------- @@ -2996,8 +3392,21 @@ $NewHtmlReport = @" + Report