Taylor Arter
Taylor Arter

Reputation: 1

Folder audit Powershell script, nested loop

I am trying to get a script working to audit folder permissions on a Windows server, among other data, and export this data to a CSV file for analysis after a ransomware attack. I ripped the script from a forum, but it did not run correctly as is. Below is a slightly modified version during my troubleshooting. I am well versed in batch scripting, and have a decent understanding of loops and pipelining, but this Powershell script has me scratching my head. It seems like the array is not making it to the nested loop. I am testing in Windows 10 Pro 21H1, using Powershell version 5.1.19041.1320, build 10.0.19041.1320

##The script:

$ErrorActionPreference = "Continue"
$strComputer = $env:ComputerName
$colDrives = Get-PSDrive -PSProvider Filesystem
 ForEach ($DriveLetter in $colDrives) {
$StartPath = "$DriveLetter`:\"
Get-ChildItem -LiteralPath $StartPath -Recurse | ?{ $_.PSIsContainer } | 

ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Item - 
LiteralPath $FullPath}.Directoryinfo.GetAccessControl())}

Select @{N='Server Name';E={$strComputer}}
@{N='Full Path';E={$FullPath}}
@{N='Type';E={If($FullPath.PSIsContainer -eq $True) {'D'} Else {'F'}}}
@{N='Owner';E={$_.Owner}}
  @{N='Trustee';E={$_.IdentityReference}}
  @{N='Inherited';E={$_.IsInherited}}
  @{N='Inheritance Flags';E={$_.InheritanceFlags}}
  @{N='Ace Flags';E={$_.PropagationFlags}}
  @{N='Ace Type';E={$_.AccessControlType}}
   @{N='Access Masks';E={$_.FileSystemRights}}
  Export-CSV -NoTypeInformation -Delimiter "|" -Path "$strComputer`_$DriveLetter.csv"

##The error I am getting:

You cannot call a method on a null-valued expression. At C:\Users\user\Documents\fileaudit2.ps1:8 char:13

##when I modify the nested loop as follows:

   ForEach ($FullPath = Get-Item -LiteralPath{Get-Item -LiteralPath $_.PSPath}{Get-Item -LiteralPath $FullPath}).Directoryinfo.GetAccessControl()}

##I get the error:

Get-Item : Cannot evaluate parameter 'LiteralPath' because its argument is specified as a script block and there is no input. A script block cannot be evaluated without input. At C:\Users\user\Documents\fileaudit2.ps1:8 char:46

##I'm just wholly struggling to understand what is not working in this loop.

Upvotes: 0

Views: 477

Answers (1)

Theo
Theo

Reputation: 61068

You are mixing a lot of unneeded Get-Item calls in there.

I also would not use Get-PSDrive for this because I assume you don't want to get results for CD drives, USB devices etc in the report.

Try:

# this returns drives WITH a trailing backslash like C:\
$colDrives = ([System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' }).Name

# or use:
# this returns drives WITHOUT trailing backslash like C:
# $colDrives = (Get-CimInstance -ClassName win32_logicaldisk | Where-Object { $_.DriveType -eq 3 }).DeviceID

$result = foreach ($drive in $colDrives) {
    Get-ChildItem -LiteralPath $drive -Directory -Recurse -ErrorAction SilentlyContinue | 
    ForEach-Object {
        $path = $_.FullName
        $acl  = Get-Acl -Path $path
        foreach ($access in $acl.Access) {
            [PsCustomObject]@{
                Server           = $env:COMPUTERNAME
                Drive            = $drive[0]  # just the first character of the drive
                Directory        = $path
                Owner            = $acl.Owner
                Trustee          = $access.IdentityReference
                Inherited        = $access.IsInherited
                InheritanceFlags = $access.InheritanceFlags -join ', '
                'Ace Flags'      = $access.PropagationFlags -join ', '
                'Ace Type'       = $access.AccessControlType
                'Access Masks'   = $access.FileSystemRights -join ', '
            }
        }
    }
}

# now you can save your result as CSV file for instance you can double-click to open in Excel:
$result | Export-Csv -Path 'X:\WhereEver\audit.csv' -NoTypeInformation -UseCulture

To do this on several remote machines, wrap it inside Invoke-Command

# set the credentials for admin access on the servers
$cred    = Get-Credential 'Please enter your admin credentials'
# create an array of the servers you need to probe
$servers = 'Server01', 'Server02'

$result = Invoke-Command -ComputerName $servers -Credential $cred -ScriptBlock {
    $colDrives = ([System.IO.DriveInfo]::GetDrives() | Where-Object { $_.DriveType -eq 'Fixed' }).Name
    foreach ($drive in $colDrives) {
        # code inside this loop unchanged as above
    }
}
# remove the extra properties PowerShell added
$result = $result | Select-Object * -ExcludeProperty PS*, RunspaceId

# output to csv file
$result | Export-Csv -Path 'X:\WhereEver\audit.csv' -NoTypeInformation -UseCulture

Upvotes: 1

Related Questions