Asura Asura - 3 months ago 24
PowerShell Question

Powershell manipulate array with folder list to show only last folders

i have to setup a Windows based file-sharing server for my work environment (500+ users in AD) and i wanted to automate things with powershell. I want to make folders based on OU's in AD hierarchy and after that assign permissions to groups of people actually working in these departments. Each ou = department and sometimes under departments there are teams and even smaller organizational units. So i will have mixed structure of folders like:

Root_directory/Tier_1/Tier_2/Tier_3/their_files_and_folders

Root_directory/Tier_1/Tier_2/their_files_and_folders

Root_directory/Tier_1/their_files_and_folders

Each tier of course can have different names, i hope you get the idea.

My problem is that i cant figure out how to get the list of last folders only created by my script based on AD tree (because i can give permissions based on them) After people will start using my server and start creating their own folders will make my current method not work.
My current method is:

Get-childitem "path_to_root_shared_directory" -r -directory | Where-Object {$_.GetDirectories().Count -eq 0}


I thought that since i have a list of folders to create based on AD (in a variable - array) maybe somehow i could manipulate that array to get only the last folders. What i mean by somehow is to compare folder paths to create and leave only paths to folders that have no more sub folders (leaf folders). So if i have folder structure like:

Root_dir

Root_dir/Department_A

Root_dir/Department_A/Team_A

Root_dir/Department_A/Team_B

Root_dir/Department_B

To leave only:

Root_dir/Department_A/Team_A

Root_dir/Department_A/Team_B

Root_dir/Department_B

I hope you guys can understand what i want to achieve ;).

Answer

You'll find below an adaptation of the third solution from http://stuart-moore.com/finding-bottom-folders-file-tree-using-powershell/ to fullfill the request I need to see them in a list 1 by 1 so then i can make another foreach loop and add permissions based on them.

Function Get-MostDepthDirectory {
    [CmdletBinding(DefaultParametersetName="DirectoryScan")] 
    param (
        [Parameter(Position=0,Mandatory=$true,ParameterSetName="DirectoryScan")]
        [String]$rootDirectory,

        [Parameter(Position=0,Mandatory=$true,ParameterSetName="DirectoryList")]
        [String[]]$subDirectories       
    )

    if ($PsCmdlet.ParameterSetName -eq "DirectoryScan") {
        $subDirectories = Get-ChildItem -Recurse $rootDirectory -Directory | Select-Object -ExpandProperty FullName
    }

    $deepestDirectories = New-Object System.Collections.ArrayList
    foreach ($d in $subDirectories){
        $t = Split-Path $d -Parent
        if ($deepestDirectories -NotContains $t){
            $deepestDirectories.Add($d) | Out-Null
        } else {
            $deepestDirectories.Remove($t) | Out-Null
            $deepestDirectories.Add($d) | Out-Null
        }
    }
    return [string[]]@($deepestDirectories| Sort-Object)
}

Outputs:

PS C:\> $dirScan = @(Get-ChildItem C:\test -Recurse -Directory | Select-Object -ExpandProperty FullName | Sort-Object)
PS C:\> $dirScan
C:\test\a-level1
C:\test\a-level1\a-level2
C:\test\a-level1\b-level2
C:\test\a-level1\b-level2\a-level3
C:\test\a-level1\b-level2\b-level3
C:\test\a-level1\b-level2\c-level3
C:\test\a-level1\b-level2\c-level3\a-level4
C:\test\b-level1
C:\test\c-level1
C:\test\c-level1\a-level2
C:\test\c-level1\b-level2
C:\test\c-level1\b-level2\a-level3
PS C:\> Get-MostDepthDirectory $dirScan
C:\test\a-level1\a-level2
C:\test\a-level1\b-level2\a-level3
C:\test\a-level1\b-level2\b-level3
C:\test\a-level1\b-level2\c-level3\a-level4
C:\test\b-level1
C:\test\c-level1\a-level2
C:\test\c-level1\b-level2\a-level3
PS C:\> Get-MostDepthDirectory C:\test
C:\test\a-level1\a-level2
C:\test\a-level1\b-level2\a-level3
C:\test\a-level1\b-level2\b-level3
C:\test\a-level1\b-level2\c-level3\a-level4
C:\test\b-level1
C:\test\c-level1\a-level2
C:\test\c-level1\b-level2\a-level3
PS C:\>