You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化扫描14TB DFS共享的PowerShell ACL脚本以提速?

调优PowerShell DFS文件夹权限扫描脚本以提升速度

我是PowerShell新手,若有错误请见谅。因一名资深员工突然离职,出于安全考虑,我被指派找出该员工在DFS中拥有访问权限的所有文件夹。找不到合适的脚本扫描14TB的DFS共享以排查该用户及其所属组的访问权限,于是自行编写了脚本。脚本可正常运行但速度过慢,希望能进行调优以提升运行速度。

我将脚本分为两部分执行:先保存所有文件夹路径,再遍历每个路径获取ACL权限并筛选目标用户/组信息,保存为以~为分隔符的CSV文件,使用PowerShell 5.1环境。原脚本如下:

$ErrorActionPreference = "Continue"
#$rootDirectory = 'C:\temp'
$rootDirectory = '\\?\UNC\myServer\myShare'
$scriptName = 'myACL'
$version = 1.0
$dateStamp = (Get-Date).ToString('yyyyMMddHHmm')
$scriptDirectory = $PSScriptRoot
$log = $scriptDirectory + "\" + $scriptName + "_dirList_v" + $version + "_"+$dateStamp+".log"
"Path" | Out-File $log

function getSubfolders ([String]$arg_directory, [string]$arg_log)
{
    $subFolders = Get-ChildItem -LiteralPath $arg_directory -Directory -Force -ErrorAction SilentlyContinue | Select-Object -expandProperty FullName
    $subFolders | Out-File $arg_log -append
    foreach ($folder in $subFolders)
    {
        getSubfolders $folder $arg_log
    }
}

#part1
getSubfolders $rootDirectory $log


#part2
$dirListSourceFile = $log
$log2 = $scriptDirectory + "\" + $scriptName + "_permissionList_v" + $version + "_"+$dateStamp+".csv"
$i=0



"Sr~Path~User/Group~Rights~isInherited?" | Out-File $log2

Start-Sleep -s 2

Import-CSV $dirListSourceFile | ForEach-Object{
    $i++
    $path = $_.path.Trim()
    $Acl = get-acl $path | Select *

    ForEach ($Access in $Acl.Access)
    {
        
        if($Access.IdentityReference.value -eq "mydomain\user1" -or $Access.IdentityReference.value -eq "mydomain\sg1" -or $Access.IdentityReference.value -eq "mydomain\sg2" -or $Access.IdentityReference.value -eq "mydomain\sg3" -or $Access.IdentityReference.value -eq "mydomain\sg4")
        {
            "$i~$path~$($Access.IdentityReference.value)~$($Access.FileSystemRights)~$($Access.IsInherited)" | Out-File $log2 -append
        }
    }
}

调优方案

1. 合并两步操作,消除中间文件IO开销

原脚本先写入文件夹路径到日志再读取处理,两次磁盘IO会大幅拖慢速度。直接在遍历文件夹时同步处理ACL,减少不必要的文件操作。

2. 替换递归函数为Get-ChildItem -Recurse

自定义递归函数在处理海量文件夹时会产生额外的函数调用开销,Get-ChildItem -Recurse是原生优化的递归遍历方式,效率更高。

3. 批量写入结果,减少文件操作次数

频繁使用Out-File -Append会重复执行文件打开、写入、关闭操作,严重影响性能。先将结果存入内存数组,最后一次性写入文件。

4. 用集合存储目标身份,加快筛选速度

原脚本的多-or判断效率低下,改用数组集合的Contains方法,查找速度更快。

5. 简化Get-Acl调用

Get-Acl $path | Select *会创建冗余对象,直接使用Get-Acl返回的原始对象即可。

优化后的脚本

$ErrorActionPreference = "Continue"
$rootDirectory = '\\?\UNC\myServer\myShare'
$scriptName = 'myACL'
$version = 1.0
$dateStamp = (Get-Date).ToString('yyyyMMddHHmm')
$scriptDirectory = $PSScriptRoot
$outputFile = Join-Path $scriptDirectory "$scriptName`_permissionList_v$version`_$dateStamp.csv"

# 预定义需要排查的用户/组集合,提升筛选效率
$targetIdentities = @(
    "mydomain\user1",
    "mydomain\sg1",
    "mydomain\sg2",
    "mydomain\sg3",
    "mydomain\sg4"
)

# 初始化结果数组,批量存储数据
$results = @()
$results += "Sr~Path~User/Group~Rights~isInherited?"

$i = 0

# 直接递归遍历并处理ACL,跳过中间文件
Get-ChildItem -LiteralPath $rootDirectory -Directory -Recurse -Force -ErrorAction SilentlyContinue | ForEach-Object {
    $i++
    $path = $_.FullName.Trim()
    $acl = Get-Acl -LiteralPath $path

    foreach ($access in $acl.Access) {
        $identity = $access.IdentityReference.Value
        if ($targetIdentities.Contains($identity)) {
            $results += "$i~$path~$identity~$($access.FileSystemRights)~$($access.IsInherited)"
        }
    }
}

# 一次性写入所有结果
$results | Out-File -FilePath $outputFile -Encoding utf8

额外优化建议

  • 并行处理:如果可以升级到PowerShell 7+,可使用ForEach-Object -Parallel实现多线程遍历;若必须使用PowerShell 5.1,可通过RunspacePool手动实现并行处理,大幅提升大文件系统的扫描速度。
  • 跳过继承权限:如果某文件夹的权限完全继承自已扫描的父文件夹,且没有显式权限条目,可以跳过该文件夹的ACL检查,减少重复工作(需注意:若有显式添加的权限仍需处理)。

内容的提问来源于stack exchange,提问作者Majid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 02:25:21