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.

 

-o((:: sprEad the l0ve ::))o-

Comments (1)

  1. SieQ

    Odpowiedz

    Z tego co pamiętam, korzystając z EMS’a dla Exchange 2010 SP1+, można korzystać z metody remove dla EmailAddress. Nie mam pod ręką laba, aby sprawdzić dokładną składnię.

Skomentuj SieQ Anuluj pisanie odpowiedzi

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Time limit is exhausted. Please reload CAPTCHA.