Optimalkan filter Get-ADUser
Di AD, saya mencoba untuk mengidentifikasi akun pengguna di mana nilai EmployeeID yang sama diisi dalam 2 atau lebih catatan. Di bawah ini adalah potongan kode saya (Kredit: Saya menggunakan Show-Progress
fungsi yang ditentukan di sini ) dan Get-ADUser
perintahnya sendiri telah memakan waktu lebih dari 2 jam untuk mengambil semua catatan. Langkah lainnya (2 hingga 5) cukup cepat. Sementara saya telah menyelesaikan pekerjaan, saya mencoba untuk mengetahui apakah ini dapat dilakukan dengan lebih efisien dengan PowerShell.
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
PS: Saya juga mencoba untuk mengekspor semua akun pengguna ke file csv dan kemudian pasca-proses dengan Excel tetapi saya harus cemberut karena ukuran dataset dan itu adalah waktu dan memori yang berderak.
Setiap saran sangat dihargai.
Jawaban
Karena kami tidak tahu apa yang ada di dalam $properties
atau $selectPropsList
, pertanyaan Anda sebenarnya hanya tentang mencari tahu pengguna mana yang telah diberikan EmployeeID yang sama, bukan?
Secara default, Get-ADUser sudah mengembalikan properti ini:
DistinguishedName
, Enabled
, GivenName
, Name
, ObjectClass
, ObjectGUID
, SamAccountName
, SID
, Surname
,UserPrincipalName
Jadi yang Anda butuhkan tambahan adalah EmployeeID. Mencoba mengumpulkan BANYAK properti memang memperlambat, jadi menjaga ini seminimal mungkin membantu mempercepat pekerjaan.
Selanjutnya, dengan menggunakan Show-Progress
skrip yang telah Anda tautkan, Anda akan sangat memperlambat eksekusi skrip. Apakah Anda benar-benar perlu memiliki bilah kemajuan? Mengapa tidak langsung menulis baris dengan langkah-langkah aktivitas ke konsol?
Selain itu, menyatukan semuanya juga tidak membantu dalam departemen kecepatan ..
$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
sudah mengembalikan objek pengguna saja, jadi filter LDAP tidak diperlukan (ObjectCategory=Person)(objectclass=user)
. Menggunakan -Filter "EmployeeID -like '*'"
mungkin lebih cepat
Jawaban ini melengkapi jawaban Theo yang sangat membantu dan berfokus untuk menunjukkan kemajuan selama operasi :
The terkait Show-Progressfungsi , yang terbaru saat tulisan ini:
memiliki bug langsung , yaitu tidak melewatkan masukan pipeline (baris yang relevan tidak sengaja dikomentari)
secara konseptual cacat karena tidak menggunakan
process
blok, yang berarti bahwa semua input pipeline dikumpulkan terlebih dahulu , sebelum diproses - yang mengalahkan gagasan tentang bilah kemajuan.
Oleh karena itu,
Show-Progress
panggilan Anda tidak akan menampilkan kemajuan hingga perintah sebelumnya dalam pipeline mengeluarkan semua keluarannya. Alternatif sederhana adalah dengan memecah pipeline menjadi perintah terpisah dan hanya memancarkan satu pesan kemajuan sebelum setiap perintah, mengumumkan tahap pemrosesan berikutnya (bukan kemajuan per objek) seperti yang ditunjukkan dalam jawaban Theo.Secara umum, tidak ada cara untuk menunjukkan kemajuan pemrosesan internal perintah , hanya kemajuan keluaran perintah (multi-objek) .
Cara termudah untuk melakukan ini melalui ForEach-Objectpanggilan yang Anda panggil
Write-Progress, tetapi itu memiliki dua tantangan:Untuk menampilkan bilah kemajuan persen selesai , Anda perlu mengetahui berapa banyak objek yang akan ada , yang harus Anda tentukan sebelumnya , karena pipeline tidak dapat mengetahui berapa banyak objek yang akan diterimanya; satu-satunya pilihan Anda adalah mengumpulkan semua keluaran terlebih dahulu (atau mencari cara lain untuk menghitungnya) dan kemudian menggunakan keluaran yang dikumpulkan sebagai masukan pipa, menggunakan hitungan objek sebagai dasar untuk menghitung nilai yang akan diteruskan
Write-Progress -PerCentComplete
.Memanggil
Write-Progress
untuk setiap objek yang diterima akan mengakibatkan perlambatan yang signifikan dari keseluruhan pemrosesan; kompromi adalah dengan hanya memanggilnya untuk setiap N objek, seperti yang ditunjukkan dalam jawaban ini ; pendekatan di sana bisa dibungkus dalam fungsi yang diimplementasikan dengan benar a laShow-Progress
yang mengharuskan melewatkan jumlah objek total sebagai argumen dan melakukan streaming pemrosesan objek input yang tepat (melaluiprocess
blok); yang mengatakan, tindakan menggunakan kode PowerShell untuk melewatkan objek input saja mahal.
Kesimpulan:
Tampilan kemajuan persen-selesai memiliki dua masalah yang melekat :
Mereka mengharuskan Anda untuk mengetahui jumlah total objek yang akan diproses sebelumnya (pipeline tidak memiliki cara untuk mengetahui berapa banyak objek yang akan melewatinya):
Salah satu: Kumpulkan semua objek untuk diproses dalam memori , sebelumnya , jika memungkinkan; jumlah elemen dalam koleksi kemudian bisa menjadi dasar untuk penghitungan persen-selesai. Ini mungkin bukan opsi dengan kumpulan masukan yang sangat besar.
Atau: Lakukan langkah pemrosesan tambahan sebelumnya yang hanya menghitung semua objek tanpa benar-benar mengambilnya. Ini mungkin tidak praktis dalam hal penambahan waktu pemrosesan.
Pemrosesan objek demi objek dalam kode PowerShell - baik melalui ForEach-Objectatau skrip / fungsi lanjutan - pada dasarnya lambat.
- Anda dapat menguranginya dengan membatasi Write-Progresspanggilan ke setiap objek N, seperti yang ditunjukkan dalam jawaban ini
Secara keseluruhan, ini adalah tradeoff antara kecepatan pemrosesan dan kemampuan untuk menunjukkan kemajuan persen-lengkap kepada pengguna akhir.