Get-ADUser filtresini optimize edin

Nov 29 2020

AD'de, aynı EmployeeID değerinin 2 veya daha fazla kayıtta doldurulduğu kullanıcı hesaplarını belirlemeye çalışıyorum. Aşağıda kod parçam var (Kredi: BuradaShow-Progress tanımlanan bir işlevi kullanıyorum ) ve tek başına komutun tüm kayıtları getirmesi 2 saatten fazla sürdü. Diğer adımlar (2 ila 5) oldukça hızlı oldu. Çalışmayı tamamlarken, bunun PowerShell ile daha verimli bir şekilde yapılıp yapılamayacağını öğrenmeye çalışıyorum.Get-ADUser

Get-ADUser -LDAPFilter "(&(ObjectCategory=Person)(objectclass=user)(employeeid=*))" -Properties $properties -Server $server_AD_GC -ResultPageSize 1000 | 
    # *ISSUE HERE*
    #    The Get-ADUser extract process seems to work very slow.
    #    However, it is important to note that the above command will be retrieving more than 200K records
    # NOTE: I've inferred that employeeid is an indexed attribute and is replicated to GlobalCatalogs and hence have used it in the filter
    Show-Progress -Activity "(1/5) Getting AD Users ..." |
select $selectPropsList -OutVariable results_UsersBaseSet | Group-Object EmployeeID | Show-Progress -Activity "(2/5) Grouping on EmployeeID ..." | ? { $_.Count -gt 1 } | 
    Show-Progress -Activity "(3/5) Filtering only dup EmpID records ..." | 
select -Exp Group | 
    Show-Progress -Activity "(4/5) UnGrouping ..." | 
Export-Csv "C:\Users\me\op_GetADUser_w_EmpID_Dupes_EntireForest - $([datetime]::Now.ToString("MM-dd-yyyy_hhmmss")).csv" -NoTypeInformation |
    Show-Progress -Activity "(5/5) Exporting ..." | 
Out-Null

Not: Ayrıca önce tüm kullanıcı hesaplarını bir csv dosyasına aktarmayı ve ardından Excel ile son işlem yapmayı denedim, ancak veri kümesinin boyutu nedeniyle kaşlarımı çatmak zorunda kaldım ve hem zaman hem de bellek sıkıştı.

Herhangi bir öneri çok takdir edilmektedir.

Yanıtlar

2 Theo Nov 29 2020 at 16:20

İçinde $propertiesveya içinde ne olduğunu bilmediğimiz $selectPropsListiçin, sorunuz gerçekten yalnızca aynı EmployeeID'nin hangi kullanıcılara verildiğini bulmakla ilgili değil mi?
Varsayılan olarak, Get-ADUser şu özellikleri zaten döndürür:

DistinguishedName, Enabled, GivenName, Name, ObjectClass, ObjectGUID, SamAccountName, SID, Surname,UserPrincipalName

Yani fazladan ihtiyacınız olan tek şey, sanırım EmployeeID. ÇOK sayıda mülk toplamaya çalışmak yavaşlar, bu yüzden bunu minimumda tutmak işleri hızlandırmaya yardımcı olur.

Daha sonra, Show-Progressbağlandığınız betiği kullanarak , betiğin çalışmasını önemli ölçüde yavaşlatacaksınız. Gerçekten bir ilerleme çubuğuna ihtiyacınız var mı? Neden etkinlik adımlarını içeren satırları doğrudan konsola yazmıyorsunuz?

Ayrıca, her şeyi bir araya getirmek hız departmanında da yardımcı olmaz

$server_AD_GC = 'YourServer' $selectPropsList = 'EmployeeID', 'Name', 'SamAccountName', 'Enabled'
$outFile = "C:\Users\me\op_GetADUser_w_EmpID_Dupes_EntireForest - $([datetime]::Now.ToString("MM-dd-yyyy_hhmmss")).csv"

Write-Host "Step (1/4) Getting AD Users ..." 
$users = Get-ADUser -Filter "EmployeeID -like '*'" -Properties EmployeeID -Server $server_AD_GC -ResultPageSize 1000

Write-Host "Step (2/4) Grouping on EmployeeID ..."
$dupes = $users | Group-Object -Property EmployeeID | Where-Object { $_.Count -gt 1 } Write-Host "Step (3/4) Collecting duplicates ..." $result = foreach ($group in $dupes) {
    $group.Group | Select-Object $selectPropsList
}

Write-Host "Step (4/4) Exporting ..."
$result | Export-Csv -Path $outFile -NoTypeInformation

Write-Host  "All done" -ForegroundColor Green

PS Get-ADUserzaten yalnızca kullanıcı nesnelerini döndürür, bu nedenle LDAP filtresine gerek yoktur (ObjectCategory=Person)(objectclass=user). Kullanmak -Filter "EmployeeID -like '*'"muhtemelen daha hızlıdır

1 mklement0 Nov 29 2020 at 22:27

Bu cevap tamamlar Theo'nun faydalı bir yanıt ve odaklanır ilerlemeyi gösteren çalışma sırasında :

  • Bağlantılı Show-Progressfonksiyonu bu yazı yazılırken son olduğunu:

    • boru hattı girişini geçmemesi nedeniyle doğrudan bir hataya sahiptir (ilgili hat yanlışlıkla yorumlanır)

    • kavramsal olarak kusurludur çünkü bir processblok kullanmaz , bu da tüm boru hattı girdilerinin işlenmeden önce toplandığı anlamına gelir - bu da ilerleme çubuğu fikrini geçersiz kılar.

  • Bu nedenle, Show-Progresskanaldaki önceki komut tüm çıktılarını verene kadar çağrılarınız ilerleme göstermeyecektir . Basit bir alternatif, boruhattı ayrı komutlara bölmek ve her komuttan önce basitçe bir ilerleme mesajı yayınlayarak , Theo'nun cevabında gösterildiği gibi işlemin bir sonraki aşamasını (nesne başına ilerleme yerine) duyurmaktır .

  • Genel olarak, dahili komut işlemenin ilerlemesini göstermenin bir yolu yoktur , yalnızca bir komutun (çoklu nesne) çıktısının ilerleyişini gösterir .

    • Bunu, ForEach-Objectaradığınız bir arama yoluyla yapmanın en basit yolu
      Write-Progress, ancak bunun iki zorluğu vardır:

      • Bir göstermek için yüzde tamamlama ilerleme çubuğu, toplamda olacak kaç nesneleri bilmek gerekir belirlemek gerekir, vaktinden bir nedeni, boru hattı da alacaksınız kaç nesneleri bilemez; Tek seçeneğiniz, önce tüm çıktıları toplamak (veya saymanın başka bir yolunu bulmak) ve sonra toplanan çıktıyı, nesnelerin sayısını geçilecek değeri hesaplamak için temel olarak kullanarak boru hattı girdisi olarak kullanmaktır Write-Progress -PerCentComplete.

      • Arama Write-Progressiçin her bir neden olur alınan nesnenin önemli bir yavaşlamaya genel işlem; bir uzlaşma, bu cevapta gösterildiği gibi, onu yalnızca her N nesne için çağırmaktır ; buradaki yaklaşım Show-Progress, toplam nesne sayısının bir argüman olarak geçirilmesini gerektiren ve uygun akışlı girdi-nesne işlemesini (bir processblok aracılığıyla ) gerçekleştiren, düzgün bir şekilde uygulanan bir fonksiyona la sarılabilir ; Bununla birlikte, giriş nesnelerini geçirmek için PowerShell kodunu kullanmanın tek eylemi maliyetlidir.


Sonuç:

Yüzde tamamlanan ilerleme ekranlarının iki temel sorunu vardır :

  • Önceden işlenecek toplam nesne sayısını bilmenizi gerektirir (bir boru hattının içinden kaç nesnenin geçeceğini bilme yolu yoktur):

    • Ya: Mümkünse , önceden işlenecek tüm nesneleri bellekte toplayın ; koleksiyondaki öğelerin sayısı tamamlanma yüzdesi hesaplamaları için temel oluşturabilir. Bu, çok büyük girdi kümelerinde bir seçenek olmayabilir.

    • Veya: Önceden, yalnızca tüm nesneleri gerçekten geri getirmeden sayan fazladan bir işleme adımı gerçekleştirin . Bu, eklenen ek işlem süresi açısından pratik olmayabilir.

  • PowerShell kodunda nesne-nesne işleme - ya ForEach-Objectda gelişmiş komut dosyası / işlev aracılığıyla - doğası gereği yavaştır.

    • Bu cevaptaWrite-Progress gösterildiği gibi, çağrıları her N nesneyle sınırlandırarak bunu hafifletebilirsiniz.

Genel olarak, işlem hızı ile son kullanıcıya tamamlanma yüzdesi ilerlemesini gösterme yeteneği arasında bir değiş tokuş .