使用PowerShell启用ACL继承时进程停滞求助
60TB+数据批量启用ACL继承脚本卡顿排查
我需要为60TB以上的数据重新启用ACL继承,使用PowerShell执行任务时,脚本卡在某个文件夹超过4小时。脚本功能为重新启用继承并移除所有显式权限,仅保留继承权限,以下是原脚本:
#Start Transcript Start-Transcript -Path "D:\Temp\processlog_$(Get-Date -format MMM-dd-yyyy-hh-mm-ss-tt).log" #Get Current Date $Starttime = Get-Date -format "MMM-dd-yyyy hh:mm:ss: tt" #Imports NTFSSecurity Powershell Module Import-Module -Name NTFSSecurity -NoClobber #Setting File Path $errorlog = "D:\temp\error_$(Get-Date -format MMM-dd-yyyy-hh-mm-ss-tt).log" $dir = "\\path" Add-Content -Path $errorlog -Value "Inheritance Script Started $Starttime." $error.clear() Write-Host "Path Targeted $dir" Write-Progress -Activity "Inheritance Process" -Status "Please wait while files and folders are being counted. This will take some time." $Path = Get-Childitem -Path $dir -Recurse $TotalFiles = $Path.Count $i = 0 foreach ($File in $Path) { $i++ $PercentComplete = (($i / $TotalFiles) * 100) Write-Progress -Activity "Inheritance Process $($_.name)" -Status "Setting Inheritance on File $i of $($TotalFiles)" -PercentComplete $PercentComplete $File | Enable-NTFSAccessInheritance -RemoveExplicitAccessRules #Start-Sleep -Milliseconds 5 } Write-host "Total number of File and Folder items fixed:"$TotalFiles Get-Item -Path $dir | Get-ACL| Enable-NTFSAccessInheritance -RemoveExplicitAccessRules Clear-Variable -Name "Path" $error | Out-File -FilePath $errorlog -Append -Encoding utf8 -NoClobber $Endtime = Get-Date -format "MMM-dd-yyyy hh:mm:ss: tt" Add-Content -Path $errorlog -Value "Inheritance Script Ended $Endtime." #End Transcript Stop-Transcript
排查与优化建议
- 避免预加载所有对象:原脚本用
Get-ChildItem -Recurse一次性遍历所有文件/文件夹并加载到内存,60TB数据量会导致内存占用过高、遍历耗时极久。改成流式处理(ForEach-Object直接接在Get-ChildItem后),边遍历边处理,无需缓存所有对象。 - 定位卡顿的具体路径:在循环中加入当前处理路径的日志记录,一旦卡住,可从日志中直接找到对应的文件夹,单独排查该路径的ACL是否存在条目过多、损坏或文件系统异常。
- 添加异常捕获与跳过机制:单个文件/文件夹的权限操作失败(如文件被锁定、ACL损坏)会导致脚本挂起,在处理每个对象时加入
try/catch块,捕获异常后记录日志并继续执行。 - 修正进度条变量错误:原进度条中使用
$_.name,但循环变量为$File,应改为$File.Name,否则进度条无法正确显示当前处理对象。 - 调整根目录处理顺序:先处理根目录的ACL继承,再处理子项,避免子项重复继承旧的根目录权限。
- 优化日志记录:原脚本仅输出全局错误集合,改为在每个对象处理时记录成功/失败信息,便于精准排查问题。
优化后的脚本示例
#Start Transcript Start-Transcript -Path "D:\Temp\processlog_$(Get-Date -format MMM-dd-yyyy-hh-mm-ss-tt).log" #Get Current Date $Starttime = Get-Date -format "MMM-dd-yyyy hh:mm:ss: tt" #Imports NTFSSecurity Powershell Module Import-Module -Name NTFSSecurity -NoClobber #Setting File Path $errorlog = "D:\temp\error_$(Get-Date -format MMM-dd-yyyy-hh-mm-ss-tt).log" $dir = "\\path" Add-Content -Path $errorlog -Value "Inheritance Script Started $Starttime." Write-Host "Path Targeted $dir" # 优先处理根目录,确保子项继承正确权限 try { Get-Item -Path $dir | Enable-NTFSAccessInheritance -RemoveExplicitAccessRules -ErrorAction Stop Add-Content -Path $errorlog -Value "[SUCCESS] Processed root directory: $dir" } catch { Add-Content -Path $errorlog -Value "[FAILED] Root directory $dir : $_" } # 流式遍历处理子项,避免预加载所有对象 $itemCount = 0 Get-ChildItem -Path $dir -Recurse -ErrorAction SilentlyContinue | ForEach-Object { $itemCount++ $currentPath = $_.FullName Write-Progress -Activity "Inheritance Process" -Status "Processing $currentPath ($itemCount)" try { $_ | Enable-NTFSAccessInheritance -RemoveExplicitAccessRules -ErrorAction Stop Add-Content -Path $errorlog -Value "[SUCCESS] Processed: $currentPath" } catch { Add-Content -Path $errorlog -Value "[FAILED] $currentPath : $_" } } $Endtime = Get-Date -format "MMM-dd-yyyy hh:mm:ss: tt" Add-Content -Path $errorlog -Value "Inheritance Script Ended $Endtime. Total items processed: $itemCount" #End Transcript Stop-Transcript
内容的提问来源于stack exchange,提问作者HollywoodHero
相关产品推荐
相关产品推荐

