ऑप्टिमाइज़ गेट-एडयूज़र फ़िल्टर

Nov 29 2020

AD में, मैं उन उपयोगकर्ता खातों की पहचान करने की कोशिश कर रहा हूँ जहाँ समान कर्मचारी मूल्य 2 या अधिक रिकॉर्ड में आबाद है। नीचे मेरा कोड ऑफ कोड है (क्रेडिट: मैं यहांShow-Progress परिभाषित एक फ़ंक्शन का उपयोग कर रहा हूं ) और अकेले कमांड को सभी रिकॉर्ड प्राप्त करने में 2 घंटे से अधिक समय लगा है। अन्य चरण (2 से 5) बहुत तेज हैं। जब मैंने काम पूरा कर लिया है, तो मैं यह जानने की कोशिश कर रहा हूं कि क्या यह पावरशेल के साथ अधिक कुशलता से किया जा सकता है।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

पुनश्च: मैंने पहले सभी उपयोगकर्ता खातों को एक सीएसवी फ़ाइल में निर्यात करने की कोशिश की है और फिर एक्सेल के साथ पोस्ट-प्रोसेस किया है, लेकिन मुझे डेटासेट के आकार के कारण फुर्र होना पड़ा और यह समय और मेमोरी क्रंचिंग दोनों था।

किसी भी सुझाव की बहुत सराहना की है।

जवाब

2 Theo Nov 29 2020 at 16:20

चूँकि हम नहीं जानते कि क्या है $propertiesया $selectPropsList, आपका प्रश्न वास्तव में केवल यह पता लगाने के बारे में है कि उपयोगकर्ताओं को एक ही कर्मचारी जारी किया गया है, है ना?
डिफ़ॉल्ट रूप से, Get-ADUser पहले से ही इन गुणों को लौटाता है:

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

तो आप सभी की जरूरत है कि कर्मचारी मुझे लगता है कि है। बहुत सारे गुणों को इकट्ठा करने की कोशिश धीमी हो जाती है, इसलिए इसे नंगे न्यूनतम रखने से चीजों को गति देने में मदद मिलती है।

इसके बाद, आपके द्वारा Show-Progressलिंक की गई स्क्रिप्ट का उपयोग करके , आप स्क्रिप्ट के निष्पादन को काफी धीमा कर देंगे। क्या आपको वास्तव में प्रगति पट्टी की आवश्यकता है? सीधे कंसोल पर गतिविधि चरणों के साथ लाइनें क्यों नहीं लिखीं?

इसके अलावा, सब कुछ एक साथ पाइपिंग गति विभाग में मदद नहीं करता है या तो ..

$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-ADUserपहले से ही उपयोगकर्ता वस्तुओं को केवल वापस करता है, इसलिए LDAP फ़िल्टर की कोई आवश्यकता नहीं है (ObjectCategory=Person)(objectclass=user)। उपयोग करना -Filter "EmployeeID -like '*'"शायद तेज है

1 mklement0 Nov 29 2020 at 22:27

यह उत्तर थियो के सहायक उत्तर का पूरक है और ऑपरेशन के दौरान प्रगति दिखाने पर केंद्रित है :

  • लिंक किए गए Show-Progressसमारोह है, जो इस लेखन के रूप में नवीनतम है:

    • इसमें एक बाहरी बग है , इसमें पाइपलाइन इनपुट पास नहीं है (संबंधित लाइन गलती से टिप्पणी की गई है)

    • इस दृष्टि से दोषपूर्ण है कि यह एक processब्लॉक का उपयोग नहीं करता है , जिसका अर्थ है कि संसाधित होने से पहले सभी पाइपलाइन इनपुट एकत्र किए जाते हैं - जो प्रगति पट्टी के विचार को पराजित करता है।

  • इसलिए, आपको Show-Progressकॉल तब तक प्रगति नहीं दिखाएगी जब तक कि पाइप लाइन में पिछली कमांड अपने सभी आउटपुट का उत्पादन नहीं करती है। एक सरल विकल्प यह है कि पाइपलाइन को अलग-अलग कमांडों में तोड़ दिया जाए और थियो के उत्तर में दिखाए गए अनुसार प्रसंस्करण के अगले चरण (बल्कि प्रति-वस्तु प्रगति) की घोषणा करते हुए, प्रत्येक कमांड से पहले एक प्रगति संदेश को छोड़ दें ।

  • आम तौर पर, कमांड-आंतरिक प्रसंस्करण की प्रगति को दिखाने का कोई तरीका नहीं है , केवल एक कमांड (मल्टी-ऑब्जेक्ट) आउटपुट की प्रगति है ।

    • ऐसा करने का सबसे सरल तरीका है ForEach-Objectजिसमें आप कॉल करते हैं
      Write-Progress, लेकिन यह दो चुनौतियों के साथ आता है:

      • प्रतिशत-पूर्ण प्रगति पट्टी दिखाने के लिए , आपको यह जानना होगा कि कुल कितनी वस्तुएँ होंगी , जिन्हें आपको समय से पहले निर्धारित करना होगा , क्योंकि एक पाइपलाइन यह नहीं जान सकती है कि उसे कितनी वस्तुएँ प्राप्त होंगी; आपका एकमात्र विकल्प सबसे पहले सभी आउटपुट को इकट्ठा करना है (या इसे गिनने का कोई और तरीका खोजना है) और फिर एकत्रित इनपुट का उपयोग पाइपलाइन इनपुट के रूप में करना है, पास करने के लिए मूल्य की गणना के आधार के रूप में वस्तुओं की गिनती का उपयोग करना Write-Progress -PerCentComplete

      • प्राप्त प्रत्येक वस्तु के Write-Progressलिए कॉल करने से समग्र प्रसंस्करण में एक महत्वपूर्ण मंदी आएगी ; एक समझौता केवल प्रत्येक एन वस्तुओं के लिए इसे कॉल करना है, जैसा कि इस उत्तर में दिखाया गया है ; दृष्टिकोण को एक उचित रूप से लागू किए गए फ़ंक्शन में एक ला में लपेटा जा सकता है जिसे एक तर्क के रूप में कुल ऑब्जेक्ट गिनती पास करने की आवश्यकता होती है और उचित स्ट्रीमिंग इनपुट-ऑब्जेक्ट प्रोसेसिंग (एक ब्लॉक के माध्यम से ) करता है; उस ने कहा, के माध्यम से इनपुट वस्तुओं को पारित करने के लिए PowerShell कोड का उपयोग करने का मात्र कार्य महंगा है।Show-Progressprocess


निष्कर्ष:

प्रतिशत-पूर्ण प्रगति डिस्प्ले में दो अंतर्निहित समस्याएं हैं :

  • उन्हें पहले से संसाधित करने के लिए आपको वस्तुओं की कुल संख्या जानने की आवश्यकता है (एक पाइपलाइन को यह जानने का कोई तरीका नहीं है कि कितनी वस्तुएं इसके माध्यम से गुजरेंगी):

    • या तो: स्मृति में संसाधित करने के लिए सभी वस्तुओं को इकट्ठा करें , पहले से , यदि संभव हो तो; संग्रह में तत्वों की गिनती तब पूर्ण-गणना के आधार के रूप में कार्य कर सकती है। यह बहुत बड़े इनपुट सेट के साथ एक विकल्प नहीं हो सकता है।

    • या: पहले से एक अतिरिक्त प्रसंस्करण चरण का प्रदर्शन करें जो केवल सभी वस्तुओं को वास्तव में पुनर्प्राप्त किए बिना गिनता है। अतिरिक्त प्रसंस्करण समय के संदर्भ में यह व्यावहारिक नहीं हो सकता है।

  • PowerShell कोड में ऑब्जेक्ट-बाय-ऑब्जेक्ट प्रोसेसिंग - या तो ForEach-Objectएक उन्नत स्क्रिप्ट / फ़ंक्शन के माध्यम से - स्वाभाविक रूप से धीमा है।

    • आप इस उत्तरWrite-Progress में दिखाए गए अनुसार हर N ऑब्जेक्ट पर कॉल सीमित करके उसे कुछ हद तक कम कर सकते हैं

कुल मिलाकर यह प्रसंस्करण गति और अंतिम उपयोगकर्ता के लिए प्रतिशत-पूर्ण प्रगति दिखाने की क्षमता के बीच एक व्यापार है