3
\$\begingroup\$

I've written a Powershell script that uses Robocopy to get the full path of all files on a drive and then run it through a foreach loop to get the owner for each file and generate it in a CSV. The code works, but is very slow when I run it against so many items. Can someone help me make it as efficient as possible? I also use "File System Security PowerShell Module 4.2.3" to use Get-NTFSOwner which gets me around the 256 character limit, which is also why I use Robocopy to generate the paths.

Import-Module NTFSSecurity
#Gets initial file and folder list
 $Folderpath = "G:\DEPT"
 $Folders = Get-Childitem $Folderpath
 ForEach ($Folder in $Folders) {Start-Job -ScriptBlock {
 Param($Folder,$Folderpath)
 robocopy "$FolderPath\$Folder" NULL /L /S /NJH /FP /NC /XJ /NS /NJH /NC /NJS /LOG:D:\AutoAssign\Data\RoboLogs\$Folder.txt
 } -ArgumentList $Folder,$Folderpath}
#Wait unitl all jobs are finished
Get-Job | Wait-Job
#Trims out white space and empty lines
 $Folderpath = "D:\AutoAssign\Data\RoboLogs"
 $Files = Get-Childitem $Folderpath
ForEach ($File in $Files) {Start-Job -ScriptBlock {
 Param($File,$Folderpath,$Files)
 $Trim = Get-Content "$Folderpath\$File"
 $Trim.trim() | Where { $_ } | Out-File "$Folderpath\$File"
 } -ArgumentList $File,$Folderpath,$Files }
#Wait unitl all jobs are finished
Get-Job | Wait-Job
#Gets Owner for each file And Create CSV
$Dir = "D:\AutoAssign\Data\RoboLogs"
$Files = Get-ChildItem $Dir
ForEach ($File in $Files){ Start-Job -ScriptBlock {
 Param($Dir,$Files,$File)
$OutputFile = "D:\AutoAssign\Data\Final\$File.csv"
$Results = @()
$Paths = Get-Content $Dir\$File
ForEach ($Path in $Paths){
 $Owner = get-ntfsowner $Path | Select Owner | ft -hidetableheaders | Out-String
 $Owner = $Owner.Trim()
 $Properties = @{
 Path = $Path
 Owner = $Owner
 }
If ($Owner -ne "BUILTIN\Administrators" -and $Owner -ne $null-and $Owner -ne "Domain\Domain Admins" -and $Owner -notlike "S-1*"){
 $Results += New-Object psobject -Property $properties}
 }
$Results | Export-Csv -notypeinformation -Path $OutputFile
} -ArgumentList $Dir,$Files,$File #Ends Initial ForEach
} #Ends Job Script Block
#Wait unitl all jobs are finished
Get-Job | Wait-Job
#Merge all files into one CSV
Get-ChildItem D:\AutoAssign\Data\Final | Select-Object -ExpandProperty FullName | Import-Csv | Export-Csv D:\AutoAssign\Data\G.csv -NoTypeInformation -Append
#Delete all original files
Get-ChildItem D:\AutoAssign\Data\RoboLogs | Remove-Item
Get-ChildItem D:\AutoAssign\Data\Final | Remove-Item
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Aug 12, 2018 at 19:12
\$\endgroup\$
3
  • \$\begingroup\$ What PowerShell Version ? I'd avoid using $Result+= as it rebuilds the whole array each time. \$\endgroup\$ Commented Aug 12, 2018 at 20:35
  • \$\begingroup\$ Using PowerShell 5.1. Can you recommend what I can substitute in to replace $Results += ? \$\endgroup\$ Commented Aug 12, 2018 at 22:39
  • \$\begingroup\$ How about this? New-Object psobject -Property $properties | Export-Csv -notypeinformation -Append -Path $OutputFile \$\endgroup\$ Commented Aug 12, 2018 at 23:01

1 Answer 1

2
\$\begingroup\$

Your robocopy command lists /NC and /NJH twice.

$Folders and $Folder contain objects with properties, use these instead of treating them as strings (which implicit casts them as such) or pipe to Select-Object -ExpandProperty FullName Same with $Files and $File

I'd not reuse variable names but define neccessary ones from begin. Proper indenting eases reading/understanding the code IMO better than excess white space.

The following script isn't tested at all, see it as rough template:

## Q:\Test2018円08円12円\cr_201527.ps1
Import-Module NTFSSecurity
$Logs = 'D:\AutoAssign\Data\RoboLogs\'
$Final = 'D:\AutoAssign\Data\Final\'
$Folderpath = "G:\DEPT"
#Gets initial file and folder list
$Folders = Get-Childitem $Folderpath
ForEach ($Folder in $Folders) {
 Start-Job -ScriptBlock { Param($Folder,$Logs)
 robocopy "$($Folder.FullName)" NULL /L /S /NJH /FP /NC /XJ /NS /NJH /NC /NJS /LOG:"$Logs$($Folder.Name).txt"
 } -ArgumentList $Folder,$Logs
}
#Wait until all jobs are finished
Get-Job | Wait-Job
<# functionality integrated into next sction
 #Trims out white space and empty lines
#>
#Gets Owner for each file And Create CSV
ForEach ($File in (Get-ChildItem $Logs)){
 Start-Job -ScriptBlock { Param($Logs,$File,$Final)
 $OutputFile = Join-Path $Final "$($File.Name).csv"
 $Results = ForEach ($Path in ((Get-Content $File.FullName).Trim() -ne '')){
 $Owner = (Get-NtfsOwner $Path).Owner.Trim()
 If ($Owner -ne "BUILTIN\Administrators" -and
 $Owner -ne $null -and
 $Owner -ne "Domain\Domain Admins" -and
 $Owner -notlike "S-1*"){
 [PSCustomObject]@{
 Path = $Path
 Owner = $Owner
 }
 }
 }
 $Results | Export-Csv -NoTypeInformation -Path $OutputFile
 } -ArgumentList $Logs,$File,$Final #Ends Initial ForEach
} #Ends Job Script Block
#Wait unitl all jobs are finished
Get-Job | Wait-Job
#Merge all files into one CSV
Get-ChildItem D:\AutoAssign\Data\Final | Select-Object -ExpandProperty FullName |
 Import-Csv | Export-Csv D:\AutoAssign\Data\G.csv -NoTypeInformation -Append
#Delete all original files
Get-ChildItem D:\AutoAssign\Data\RoboLogs | Remove-Item
Get-ChildItem D:\AutoAssign\Data\Final | Remove-Item
answered Aug 13, 2018 at 12:28
\$\endgroup\$
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.