AD objektumok tulajdonságainak kiolvasása, módosítása

Ha PowerShell, akkor objektumok. Az előzőekhez hasonlóan csatlakozzunk a most létrehozott szervezeti egység objektumhoz, és nézzük meg a tagjellemzőit a get-member cmdlet segítségével:

PS C:\> $adou = [ADSI] "LDAP://OU=Emberek,DC=iqjb,DC=w08"

PS C:\> $adou

 

distinguishedName

-----------------

{OU=Emberek,DC=iqjb,DC=w08}

 

 

PS C:\> $adou | get-member

 

 

   TypeName: System.DirectoryServices.DirectoryEntry

 

Name                  MemberType Definition

----                  ---------- ----------

description           Property   System.DirectoryServices.PropertyValueC...

distinguishedName     Property   System.DirectoryServices.PropertyValueC...

dSCorePropagationData Property   System.DirectoryServices.PropertyValueC...

instanceType          Property   System.DirectoryServices.PropertyValueC...

name                  Property   System.DirectoryServices.PropertyValueC...

nTSecurityDescriptor  Property   System.DirectoryServices.PropertyValueC...

objectCategory        Property   System.DirectoryServices.PropertyValueC...

objectClass           Property   System.DirectoryServices.PropertyValueC...

objectGUID            Property   System.DirectoryServices.PropertyValueC...

ou                    Property   System.DirectoryServices.PropertyValueC...

uSNChanged            Property   System.DirectoryServices.PropertyValueC...

uSNCreated            Property   System.DirectoryServices.PropertyValueC...

whenChanged           Property   System.DirectoryServices.PropertyValueC...

whenCreated           Property   System.DirectoryServices.PropertyValueC...

Hát elég furcsa, amit kaptunk. Látjuk a szervezeti egységünk tulajdonságait, de hol vannak a metódusok? Hol a Create? Sajnos a PowerShell-ben nincsen 100%-ban adaptálva a System.DirectoryServices osztály. Ennek több oka van. Az egyik, hogy valójában itt nem színtiszta .NET osztályról van szó, hanem COM objektum is meghúzódik a felszín alatt, és annak metódusait nem olyan egyszerű átemelni. Gondoljunk csak arra, hogy egy ilyen DirectoryEntry típusú objektum lehet felhasználói fiók, számítógép fiók, telephely, csoport, stb., ezeknek mind más és más metódusuk van, ezeknek az adaptálása a PowerShell környezetbe nem olyan egyszerű. Ebből származik a második ok, ami miatt ez nincs adaptálva, az pedig az, hogy a fejlesztők az 1.0 megjelenését nem akarták ezzel késleltetni, várhatóan a 2.0 verzió már precízebb AD támogatást fog nyújtani.

Szerencsére van egy kis menekvési ösvényünk, azaz kikapcsolhatjuk a PowerShell adaptációs rétegét, és megnézhetjük a „színtiszta” .NET objektumot is, ha a psbase  nézeten keresztül nézzük az objektumunkat:

PS C:\> $adou.psbase | get-member

 

 

   TypeName: System.Management.Automation.PSMemberSet

 

Name                      MemberType Definition

----                      ---------- ----------

...

MoveTo                    Method     System.Void MoveTo(DirectoryEntry n...

RefreshCache              Method     System.Void RefreshCache(), System....

remove_Disposed           Method     System.Void remove_Disposed(EventHa...

Rename                    Method     System.Void Rename(String newName)

...

ToString                  Method     System.String ToString()

AuthenticationType        Property   System.DirectoryServices.Authentica...

Children                  Property   System.DirectoryServices.DirectoryE...

Container                 Property   System.ComponentModel.IContainer Co...

Guid                      Property   System.Guid Guid {get;}

Name                      Property   System.String Name {get;}

NativeGuid                Property   System.String NativeGuid {get;}

NativeObject              Property   System.Object NativeObject {get;}

ObjectSecurity            Property   System.DirectoryServices.ActiveDire...

Options                   Property   System.DirectoryServices.DirectoryE...

Parent                    Property   System.DirectoryServices.DirectoryE...

Password                  Property   System.String Password {set;}

Path                      Property   System.String Path {get;set;}

Properties                Property   System.DirectoryServices.PropertyCo...

SchemaClassName           Property   System.String SchemaClassName {get;}

SchemaEntry               Property   System.DirectoryServices.DirectoryE...

Site                      Property   System.ComponentModel.ISite Site {g...

UsePropertyCache          Property   System.Boolean UsePropertyCache {ge...

Username                  Property   System.String Username {get;set;}

A fenti, kicsit megvágott, de még így is hosszú listából látszik, hogy az objektumot valójában lehet például mozgatni, átnevezni, és néhány újabb tulajdonság is feltárul a szemünk előtt. De például még mindig nem látjuk a SetInfo és a Create metódust, mert ezek az ADSI COM interfészből jönnek, és a .NET nem kérdezi ezeket le, így nem is mutatja meg, viszont meghívni, használni lehet őket.

Vagy nézzük a következőket:

PS C:\> $d = [ADSI] ""

PS C:\> $d

 

distinguishedName

-----------------

{DC=iqjb,DC=w08}

A fenti módon például nagyon egyszerűen lehet az aktuális tartományunkhoz csatlakozni. Próbáljuk meg ennek megnézni a „rejtett” children tulajdonságát:

PS C:\> $adou = [ADSI] "LDAP://OU=Demó,DC=iqjb,DC=w08"

PS C:\> $adou.psbase.Children

 

distinguishedName

-----------------

{CN=Csilla Fájdalom,OU=Demó,DC=iqjb,DC=w08}

{CN=Csoport,OU=Demó,DC=iqjb,DC=w08}

{CN=group1,OU=Demó,DC=iqjb,DC=w08}

{CN=János Vegetári,OU=Demó,DC=iqjb,DC=w08}

{CN=Márton Beléd,OU=Demó,DC=iqjb,DC=w08}

Hiszen ez megadta az adott konténer objektumban található al-objektumokat!

Megjegyzés

A lokális gép esetében a PSBase egészen extrém információkat rejt el:

[40] PS C:\> $computer = [ADSI]"WinNT://."

[41] PS C:\> $v = $computer.psbase.children | ForEach-Object {$_}

[42] PS C:\> $v[0].name; $v[0].psbase.schemaclassname

Administrator

User

[43] PS C:\> $v[30].name; $v[30].psbase.schemaclassname

BITS

Service

A [40]-es sorban hozzákapcsolódom a helyi géphez egy $computer változón keresztül. Majd betöltöm egy $v változóba ennek a psbase által feltárt children tulajdonságának elemeit egy ciklussal. Ennek 0. elemének name tulajdonságát nézve kiderül, hogy ez egy helyi felhasználó, az Administrator. Ennek típusát is ki lehet olvasni egy újabb psbase feltárás után a schemaclassname tulajdonsággal.

A meglepetés akkor jön, ha egy jóval későbbi elemet nézünk meg, mondjuk a 90.-et. Nálam ez meg egy szolgáltatás volt, a BITS (a kedves olvasónál lehet, hogy ez valami más). Azaz a lokális gép esetében a children a gépnek nagyon sok jellemzőjét megadja. Az eligazodást segíti a Find metódus:

[47] PS C:\> $service = $computer.psbase.Children.Find("Alerter")

[48] PS C:\> $service.serviceaccountname

NT AUTHORITY\LocalService

Miután itt vegyes elemekkel dolgozunk, itt különösen jól jön a get-member cmdlet.

Mindebből az következik, hogy nem érdemes még kidobni korábbi ADSI ismereteinket, illetve ismernünk kell az AD objektumok tulajdonságainak neveit, hogy ezeket a tulajdonságokat módosíthassuk. Nézzünk ez utóbbira példát egy felhasználói fiókkal kapcsolatban. Van egy már létező felhasználóm, annak szeretném kiolvasni és beállítani a telefonszám tulajdonságát. Ehhez kell nekünk az, hogy tudjuk, hogy az AD-ben a telefonszám tulajdonságnak mi is a belső elnevezése. Ennek felderítésére több módszer van, nézzünk egy PowerShell-est:

PS C:\> $user = [ADSI] "LDAP://cn=János Vegetári,OU=Demó,DC=iqjb,DC=w08"

PS C:\> $user.psbase.properties

 

PropertyName       Value                        Capacity              Count

------------       -----                        --------              -----

objectClass        {top, person, o...                  4                  4

cn                 János Vegetári                      4                  1

sn                 Vegetári                            4                  1

telephoneNumber    2008                                4                  1

givenName          János                               4                  1

distinguishedName  CN=János Vegetá...                  4                  1

...

A fenti listában látjuk, hogy a telefonszám attribútum neve - meglepő módon – telephoneNumber.

Vagy a Windows Server 2008 esetében az Active Directory Users and Computers eszköz szerencsére már tartalmaz egy Attribute Editor fület, a korábbi Windows változatoknál az ADSIEdit eszközzel érhetjük el ugyanezt:

 

128 . ábra A Windows Server 2008 ADUC új Attribute Editor-a

Nézzük meg, hogyan lehet ezt a telefonszámot kiolvasni, majd átírni. Az első megoldás a „PowerShell-es”:

PS C:\> $user.telephoneNumber

1234

PS C:\> $user.telephoneNumber=2008

PS C:\> $user.setinfo()

PS C:\> $user.telephoneNumber

2008

Ebben az a furcsa, hogy a Get-Member-rel nem lehetett kiolvasni, hogy a $user-nek van telephoneNumber tulajdonsága, mégis lehet használni.

A második megoldás a hagyományos, ADSI-stílus:

PS C:\> $u.Get("telephoneNumber")

1234

PS C:\> $u.Put("telephoneNumber",9876)

PS C:\> $u.SetInfo()

PS C:\> $u.Get("telephoneNumber")

9876

A Get metódussal tudjuk az adott tulajdonságot kiolvasni, a Put-tal átírni. Egyik esetben sem szabad megfeledkezni a SetInfo-ról, ami az objektum memóriabeli reprezentációját írja be ténylegesen az AD-ba.

A Get és a Put is „rejtett” metódus, a paraméterezésük a példában látható. Az SD attribútumok LDAP nevére kell hivatkozni mindkettőnél.

Megjegyzés

Sajnos nem minden attribútum kezelhető a PowerShell-es módszerrel. Ilyen például a Company attribútum:

PS C:\> $u.company

PS C:\> $u.get("company")

Cég

Az első esetben nem kaptam semmilyen választ az attribútum kiolvasására, de get-tel mégis működött.

Mi van akkor, ha kiolvastuk egy felhasználó adatait egy változóba, majd ezután valaki egy másik gépről vagy egy másik alkalmazással módosítja a felhasználónk valamely attribútumát. Ilyenkor a getinfo metódussal lehet frissíttetni az adatokat a memóriában:

PS C:\> $u.get("company")

Egyik

PS C:\> $u.getinfo()

PS C:\> $u.get("company")

Másik

A fenti példában az első kiolvasás után az ADUC eszközzel az első get után átírtam a felhasználó Company attribútumát, és a getinfo-val ezt frissítettem a memóriában, így az új érték már a PowerShell-ből is látszik.

Munka többértékű (multivalued) attribútumokkal

Az Active Directory egyik jellegzetes attribútuma az un. „multivalued property”. Ez olyan tulajdonság, ahova az értékek listáját, tömbjét tehetjük. Legtipikusabb ilyen attribútum az Exchange Server bevezetése után a felhasználók e-mail címeit tartalmazó ProxyAddresses, vagy a csoportok Member attribútuma, de erről majd külön értekezek. Marad mondjuk az other... kezdetű különböző telefonszámok tárolására szolgáló attribútumok, mint például az otherMobile vagy az otherTelephone.

Ezeket ki lehet olvasni az eddig megismert módszerekkel is, de nézzük, hogy milyen problémákkal szembesülhetünk. Ha a get metódust használom, és csak egy értéket tárol a „multivalued propery”, akkor nem egy elemű tömböt kapok, hanem sima skaláris értéket:

PS C:\> $user.get("otherMobile")

othermobil1234

PS C:\> $user.get("otherMobile").gettype()

 

IsPublic IsSerial Name                                     BaseType

-------- -------- ----                                     --------

True     True     String                                   System.Object

Ezzel szemben, ha több értéket tárolunk, akkor már tömböt kapunk:

PS C:\> $user.getinfo()

PS C:\> $user.get("otherMobile")

othermobil2345

othermobil1234

PS C:\> $user.get("otherMobile").gettype()

 

IsPublic IsSerial Name                                     BaseType

-------- -------- ----                                     --------

True     True     Object[]                                 System.Array

Ez nem biztos, hogy jó nekünk, mert így a szkriptünket kétfajta esetre kell felkészítenünk: külön arra az esetre, ha csak egy értéket tárolunk és külön arra az esetre is, ha többet. Ez bonyolítja a programjainkat.

Ha konzisztensen, mindig tömbként akarjuk kezelni az ilyen „multivalued property”-ket, akkor vagy használjuk a PowerShell-es stílust:

PS C:\> $user.otherMobile

othermobil1234

PS C:\> $user.otherMobile[0]

othermobil1234

PS C:\> $user.otherMobile.gettype()

 

IsPublic IsSerial Name                                     BaseType

-------- -------- ----                                     --------

True     False    PropertyValueCollection                  System.Collec...

Vagy használjuk a GetEx metódust:

PS C:\> $user.getex("otherMobile")

othermobil1234

PS C:\> $user.getex("otherMobile").gettype()

 

IsPublic IsSerial Name                                     BaseType

-------- -------- ----                                     --------

True     True     Object[]                                 System.Array

Az ilyen multivalued property-k írása sem egyértelmű, hiszen több lehetőségem is van:

a meglevő értékekhez akarok egy újabbat hozzáfűzni,

a meglevő értékek helyett akarok egy újat betölteni.

Ezeket a lehetőségeket én magam is le tudom programozni a szkriptemben. Ha az első változatra van szükségem, akkor előbb kiolvasom az attribútum aktuális tartalmát egy változóba, hozzárakom az új értéket és így rakom vissza a put-tal, vagy egyszerű értékadással. Ha pedig a második változatra van szükségem, akkor egyszerűen felülírom az attribútumot az új értékkel.

Sokkal elegánsabb, ha ezt már maga az objektum tudná egy „okosabb” metódussal. Ilyen létezik, ez pedig a PutEx:

PS C:\> $user.getex("otherMobile")

othermobil1234

PS C:\> $user.putex(3,"otherMobile",@("othermobilPutEx2"));$user.setinfo()

PS C:\> $user.getex("otherMobile")

othermobilPutEx2

othermobil1234

PS C:\> $user.putex(2,"otherMobile",@("othermobilPutEx3"));$user.setinfo()

PS C:\> $user.getex("otherMobile")

othermobilPutEx3

A fenti példában a kiinduló állapotban egy mobilszámunk van. Ezután hozzáfűzök egy újabbat a putex használatával, a hozzáfűzést az első paraméterként szereplő 3-as jelzi. Fontos, hogy a hozzáfűzendő értéket tömbként kell kezelni, ezért van ott a kukac-zárójelpár! Ezután egy újabb putex-et hívok meg, immár 2-es paraméterrel, ez a felülírás művelete, ennek hatására már csak ez a legújabb mobilszám lesz az attribútumban.

Használhatom még az 1-es paramétert is, ez ekvivalens az attribútum értékeinek törlésével, vagy használhatom a 4-es paramétert, ez a paraméterként megadott elemet töröli az értékek közül:

PS C:\> $user.putex(3,"otherMobile",@("Append"));$user.setinfo()

PS C:\> $user.getex("otherMobile")

Append

othermobilPutEx3

PS C:\> $user.putex(4,"otherMobile",@("Append"));$user.setinfo()

PS C:\> $user.getex("otherMobile")

othermobilPutEx3

A fenti példában elsőként hozzáfűzök egy értéket, majd ugyanezt eltávolítom.

Speciális tulajdonságok kezelése

Van néhány attribútum, amelyek az eddig megismert módszerek egyikével sem kezelhetők:

PS C:\> $user.AccountDisabled

PS C:\> $user.get("AccountDisabled")

Exception calling "get" with "1" argument(s): "The directory property canno

t be found in the cache.

"

At line:1 char:10

+ $user.get( <<<< "AccountDisabled")

A PowerShelles szintaxis meg se nyikkan, a get meg még hibát is jelez. Ilyen esetekben használhatjuk a psbase nézeten keresztül az InvokeGet és InvokeSet metódusokat:

PS C:\> $user.psbase.invokeget("AccountDisabled")

False

PS C:\> $user.psbase.invokeset("AccountDisabled","TRUE")

PS C:\> $user.SetInfo()

PS C:\> $user.psbase.invokeget("AccountDisabled")

True



Word To HTML Converter