scenariusz: w atrybucie proxyAddresses w AD użytkownicy mają wpisane nieużywane adresy X4oo, które trzeba było usunąć. prościzna… przynajmniej tak mi się wydawało. sporo ciekawych drobiazgów przy tym wyszło i zadanie, które oceniałem na 15-2o min zajęło mi ze 2h /:
a takież to ciekawostki powychodziły…
najpierw trzeba wyszukać wszystkie obiekty [user/contact], które mają w proxyaddresses X400. szczęśliwie filtry są na tyle sprytne, że radzą sobie z multivalue [zaraz napiszę jak to robią] i nie trzeba się męczyć z jakimiś konwersjami:
get-adobject -f {proxyaddresses -like "*x400*"} -properties proxyaddresses|%{ <...tu bedzie obsluga...> }
w 'normalnym’ języq, trzeba by się pomęczyć najpierw wyszuqjąc wszystkie obiekty posiadające wartość proxyaddresses, potem konwertując tablicę do stringa, a potem sprawdzić czy w tym stringu jest wartość x400 – bo w 'normalnym’ języq świat nie jest tak prosty (;
#tak nie trzeba robić, bo PowerShell rządzi! get-adobject -f {proxyaddresses -like "*"} -properties proxyaddresses|%{ $pa=$_.proxyaddresses -join ';' if( $pa -like "*X400*") { <...>
proxyaddresses jest tupu 'mulivalue’ czyli jako parametr przyjmuje tablicę stringów i z tejże tablicy trzeba usunąć linijkę, która zawiera wartość 'x4oo’. wartość można łatwo odczytać, ale jak z tej tablicy wywalić ową linijkę?i tutaj czas na wyjaśnienie, jakim cudem filtr zadziałał dla tablicy tak, jakby to był pojedynczy string. spróbuję to zobrazować na trochę prostszym przykładzie:
C:\ :))o- $a=@("abc","cde","efg") C:\ :))o- $a abc cde efg C:\ :))o- $a|gm TypeName: System.String Name MemberType Definition ---- ---------- ---------- Clone Method System.Object Clone(), System.Object ICloneable.Clone() <...CUT..> Replace Method string Replace(char oldChar, char newChar), string Replace(string ol.. <...CUT...>
na powyższym przykładzie widać, że po zdefiniowaniu tablicy i sprawdzeniu jej typu przy pomocy get-member, PS traktuje ją jak zwykły string… jeśli jednak sprawdzi się typ zmiennej….
C:\ :))o- $a.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True Object[] System.Array
choć nieco dziwne, to wiele ułatwia. pozostaje jednak nadal pytanie – jak łatwo usunąć element z tablicy stringów? można kombinować z metodami replace i remove, które tu zadziałają jak dla zwykłego stringa, ale dają średnie rezultaty. dużo ciekawszym sposobem jest metoda remove, dla klasy ArrayList.
get-adobject -f {proxyaddresses -like "*x400*"} -properties proxyaddresses|%{ $newpa=[System.Collections.ArrayList]$_.proxyaddresses foreach($p in $_.proxyaddresses) { if($p -like '*x400*') {$newpa.remove($p)} } set-adobject $_ -Replace @{proxyaddresses=[array]$newpa} }
na koniec jeszcze jedna ciekawostka. zanim wpadłem na konwersję do ArrayList, kombinowałem z przepisaniem zmiennej do drugiej tablicy i próbowałem wycinać z niej wartości na różne sposoby. tak trafiłem na kolejną 'ciekawostkę’ – w cudzysłowiu, bo de facto taki sposób działania jest normalny dla środowisk obiektowych: powiązanie zmiennej z atrybutem obiektu jest robione przez referencję a nie jest ona kopiowana. taki jakiś niedziałający kod:
get-adobject -f {proxyaddresses -like "*x400*"} -properties proxyaddresses|%{ $newpa=$_.proxyaddresses foreach($p in $_.proxyaddresses) { if($p -like '*x400*') {$newpa.remove($p)} } set-adobject $_ -Replace @{proxyaddresses=$newpa} }
podczas działania dostawałem taki błąd:
An error occurred while enumerating through a collection: Collection was modified; enumeration operation may not execute..At D:\ISCG\scriptz\cleanX400.ps1:11 char:16
+ foreach <<<< ($p in $_.proxyaddresses) {
+ CategoryInfo : InvalidOperation: (System.Collecti…numeratorSimple:ArrayListEnumeratorSimple) [], RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
kolekcja została zmodyfikowana… i faktycznie – kiedy sprawdziłem modyfikacje na $newpa, wyświetlenie $_.proxyaddresses je odzwierciedlało. wniosek – z obiektami nie ma żartów, trzeba uważać (;
na koniec jeszcze jedna metoda usuwania konkretnej linii a tablicy stringów, która jednak mi się nie przydała, ponieważ trzeba znać index. załóżmy, że chcę usunąć 4tą wartość:
$a=@('abc','def',1,5,8,'fgt',43) $a=$a[0..2+4..($a.Length-1)]
reasumując – atrybuty zostały poprawione, a te 2h nie poszły na marne – rozumiem bardziej ^^
eN.
SieQ