2016-05-23 31 views
2

我正在编写一个脚本,用于查询我们所有AD域的工作,然后返回具有管理权限的计算机。下面的脚本工作并返回预期的结果,但它在我们较大的域上非常缓慢。如何加快AD对象上的PowerShell操作

当使用23k以下的对象时,只需几分钟(6分钟左右)就可以运行,但当它处理90k +时,就会花费数小时。

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

有没有一种方法可以加速运行快几个小时?任何帮助将不胜感激。

$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替换它通过一点点降低运行时的建议。

编辑2:

更新了代码的正确解,TheMadTechnician的建议ontop的我过滤组以降低它们的数量,并且还插入组名称到一个数组,而不是一个表。与减少的组数相结合,阵列的使用显着加快了操作速度。

当前错误:“两个”管理员类型正确导出到CSV,但没有在文本文件中报告,我认为它与if语句中的逻辑有关。我在看,目前

编辑3:

固定两种管理类型的逻辑错误,这是对这个问题的最终解决方案。 由于私人信息,$ domains var会在此代码块的视图之外声明。

谢谢大家,你的时间!

+0

您可能想尝试LDAP过滤器和'System.DirectoryServices.DirectorySearcher'(示例在这里:http://www.powershelladmin.com/wiki/Getting_usernames_from_active_directory_with_powershell)。测量代码的每个部分所耗费的时间以查找最长的查询,然后从优化那些开始(如果您还没有这样做) – sodawillow

+0

我试图在代码块上运行并使用Measure-Command来测试看看我可能会增加不必要的时间。没有什么似乎是过度的,但是如果放在一起需要很长时间 – Mack

+0

我会想象L2和L4的持续时间比其他时间长得多。也许可以用'Get-ADGroup'来重写L4? – sodawillow

回答

1

那么,看起来至少你可以从组合一些行中受益。有几个地方可以定义一个变量,然后立即通过过滤来重新定义它。如:

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

可降低到:

$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")}} 

然后在附近最后你遍历所有寻找“两个”admintypes的计算机,并从$all_computers变量中删除这些变量,然后再次运行整个事情,并做4次。不,不这样做,请改用Switch命令。它应该是这样的:

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,然后再计算结果。这将大大降低内存消耗,这在小型测试运行中可能无关紧要,但在大批量运行时应该会产生相当大的差异。试试这个修改后的脚本,并让我知道如果您有任何具体问题:

#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 
+0

我在脚本的一个分支上进行了更改,并在测试平台服务器上多次运行它,平均而言,它将运行时间增加了6秒(至36秒)。以前在测试台服务器上的迭代能够在30秒内完成。 switch语句中是否有某些东西比我所做的要好,因为你失去了重新定义变量的开销? 另外,感谢您的时间和帮助,我真的很感激! :) – Mack

+0

我重新读你的脚本,我正在做一些重大的改变,并会回复给你。我认为肯定会有一些改进,可以加快速度并帮助管理更大的迭代内存。 – TheMadTechnician

+0

好的,再次感谢。 刚刚起来,我删除了修剪命令,并用替换它替换为 '$ upep_admin_exist_cnt =比较对象-DifferenceObject $组名称 - 引用对象$ com_name_upep -ExcludeDifferent -IncludeEqual - 属性名称| Select-Object @ {name =“name”; expression = {$($ _。Name).ToString()-replace“UPEPAdmins”}}' 现在是它的样子,我将更新我的问题以反映您的目前的建议和我的改变! – Mack

0

根据PowerShell的版本,您有可用(IIRC你需要PSv4),您可以使用。凡方法对你的列表,它是更快:

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

我怀疑使用选择后来也快了一点点,但这只是猜测。

+0

实际使用 {$ _ -eq“服务器”} 可能会更快;) – whatever