PowerShell Community Extensions Active Directory Provider Part 2
In part one of this series : PowerShell Community Extensions Active Directory Provider Part 1
I did show how you can use the PowerShell Community Extensions 1.1 (PSCX 1.1) Active directory provider, to explore your Active Directory Domain from PowerShell as if it was a FileSystem. I this post I go on from there and Show how to select a user using the provider and how to change the Description.
I ended former post with the remark that the output from the provider was a bit different from the output we recieve as we connect directly to Active directory from PowerShell using the ADSI adapter.
Using PowerShell ADSI adapter :
PoSH> $root = [adsi]''
PoSH> $root
distinguishedName
-----------------
{DC=mow,DC=local}
PoSH> $root.PSBase.Children.Find('ou=mowOU')
distinguishedName
-----------------
{OU=MowOu,DC=mow,DC=local}
PoSH> $root.PSBase.Children.Find('ou=mowOU') | fl *
objectClass : {top, organizationalUnit}
ou : {MowOu}
distinguishedName : {OU=MowOu,DC=mow,DC=local}
instanceType : {4}
whenCreated : {5/18/2006 7:15:13 PM}
whenChanged : {5/18/2006 7:15:13 PM}
uSNCreated : {System.__ComObject}
uSNChanged : {System.__ComObject}
name : {MowOu}
objectGUID : {139 153 183 252 115 3 24 73 145 12 14 36 64 30 237 202}
objectCategory : {CN=Organizational-Unit,CN=Schema,CN=Configuration,DC=mow,DC=local}
nTSecurityDescriptor : {System.__ComObject}
PoSH>
Using PSCX 1.1 Active Directory Provider :
PoSH> cd MOW:\
PoSH> gi MowOu
LastWriteTime Type Name
------------- ---- ----
5/18/2006 9:15 PM organizationalUnit MowOu
PoSH> get-Item MowOu | Format-List
Name : MowOu
Type : organizationalUnit
LastWriteTime : 5/18/2006 9:15:13 PM
PoSH> get-Item MowOu | Format-List *
PSPath : PSCX\DirectoryServices::MOW:\MowOu
PSParentPath : PSCX\DirectoryServices::MOW:
PSChildName : MowOu
PSDrive : MOW
PSProvider : PSCX\DirectoryServices
PSIsContainer : True
Type : organizationalUnit
Name : MowOu
Description :
LastWriteTime : 5/18/2006 9:15:13 PM
FullName : MOW:\MowOu
CanonicalName : mow.local/MowOu
DistinguishedName : OU=MowOu,DC=mow,DC=local
Types : {top, organizationalUnit}
Entry : System.DirectoryServices.DirectoryEntry
IsContainer : True
PoSH>
If we look at the types of the objects and use Get-Member to look at the object returned by the PSCX AD Provider we can see why :
PoSH> $root.PSBase.Children.Find('ou=mowOU').PSbase.getType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False DirectoryEntry System.ComponentModel.Component
PoSH> ( get-Item MowOu ).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False DirectoryEntryInfo System.Object
PoSH> gi MowOu | gm
TypeName: Pscx.Providers.DirectoryServices.DirectoryEntryInfo
Name MemberType Definition
---- ---------- ----------
AddPropertyValue Method System.Void AddPropertyValue(PSObject psobject, Boolean raw)
Dispose Method System.Void Dispose()
Equals Method System.Boolean Equals(Object obj), System.Boolean Equals(DirectoryEntryInfo other)
GetChildren Method Pscx.Providers.DirectoryServices.DirectoryEntryInfo[] GetChildren()
GetHashCode Method System.Int32 GetHashCode()
GetProperty Method System.Management.Automation.PSObject GetProperty(Collection`1 pickList, Boolea...
GetType Method System.Type GetType()
get_CanonicalName Method System.String get_CanonicalName()
get_Description Method System.String get_Description()
get_DistinguishedName Method System.String get_DistinguishedName()
get_Entry Method System.DirectoryServices.DirectoryEntry get_Entry()
get_FullName Method System.String get_FullName()
get_IsContainer Method System.Boolean get_IsContainer()
get_LastWriteTime Method System.Nullable`1[[System.DateTime, mscorlib, Version=2.0.0.0, Culture=neutral,...
get_Name Method System.String get_Name()
get_Types Method Pscx.DirectoryServices.DirectoryEntryTypeCollection get_Types()
RemovePropertyValue Method System.Void RemovePropertyValue(PSObject psobject, Boolean raw)
SetProperty Method System.Void SetProperty(PSObject psobject, Boolean raw)
ToString Method System.String ToString()
PSChildName NoteProperty System.String PSChildName=MowOu
PSDrive NoteProperty Pscx.Providers.DirectoryServices.DirectoryServiceDriveInfo PSDrive=MOW
PSIsContainer NoteProperty System.Boolean PSIsContainer=True
PSParentPath NoteProperty System.String PSParentPath=PSCX\DirectoryServices::MOW:
PSPath NoteProperty System.String PSPath=PSCX\DirectoryServices::MOW:\MowOu
PSProvider NoteProperty System.Management.Automation.ProviderInfo PSProvider=PSCX\DirectoryServices
CanonicalName Property System.String CanonicalName {get;}
Description Property System.String Description {get;}
DistinguishedName Property System.String DistinguishedName {get;}
Entry Property System.DirectoryServices.DirectoryEntry Entry {get;}
FullName Property System.String FullName {get;}
IsContainer Property System.Boolean IsContainer {get;}
LastWriteTime Property System.Nullable`1[[System.DateTime, mscorlib, Version=2.0.0.0, Culture=neutral,...
Name Property System.String Name {get;}
Types Property Pscx.DirectoryServices.DirectoryEntryTypeCollection Types {get;}
Type ScriptProperty System.Object Type {get=$this.Types.MostDerivedType;}
PoSH>
The PSCX AD Provider does not return DirectoryEntry objects but DirectoryEntryInfo objects.
From the complete object path output of the Get-Member we can see that this is a type that is defined by the provider itself :
Pscx.Providers.DirectoryServices.DirectoryEntryInfo
Also from the output of get-member we can see that
The Description value is a NoteProperty and has only a get no set and that there is also an Entry Property that returns a DirectoryEntry Object,
that can we use to get the DirectoryEntry object and make the change there :
PoSH> ls |? {$_.type -match 'User'}
LastWriteTime Type Name
------------- ---- ----
9/29/2006 5:53 PM user FooMoved
9/27/2006 10:13 PM user Ken Myer
8/15/2006 8:12 PM user NewUs:::er0003
8/14/2006 10:26 PM user NewUser0010
8/15/2006 8:12 PM user NewUser0011
8/15/2006 8:12 PM user NewUser0012
11/15/2006 12:13 PM user test
PoSH> $UserInfo = Get-Item test
PoSH> $UserInfo | fl *
PSPath : PSCX\DirectoryServices::MOW:\test
PSParentPath : PSCX\DirectoryServices::MOW:
PSChildName : test
PSDrive : MOW
PSProvider : PSCX\DirectoryServices
PSIsContainer : False
Type : user
Name : test
Description :
LastWriteTime : 11/15/2006 12:13:56 PM
FullName : MOW:\test
CanonicalName : mow.local/test
DistinguishedName : CN=test,DC=mow,DC=local
Types : {top, person, organizationalPerson, user}
Entry : System.DirectoryServices.DirectoryEntry
IsContainer : False
PoSH> $UserInfo.Description = 'New Description'
"Description" is a ReadOnly property.
At line:1 char:11
+ $UserInfo.D <<<< escription = 'New Description'
PoSH> $user = $UserInfo.entry
PoSH> $user
distinguishedName
-----------------
{CN=test,DC=mow,DC=local}
PoSH> $user | gm
TypeName: System.DirectoryServices.DirectoryEntry
Name MemberType Definition
---- ---------- ----------
accountExpires Property System.DirectoryServices.PropertyValueCollection accountExpires {get;set;}
badPasswordTime Property System.DirectoryServices.PropertyValueCollection badPasswordTime {get;set;}
badPwdCount Property System.DirectoryServices.PropertyValueCollection badPwdCount {get;set;}
cn Property System.DirectoryServices.PropertyValueCollection cn {get;set;}
codePage Property System.DirectoryServices.PropertyValueCollection codePage {get;set;}
countryCode Property System.DirectoryServices.PropertyValueCollection countryCode {get;set;}
distinguishedName Property System.DirectoryServices.PropertyValueCollection distinguishedName {get;set;}
instanceType Property System.DirectoryServices.PropertyValueCollection instanceType {get;set;}
lastLogoff Property System.DirectoryServices.PropertyValueCollection lastLogoff {get;set;}
lastLogon Property System.DirectoryServices.PropertyValueCollection lastLogon {get;set;}
logonCount Property System.DirectoryServices.PropertyValueCollection logonCount {get;set;}
name Property System.DirectoryServices.PropertyValueCollection name {get;set;}
nTSecurityDescriptor Property System.DirectoryServices.PropertyValueCollection nTSecurityDescriptor {get;set;}
objectCategory Property System.DirectoryServices.PropertyValueCollection objectCategory {get;set;}
objectClass Property System.DirectoryServices.PropertyValueCollection objectClass {get;set;}
objectGUID Property System.DirectoryServices.PropertyValueCollection objectGUID {get;set;}
objectSid Property System.DirectoryServices.PropertyValueCollection objectSid {get;set;}
primaryGroupID Property System.DirectoryServices.PropertyValueCollection primaryGroupID {get;set;}
pwdLastSet Property System.DirectoryServices.PropertyValueCollection pwdLastSet {get;set;}
sAMAccountName Property System.DirectoryServices.PropertyValueCollection sAMAccountName {get;set;}
sAMAccountType Property System.DirectoryServices.PropertyValueCollection sAMAccountType {get;set;}
userAccountControl Property System.DirectoryServices.PropertyValueCollection userAccountControl {get;set;}
uSNChanged Property System.DirectoryServices.PropertyValueCollection uSNChanged {get;set;}
uSNCreated Property System.DirectoryServices.PropertyValueCollection uSNCreated {get;set;}
whenChanged Property System.DirectoryServices.PropertyValueCollection whenChanged {get;set;}
whenCreated Property System.DirectoryServices.PropertyValueCollection whenCreated {get;set;}
PoSH> $User.Description = 'New Description'
PoSH> $user.setInfo()
PoSH> Get-Item test | fl
Name : test
Type : user
LastWriteTime : 4/7/2007 2:03:28 AM
PoSH> Get-Item test | fl *
PSPath : PSCX\DirectoryServices::MOW:\test
PSParentPath : PSCX\DirectoryServices::MOW:
PSChildName : test
PSDrive : MOW
PSProvider : PSCX\DirectoryServices
PSIsContainer : False
Type : user
Name : test
Description : New Description
LastWriteTime : 4/7/2007 2:03:28 AM
FullName : MOW:\test
CanonicalName : mow.local/test
DistinguishedName : CN=test,DC=mow,DC=local
Types : {top, person, organizationalPerson, user}
Entry : System.DirectoryServices.DirectoryEntry
IsContainer : False
PoSH>
And we can see that the change to the description has been made and is reflected in the DirectoryEntryInfo object when we run get-item to retrieve it again.
The DirectoryEntryInfo object is used as it provides standard formatting as we are used from the other providers, the standard noteproperties with the providerinfo PowerShell needs as PSPath and the other noteproperties starting with PS, also this wrapper object helps improving the performance by removing overhead as not the whole DirectoryEntry is returned while enumerating an Active container, but only the properties needed (like also the DirectorySearcher does as retrieving the complete directoryEntry objects is not needed and can have a major performance impact).
This Active Directory provider is really great !! and there is much more cool extra functionality the PowerShell Community Extensions do add.
So to the PowerShell Community Extension team ..Thanks a lot for all the effort guy's and keep up the good work, it's really appriciated !
Enjoy,
Greetings /\/\o\/\/
s.i.a.t.n.y? PSCX set-events x0n ;-)