Powershell使用文件夹列表操作数组以仅显示最后的文件夹

时间:2016-08-28 11:57:27

标签: powershell

我必须为我的工作环境设置一个基于Windows的文件共享服务器(AD中有500多个用户),我想用PowerShell自动化。我想在AD层次结构中基于OU创建文件夹,之后为实际在这些部门中工作的人员分配权限。每个ou =部门,有时在部门之下,有团队,甚至更小的组织单位。所以我将混合文件夹结构,如:

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

每一层当然可以有不同的名称,我希望你能得到这个想法。

我的问题是我无法弄清楚如何获取仅由我的脚本基于AD树创建的最后文件夹列表(因为我可以基于它们授予权限)之后人们将开始使用我的服务器并开始创建自己的文件夹将使我当前的方法不起作用。 我目前的方法是:

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

我认为,因为我有一个基于AD(在一个变量 - 数组中)创建的文件夹列表,也许我可以操纵该数组只获取最后一个文件夹。我的意思是以某种方式比较文件夹路径来创建和只留下没有更多子文件夹(叶文件夹)的文件夹的路径。所以,如果我有文件夹结构,如:

ROOT_DIR

ROOT_DIR / Department_A

ROOT_DIR / Department_A / Team_A

ROOT_DIR / Department_A / Team_B

ROOT_DIR / Department_B

仅离开:

ROOT_DIR / Department_A / Team_A

ROOT_DIR / Department_A / Team_B

ROOT_DIR / Department_B

我希望你们能理解我想要达到的目标;)。

2 个答案:

答案 0 :(得分:2)

您将在下面找到从http://stuart-moore.com/finding-bottom-folders-file-tree-using-powershell/到第三个解决方案的改编,以满足请求我需要在列表1中逐一查看它们,然后我可以创建另一个foreach循环并添加基于权限的在他们身上。

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)
}

输出:

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:\>

编辑:我正在补充一点解释。

代码段创建了一个Get-MostDepthDirectory CmdLet,可以使用要过滤的目录数组或要扫描的目录来调用。

如果使用要扫描的目录(ParameterSetName="DirectoryScan")调用,它会构建一个$subDirectories变量,其中包含所有子目录的绝对路径,否则(ParameterSetName="DirectoryList")它将获取目录列表直接来自参数。

它启动一个System.Collections.ArrayList对象,这是一个来自.NET框架的集合,这里更合适,因为它有AddRemove方法,允许不需要的数组的管理内容知道索引(否则代码会更复杂)。该对象将存储已过滤的列表。

然后:

  1. 它在子目录列表(foreach ($d in $subDirectories))上循环

  2. 它从目录($t = Split-Path $d -Parent

  3. 中提取父目录
  4. 如果列表中不包含父项(if ($deepestDirectories -NotContains $t)),则会添加当前目录($deepestDirectories.Add($d) | Out-Null

  5. 否则,它删除父($deepestDirectories.Remove($t) | Out-Null)并添加目录($deepestDirectories.Add($d) | Out-Null

  6. 循环完成后,ArrayList将被排序并在返回之前转换为字符串数组。

    Out-Null用于防止Add对象的RemoveArrayList方法的输出将其内存状态返回到管道,否则PowerShell可能会返回它们以及过滤的目录列表。

    希望通过解释更清楚一点。

答案 1 :(得分:1)

这是一种方法:

#include <stdio.h>

int menu(void);
void choice1(void);
void choice2(void);
void choice3(void);

int main(void) {
    int ch;
    for (;;) {
        switch (ch = menu()) {
        case '1':  choice1();  continue;
        case '2':  choice2();  continue;
        case '3':  choice3();  continue;
        case '4':
        case EOF:  break;
        default:   printf("Invalid character %c\n", ch);  continue;
        }
        break;
    }
    return 0;
}

int menu(void) {
    char choice;

    printf("\nMenu:\n\n");
    printf("1) Choice 1.\n");
    printf("2) Choice 2.\n");
    printf("3) Choice 3.\n");
    printf("Choose any of the above, or enter 4 to quit.\n\n");
    if (scanf(" %c", &choice) == 1)
        return choice;
    else
        return EOF;
}

void choice1(void) {
    printf("\nChoice 1\n");
}

void choice2(void) {
    printf("\nChoice 2\n");
}

void choice3(void) {
    printf("\nChoice 3\n");
}