如何加快对AD对象的PowerShell操作 [英] How to speed up PowerShell operations on AD objects

查看:87
本文介绍了如何加快对AD对象的PowerShell操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个工作脚本,该脚本将查询我们所有的AD域,然后返回具有管理员权限的计算机。下面的脚本可以正常工作并返回预期的结果,但是在我们较大的域上却很慢。

I am writing a script for work that will query all of our AD domains and then return the computers that have admin privileges. The below script works and returns the expected results but it is very slow on our larger domains.

当使用23k对象及更少的对象时,它仅需几分钟(6分钟)即可运行大约),但是当它必须处理90k +时,它变得很费时间。

When working with 23k objects and less it runs in only a few minutes (6min or so), but when its has to handle 90k+ it gets into hours.

我是PowerShell的新手,不知道在这里进行什么操作会增加指数级的运行时间,所以我一直无法缩小范围。我的直觉是它必须以这种方式处理PowerShell正在扩展数组以不断添加更多对象的情况?我也在考虑更好地利用管道...但是是新手,来自bash,我不熟悉这个概念以及如何在代码中使用它

I am new to PowerShell and have no idea what operation here would have an exponential runtime increase so I have been unable to narrow it down. My hunch is that it has to deal with that way PowerShell is expanding the arrays to continuously add more objects? I was also thinking about making better use of the pipeline... but being new and coming from bash I am unfamiliar with this concept and how to utilize it in this code

有什么办法可以加快运行速度,使其超过几个小时?

Is there a way I can speed this up to run faster than a few hours? Any help would be greatly appreciated.

$date = Get-Date -uFormat %d-%m-%y

ForEach($domain in $domains)
{
        $all_computers = Get-ADComputer -Server $domain -filter * -Properties enabled | select-object name,enabled,@{name="distinguishedname";expression={$_.DistinguishedName -replace "(CN[^,]+,)"}}
        #Gets all of the objects that are in a group and pulls their names this is to get the admin flag that is appended to names in this group
        $group_name = (Get-ADGroup -Server $domain -Filter{name -like "*admin*"}).Name

        #Counts the devices pulled from the computer query
        $DevNum = $all_computers.count
        echo "Number of devices: " $DevNum > "$domain LARGE $date.txt"

        #Remove servers from the list
        $all_computers = $all_computers | ?{ $_ -NotMatch "Servers" }

        #Counts the number of servers we removed
        $NumSkipped = $DevNum - $all_computers.count

        Switch($all_computers){
            #Finding all of the accounts where both types of admins exist and removing them from the master list
            {$group_name -contains $($_.name + "Admins") -and $group_name -contains $($_.name + "UPEPAdmins")} {$_ | Add-Member "admintype"  "both";Continue}
            #Finding all of the accounts with only exception admins and removing them from the master list
            {$group_name -contains $($_.name + "Admins")} {$_ | Add-Member "admintype" "old";Continue}
            #Finding all of the accounts with only upep admins and removing them from the master list
            {$group_name -contains $($_.name + "UPEPAdmins")} {$_ | Add-Member "admintype" "UPEP";Continue}
            #These accounts have no admin
            default {$_ | Add-Member "admintype" "No"}
        }

        echo "Number of servers skipped: " $NumSkipped >> "$domain LARGE $date.txt"

        echo "Number of workstations: " $all_computers.count >> "$domain LARGE $date.txt"

        echo "Number of Exception admins found: " $($all_computers|?{$_.admintype -match "old|both"}).count >> "$domain LARGE $date.txt"

        echo "Number of UPEP admins found: " $($all_computers|?{$_.admintype -match "upep|both"}).count >> "$domain LARGE $date.txt"

        echo "Number of both UPEP and Exception admins found: " $($all_computers|?{$_.admintype -eq "both"}).count >> "$domain LARGE $date.txt" 

        #output
        $all_computers | Export-Csv "$domain LARGE $date.csv"
}



编辑1:



更新的代码以反映SodaWillow,TheMadTechnician和
的建议,删除修剪并将其替换为-replace会稍微减少运行时间。

Edit 1:

Updated code to reflect suggestions from SodaWillow, TheMadTechnician, and removing trim and replacing it with -replace decreased runtime by a little bit.

在TheMadTechnician建议的基础上,将代码更新为正确的解决方案,我过滤了组以减少其数量并插入将名称分组为数组而不是表。与减少的组号结合使用数组会大大加快操作。

Updated the code to the correct solution, ontop of TheMadTechnician's suggestions I filtered the groups to decrease their number and also inserted group names into an array rather than a table. The use of an array sped up operations significantly when combined with the decreased group numbers.

当前错误:两种管理类型都已正确导出为CSV,但没有报告完全在文本文件中,我认为这与if语句中的逻辑有关。我目前正在查看

Current bugs: The "Both" admin types are being exported to CSV correctly but not being reported in the text file at all, I think it has to do with the logic in the if statement. I am looking at that currently

修复了两个管理员类型的逻辑错误,这是最终的错误解决这个问题的方法。由于私人信息,
的$ domains变量被声明在此代码块的视线之外。

Fixed Both admin type logic bug, this is the final solution for this problem. the $domains var is declared out of view of this code block due to private information.

感谢大家的宝贵时间!

推荐答案

好吧,看来至少您可以从组合某些行中受益。您可以在几个地方定义变量,然后通过过滤自身立即重新定义它。例如:

Well, it looks like at the least you could benefit from combining some lines. There's a few places that you define a variable, and then immediately redefine it by filtering itself. Such as:

$servs = $all_computers | Select-Object Name,DistinguishedName
$servs = $servs -Match "Servers" 

Can减少为:

$servs = $all_computers | Select-Object Name,DistinguishedName | Where {$_ -match "Servers"}

现在,对于 $ admin_exist_cnt 和 $ upep_admin_exist_cnt

$admin_exist_cnt = Compare-Object -DifferenceObject $group_name -ReferenceObject $com_name_admin -ExcludeDifferent -IncludeEqual -Property name | select-object @{name="name";expression={$($_.name).toString().TrimEnd("A","d","m","i","n","s")}}

$upep_admin_exist_cnt = Compare-Object -DifferenceObject $group_name -ReferenceObject $com_name_upep -ExcludeDifferent -IncludeEqual -Property name | Select-Object @{name="name";expression={$($_.Name).ToString().TrimEnd("U","P","E","P","A","d","m","i","n","s")}}

然后在最后,您遍历所有计算机,寻找两种管理类型,然后从 $ all_computers 变量中删除它们,然后再次遍历整个过程,并执行类似的操作4次。不,不要那样做,而是使用 Switch 命令。看起来像这样:

Then near the end you run through all the computers looking for "both" admintypes, and remove those from the $all_computers variable, then run through the whole thing again, and do that like 4 times. No, don't do that, use the Switch command instead. It would look like this:

Switch($all_computers){
    #Finding all of the accounts where both types of admins exist and removing them from the master list
    {$both_exist_cnt.name -contains $_.name} {$_ | Add-Member "admintype"  "both";Continue}
    #Finding all of the accounts with only exception admins and removing them from the master list
    {$admin_exist_cnt.name -contains $_.name} {$_ | Add-Member "admintype" "old";Continue}
    #Finding all of the accounts with only upep admins and removing them from the master list
    {$upep_admin_exist_cnt.name -contains $_.name} {$_ | Add-Member "admintype" "UPEP";Continue}
    #These accounts have no admin
    default {$_ | Add-Member "admintype" "No"}
}

然后您可以减少输出

#output
$all_computers | Export-Csv test.csv

编辑:好的,回顾一下事情看到您正在重新定义很多东西。相反,我建议只通过 Switch 运行一次,然后再计算结果。这将显着减少内存消耗,这在小规模测试运行中可能无关紧要,但是在大批量运行时应该有很大的不同。试试这个经过修改的脚本,如果您有任何特定的问题,请告诉我:

Ok, went back over things and saw that you're redefining things a whole lot. Instead I propose just running it through a Switch once, then counting up your results afterwards. This will reduce memory consumption considerably, which may not matter on small test runs but should make a considerable difference when running against large quantities. Try this revised script, and let me know if you have any specific questions:

#TODO Fix the server thing and put it in a for loop
$all_computers = Get-ADComputer -Server NW -filter * -Properties enabled | select name,enabled,distinguishedname
#Gets all of the objects that are in a group and pulls their names this is to get the admin flag that is appended to names in this group
$group_name = Get-ADObject -Server NW -Filter{objectCategory -eq "group"} | select name

#Counts the devices pulled from the computer query
#TODO Replace "test.txt" with a descriptive file name
$DevNum = $all_computers.count
echo "Number of devices: " $DevNum > test.txt

#Remove servers from the list
$all_computers = $all_computers | ?{ $_ -NotMatch "Servers" }

#Counts the number of servers we removed
$NumSkipped = $DevNum - $all_computers.count

Switch($all_computers){
    #Finding all of the accounts where both types of admins exist and removing them from the master list
    {$group_name.name -contains $($_.name + "Admins") -and $group_name.name -contains $($_.name + "UPEPAdmins")} {$_ | Add-Member "admintype"  "both";Continue}
    #Finding all of the accounts with only exception admins and removing them from the master list
    {$group_name.name -contains $($_.name + "Admins")} {$_ | Add-Member "admintype" "old";Continue}
    #Finding all of the accounts with only upep admins and removing them from the master list
    {$group_name.name -contains $($_.name + "UPEPAdmins")} {$_ | Add-Member "admintype" "UPEP";Continue}
    #These accounts have no admin
    default {$_ | Add-Member "admintype" "No"}
}

#TODO Replace "test.txt" with a descriptive file name
echo "Number of servers skipped: " $NumSkipped >> test.txt

#Calculating the number of workstations 
echo "Number of workstations: " $all_computers.count >> test.txt

#TODO Replace "test.txt" with a descriptive file name
echo "Number of Exception admins found: " $($all_computers|?{$_.admintype -match "old|both"}).count >> test.txt

#TODO Replace "test.txt" with a descriptive file name
echo "Number of UPEP admins found: " $($all_computers|?{$_.admintype -match "upep|both"}).count >> test.txt

#Find both exception and upep admin names
if($($all_computers|?{$_.admintype -ne "No"}))
{
        echo "Number of both UPEP and Exception Admins: 0" >> test.txt
}else
{
        echo "Number of both UPEP and Exception Admins: " $($all_computers|?{$_.admintype -match "both"}).count >> test.txt
}

#output
$all_computers | Export-Csv test.csv

这篇关于如何加快对AD对象的PowerShell操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆