powershell - PowerShell错误,主域和可信域之间的信任关系失败
问题描述
我制作了一个脚本,必须一个一个地遍历数千个 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
}
}
同样,代码不应该有任何问题,因为错误是如此随机发生并在再次运行脚本时通过。关于可能导致此问题/如何解决此问题的任何想法?
感谢所有帮助!
解决方案
当您调用 时AddAccessRule
,如果身份引用是类型,System.Security.Principal.SecuriyIdentifier
那么您不会遇到此问题。该问题似乎发生在从转换NTAccount
为SecurityIdentifier
; 由您调用$ntAccount.Translate([System.Security.Principal.SecuriyIdentifier])
,或者AddAccessRule
在收到除SecurityIdentifier
.
好消息是,从作为string
to 类型保存的 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 函数中提供了一个很好的解决方案,用于通过 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 字符串。可以在这里找到/复制下面的代码。
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
}
我已经从它们的源代码中逐字复制了这些代码示例。
推荐阅读
- java - 验证 javax.naming.NamingException:LDAP
- fluid - TYPO 在节内渲染节
- python - 为什么在运行连接测试时会出现 ModuleNotFoundError
- python - 如何使用python在chrome中打开特定链接
- python - 在控制台的两个输入之间运行一个函数
- tfs - TFS Set Permission 角色的案例
- kubernetes-helm - 将 yaml 转换为 helm 模板中的属性文件
- windows - 从 Ansible 配置 IIS 身份验证
- c - 链接器/编译器/预处理问题
- python - 如何在python中获得voronoi边缘图