【问题标题】:PowerShell error, trust relationship between the primary domain and the trusted domain failedPowerShell错误,主域和可信域之间的信任关系失败
【发布时间】:2018-07-13 07:07:08
【问题描述】:

我制作了一个脚本,它必须遍历数千个 AD 用户主目录 一个一个,基本上每一个都做以下步骤:

  • 取得文件夹的所有权
  • 为域管理员组添加访问规则
  • 归还文件夹的所有权
  • 循环遍历所有子文件夹和文件,启用继承和删除 所有明确的权限

经过大量测试和问题解决后,脚本完美运行,除了一个让我头撞墙的问题。

脚本成功循环了大约 50-150 个文件夹(非常随机),然后导致以下错误:"the trust relationship between the primary domain and the trusted domain failed"

我构建了一个额外的循环,当此错误发生时将重试 30 次(每 30 秒)。但是,这无济于事,因为只要脚本运行,信任关系就会丢失。

最有趣的部分是,一旦我再次运行脚本,(从问题文件夹开始)该文件夹被处理而没有进一步的错误。该脚本再也不会卡在同一个文件夹中。但后来又发生了这种情况,比如 50 个文件夹之后。

这是一个巨大的不便,因为我需要处理至少 15,000 个用户文件夹,并且当 1 个失败时,我总是需要编译一个新的“要处理的文件夹”列表。

这里是基本的代码功能,我去掉了所有不必要的错误处理和重试循环以获得更好的可读性:

foreach ($folder in $homeFoldersFound) {
    $accessControl = Get-Acl -LiteralPath $folder.FullName -ErrorAction Stop

    #Current owner
    $folderOwner = $accessControl.Owner

    #Take ownership for the user running the script
    $accessControl.SetOwner([System.Security.Principal.NTAccount]$currentUser)

    #Access rule to add
    $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($groupToAdd,"FullControl","ContainerInherit,ObjectInherit", "None", "Allow")
    $accessControl.AddAccessRule($accessRule)

    #Purge current explicit permissions
    $accessControl.SetAccessRuleProtection($true, $false)

    #Apply ownership and access rules
    set-acl -AclObject $accessControl -LiteralPath $folder.FullName -ErrorAction Stop | Out-Null


    #Return the previous ownership and apply
    $accessControl.SetOwner([System.Security.Principal.NTAccount]$folderOwner)
    $accessControl.SetAccessRuleProtection($false, $false)
    set-acl -AclObject $accessControl -LiteralPath $folderItem -ErrorAction Stop | Out-Null


    #Loop through child items, enable inheritance & remove explicit permissions
    foreach ($item in (Get-ChildItem -LiteralPath $folder.FullName -Recurse -ErrorAction Stop)) {
        #More code
    }
}

同样,代码不应该有任何问题,因为错误发生得如此随机,并在再次运行脚本时通过。关于可能导致此问题/如何解决此问题的任何想法?

感谢所有帮助!

【问题讨论】:

  • 您是否在具有本地路径文件夹的机器上运行脚本?例如D:\sharefoldername\users\ ?当我在我的文件服务器中查询每个文件夹的权限时,我遇到了同样的问题,当我从文件服务器(2012 R2)运行它时我没有遇到问题。如果我想从我的机器上运行它,我会运行一个 get-childitem -path 目录,将这些结果导出到多个 txt 文件中,然后使用每个文本文件作为输入运行我的权限脚本。希望你明白我在说什么。
  • $homeFoldersFound是指通用域名还是特定域服务器?如果您指的是通用域名,我猜您与之交谈的服务器可能会突然更改并且尚未被复制。
  • $userFolder = "\\AD.l\path\to\folders" $homeFoldersFound = (Get-ChildItem -LiteralPath $userFolder -Directory -Force) 这是一个 DFS 文件系统,我无法从本地计算机访问文件夹。如您所见,我需要使用以 '\\' 开头的共享路径
  • @iRon 您是否建议不要使用“\\domain.local\path\folders\”,例如,我应该使用“\\domainDC3\path\folders\”?
  • 是的,这正是我会尝试的。

标签: powershell active-directory acl powershell-5.0


【解决方案1】:

当您调用AddAccessRule 时,如果标识引用的类型为System.Security.Principal.SecuriyIdentifier,那么您不会遇到这个问题。从NTAccount 转换为SecurityIdentifier 时似乎会出现此问题;你可以调用$ntAccount.Translate([System.Security.Principal.SecuriyIdentifier]),或者在收到SecurityIdentifier 以外的任何类型的身份引用后将其留给AddAccessRule 在后台执行。

好消息是,从作为string 保存的SID 转换为SecurityIdentifier 类型不存在此问题;所以一个简单的演员就足够了;例如[System.Security.Principal.SecurityIdentifier]'S-1-1-0'.

要在不使用Translate 选项的情况下获取 SID,您可以从 AD 中提取它((Get-AdUser 'myUsername').SID 如果您安装了 AD 模块,HexSIDToDec(([ADSI]("WinNT://$myDomain/$myUsername,user")).objectSID) 如果没有安装)。

另外,Dave Wyatt 在他的Get-Sid function 中提供了一个很好的解决方案,用于通过 Windows API 获取用户的 SID。他的代码复制如下:

function Get-Sid
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [System.String]
        $Account,

        [Parameter(Mandatory = $false, Position = 1)]
        [System.String]
        $Domain = $null
    )

    Add-Type -TypeDefinition @'
        using System;
        using System.Runtime.InteropServices;
        using System.Text;

        public enum SID_NAME_USE 
        {
            SidTypeUser = 1,
            SidTypeGroup,
            SidTypeDomain,
            SidTypeAlias,
            SidTypeWellKnownGroup,
            SidTypeDeletedAccount,
            SidTypeInvalid,
            SidTypeUnknown,
            SidTypeComputer
        }

        public class NativeMethods
        {
            [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError = true)]
            public static extern bool LookupAccountName (
                string lpSystemName,
                string lpAccountName,
                [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
                ref uint cbSid,
                StringBuilder ReferencedDomainName,
                ref uint cchReferencedDomainName,
                out SID_NAME_USE peUse);
        }
'@

    $NO_ERROR = 0
    $ERROR_INSUFFICIENT_BUFFER = 122
    $ERROR_INVALID_FLAGS = 1004

    $sidBytes = $null
    $sidByteCount = 0
    $referencedDomainName = New-Object System.Text.StringBuilder
    $referencedDomainNameCharCount = [System.UInt32]$referencedDomainName.Capacity
    [SID_NAME_USE]$sidNameUse = [SID_NAME_USE]::SidTypeUnknown

    $errorCode = $NO_ERROR

    if (-not [NativeMethods]::LookupAccountName($Domain, $Account, $sidBytes, [ref]$sidByteCount, $referencedDomainName, [ref] $referencedDomainNameCharCount, [ref] $sidNameUse))
    {
        $errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
        if ($errorCode -eq $ERROR_INSUFFICIENT_BUFFER -or $errorCode -eq $ERROR_INVALID_FLAGS)
        {
            $sidBytes = New-Object Byte[]($sidByteCount)
            $null = $referencedDomainName.EnsureCapacity([int]$referencedDomainNameCharCount)
            $errorCode = $NO_ERROR

            if (-not [NativeMethods]::LookupAccountName($Domain, $Account, $sidBytes, [ref]$sidByteCount, $referencedDomainName, [ref] $referencedDomainNameCharCount, [ref] $sidNameUse))
            {
                $errorCode = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
            }
        }
    }
    else
    {
        $displayAccount = ""

        if (-not [string]::IsNullOrEmpty($Domain))
        {
            $displayAccount += "$Domain\"
        }

        $displayAccount += $Account

        throw "Account '$displayAccount' could not be translated to a SID."
    }

    if ($errorCode -eq $NO_ERROR)
    {
        $sid = New-Object System.Security.Principal.SecurityIdentifier($sidBytes,0)
        Write-Output $sid
    }
    else
    {
        throw (New-Object System.ComponentModel.Win32Exception($errorCode))
    }
}

Get-Sid -Domain 'DOMAIN' -Account 'GroupName'

注意:在我的 ADSI 示例中,我使用了 HexSIDToDec 函数将字节数组转换为 SID 字符串。代码可以found here/复制到下面。

Function HexSIDToDec($HexSID)
{
    # Convert into normal array of bytes.
    $strSID = "S-" + $HexSID[0]
    $arrSID = $strSID.Split(" ")
    $Max = $arrSID.Count
    $DecSID = $arrSID[0] + "-" + $arrSID[1] + "-" + $arrSID[8]
    If ($Max -eq 11)
    {
      Return $DecSID
    }
    $Temp1 = [Int64]$arrSID[12] + (256 * ([Int64]$arrSID[13] + (256 * ([Int64]$arrSID[14] + (256 * ([Int64]$arrSID[15]))))))
    $DecSID = $DecSID + "-" + $($Temp1)
    If ($Max -eq 15)
    {
      Return $DecSID
    }
    $Temp2 = [Int64]$arrSID[16] + (256 * ([Int64]$arrSID[17] + (256 * ([Int64]$arrSID[18] + (256 * ([Int64]$arrSID[19]))))))
    $DecSID = $DecSID + "-" + $($Temp2)
    $Temp3 = [Int64]$arrSID[20] + (256 * ([Int64]$arrSID[21] + (256 * ([Int64]$arrSID[22] + (256 * ([Int64]$arrSID[23]))))))
    $DecSID = $DecSID + "-" + $($Temp3)
    If ($Max -lt 24)
    {
      Return $DecSID
    }
    $Temp4 = [Int64]$arrSID[24] + (256 * ([Int64]$arrSID[25] + (256 * ([Int64]$arrSID[26] + (256 * ([Int64]$arrSID[27]))))))
    $DecSID = $DecSID + "-" + $($Temp4)
    Return $DecSID
}

我已经从源代码中逐字复制了这些代码示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-26
    • 2020-10-07
    • 1970-01-01
    • 2010-11-28
    • 2014-05-11
    • 1970-01-01
    相关资源
    最近更新 更多