优化脚本以递归方式修改网络共享中文件的ACL

时间:2020-08-30 11:33:35

标签: powershell

(你好!有史以来第一次在这里发帖,所以如果你发现它是疯了,请不要对我太猛烈抨击:))

我有一个任务,我必须对文件共享的根文件夹中存储的所有文件和文件夹进行递归设置“继承”,即从根文件夹复制ACL并将其应用于所有子文件夹。

该任务由于两个问题而变得复杂:首先-一些孩子没有所有者或不是Admins组,其次-一些文件的完整路径超过了256个符号限制,因此不能通过常规方式进行工作(这两个问题都是在使用ROBOCOPY脚本将共享从一个NAS迁移到另一个NAS时出现的,但这显然不理想)。

这两个问题使我无法使用GUI,并且选中了“将所有子权限替换为该对象的可继承权限”选项,因为在某些时候(有时经过几个小时的处理)它会引发“访问被拒绝”错误,并且您要么跳过每个文件,要么完全取消该过程。

为避免这些问题,我编写了一个脚本,该脚本提高了当前进程的特权(从this脚本中无耻地借来的C#代码块,进行了少量修改),并允许您将管理组设置为正在处理的文件/文件夹的所有者。 ,这反过来又使您能够修改其ACL,同时使用DOS设备路径语法以相同的方式抓取和处理长名称的子代。

换句话说,脚本可以执行我想要的操作。但是这样做的过程非常缓慢,因为我们共享中的每个文件夹都包含成千上万个文件,每个文件在脚本的流程块内的每次迭代中都经过单独处理。如果只有GUI对我有用,那么它比GUI慢得多。

因此,我认为也许某些StackOverflow上的Powershell专家会建议一种优化我笨拙的脚本并使其运行更快的方法? :)如果GUI的速度更快,那一定有办法吧?

$CSScriptBlock = @' advapi32.dll functions here that enable required privileges '@
function Adjust-Privilege { ... Add-Type $CSScriptBlock etc etc }

$root = "\\server\share\folder"

function restore-inheritance {
param(
[parameter(ValueFromPipelineByPropertyName=$True)]
[Alias('FullName')]
[string[]]$Path
)
    BEGIN ### enable privileges, get ACL from root folder
    { 
        "SeRestorePrivilege","SeBackupPrivilege","SeTakeOwnershipPrivilege" | Adjust-Privilege

        $acl = Get-ACL $root
        ### remove explicit ACEs
        $acl.Access | Where {$_.isinherited -eq $false} | % {
            $acl.RemoveAccessRule($_)
        }
    }

    PROCESS ### try to apply that ACL to children, set owner on failure and retry
    {   
        $DirOwner = New-Object System.Security.AccessControl.DirectorySecurity
        $DirOwner.SetOwner([System.Security.Principal.NTAccount]'Builtin\Administrators')
        $FileOwner = New-Object System.Security.AccessControl.FileSecurity
        $FileOwner.SetOwner([System.Security.Principal.NTAccount]'Builtin\Administrators')
         
        $path = $input.fullName    
        $litpath = "\\?\UNC" + $path.substring(1)

        if ([bool](get-item $path)) {
            try {
                Write-Host "Attempting to fix inheritance on [ $path ]"
                Set-Acl $path $acl -EA Stop
                }
            catch [System.Management.Automation.RuntimeException],`
                  [System.UnauthorizedAccessException],`
                  [System.IO.IOException] {
                Write-Host "Attempting to overwrite ownership of [ $path ]"
                $item = get-item $path
                if (!$item.PSIsContainer) {
                    $item.SetAccessControl($FileOwner)
                    Set-Acl $path $acl
                    }
                else {
                    $item.SetAccessControl($DirOwner)
                    Set-Acl $path $acl
                    }
                }
        }
        ### kicks in only when file is unreachable via regular path
        else {
            try {
                Write-Host "Attempting to fix inheritance on [ $litpath ]" -F Yellow
                Set-Acl -LiteralPath $litpath $acl -EA Stop
                }
            catch [System.Management.Automation.RuntimeException],`
                  [System.UnauthorizedAccessException],`
                  [System.IO.IOException] {
                Write-Host "Attempting to overwrite ownership of [ $litpath ]" -F Yellow
                $item = get-item -LiteralPath $litpath
                if (!$item.PSIsContainer) {
                    $item.SetAccessControl($FileOwner)
                    Set-Acl -LiteralPath $litpath $acl
                    }
                else {
                    $item.SetAccessControl($DirOwner)
                    Set-Acl -LiteralPath $litpath $acl
                    }
                }
            } 
    }

    END ### disable privileges
    {
        "SeRestorePrivilege","SeBackupPrivilege","SeTakeOwnershipPrivilege" | Adjust-Privilege -Disable
    }
}

get-childitem $root -Recurse -EA Stop | restore-inheritance

0 个答案:

没有答案