我有一个从数据源同步用户的系统。数据源由用户信息组成。同步新用户时,会触发创建或更新用户的 PowerShell 任务。这一切都很好,但是当新/更新用户的数量变得太大时,一些任务会失败并出现一些有趣的错误,例如:
"The server has returned the following error: invalid enumeration context."
或者
"A connection to the directory on which to process the request was unavailable. This is likely a transient condition."
在进行故障排除时,这些错误发生的原因似乎很明显是缺乏资源。这是因为所有同时触发的任务都在自己的 PS session 中导入模块。
所以我尝试了一些不同的东西并测量 Import-Module 的速度等。所以我得出结论,运行
Import-Module
更快。然后 Get-ADUser
例如,只需 Get-ADUser
(这也将导入模块)。Measure-Command {Import-Module ActiveDirectory}
Average time 340 ms
Measure-Command {Get-ADUser -Filter *}
Average time 420 ms
Get-ADUser
导入模块后Average time 10 ms
但这些边际差异不会对问题产生任何影响。所以我不得不进一步看。我发现禁用驱动器可能有助于加快进程,所以我在导入模块之前添加了以下内容:
$Env:ADPS_LoadDefaultDrive = 0
Measure-Command {Import-Module ActiveDirectory}
Average time 85 ms
快4倍!但同时错误仍然存在于大量用户(例如 50 个任务)。所以我想在脚本中轮询可用性,或者做一个
do..while
环形。或者,触发单独任务的系统可能需要重新设计,以拥有某种队列。有人认识这种情况吗?或者他们想就这个主题分享一些想法?
最佳答案
It is because all the simultaneously triggered tasks are importing the module on their own PS session.
然后,您需要确保不会发生这种情况,或者至少不会出现资源不足的情况。所以你有两个选择:
我认为选项 2 是更好的解决方案。例如,您的同步作业不会立即触发脚本,而是将用户名写入文件(甚至在内存中),一旦找到所有用户,它就会触发 PowerShell 脚本并传递列表(或脚本可以读取写入的文件)。你有选择 - 任何最有效的。
更新:所有 .NET 都可在 PowerShell 中使用,因此另一种选择是将整个脚本更改为使用 .NET 的
DirectoryEntry
而不是 ActiveDirectory 模块,它会使用更少的内存。在 PowerShell 中甚至有它的快捷方式。例如,[ADSI]"LDAP://$distinguishedName"
将创建一个 DirectoryEntry
用户的对象。这是一次实质性的重写,但性能要好得多(速度和内存消耗)。以下是使用
DirectorySearcher
进行搜索的一些示例(使用 [ADSISearcher]
快捷方式):https://blogs.technet.microsoft.com/heyscriptingguy/2010/08/23/use-the-directorysearcher-net-class-and-powershell-to-search-active-directory/下面是使用
DirectoryEntry
创建帐户的示例: https://www.petri.com/creating-active-directory-user-accounts-adsi-powershell
关于powershell - 批量使用 ActiveDirectory cmdlet 时出现 Active Directory transient 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53478669/