A question came up about working with Active Directory objects regarding the difference between
$object.attribute = "value"
and
$object.Put("attribute", "value")
They both perform the same function in that the attribute is assigned a value. The question was whats the difference and which should you use. The question also noted that when creating objects they behave differently.
PS> $ou = [ADSI]"LDAP://ou=test,dc=Manticore,dc=org"
PS> $user1 = $ou.create("user","cn=test39")
PS> $user1.description = "test 39"
PS> $user1.setinfo()
Exception calling "setinfo" with "0" argument(s): "A constraint violation occurred.
(Exception from HRESULT: 0x8007202F)"
At line:1 char:15
+ $user1.setinfo <<<< ()
PS> $user2 = $ou.create("user","cn=test49")
PS> $user2.Put("description", "test 49")
PS> $user2.setinfo()
PS>
PS> $user1 = $ou.create("user","cn=test59")
PS> $user1.setinfo()
PS> $user1.description = "test 59"
PS> $user1.setinfo()
PS> $user1 = $ou.create("user","cn=test59")
PS> $user1.setinfo()
PS> $user1.description = "test 59"
PS> $user1.setinfo()
We start as normal by creating an object for the OU to contain the user. We then use the create method to create the user. If we try to set the description (or any other attribute) and then call setinfo() we get the error shown. However, if we use Put() to set the attribute immediately after creation and then call setinfo() - it works!!
If we want to set the attribute directly we have to call setinfo() before we do it - and then again afterwards.
If we want an example modifying an attribute
PS> $user1 = [ADSI]"LDAP://cn=test59,ou=test,dc=manticore,dc=org"
PS> $user2 = [ADSI]"LDAP://cn=test49,ou=test,dc=manticore,dc=org"
PS> $user1.description = "new description 59"
PS> $user1.setinfo()
PS> $user2.Put("description", "new description 49")
PS> $user2.setinfo()
So why the difference?
I think that this is all to do with the way the object is accessed. Remember that [ADSI] is an accelerator for the .NET class System.DirectoryServices.DirectoryEntry (perform a get-member on an object). System.DirectoryServices.DirectoryEntry is a wrapper for the ADSI COM based interface.
The situation is further complicated in that the PowerShell object is not a "pure" .NET System.DirectoryServices.DirectoryEntry object. Try a get-member on it you won't see any of the methods just the AD attributes of the object. Dropping in to the base object using $user1.psbase | get-member will display the .NET methods. What you will never see is the ADSI methods such as Put and SetInfo - they are implemented but invisible (this caused a lot of discussion when it was introduced in the beta versions)
If you look at VBScript books such as the Windows 2000 Scripting Guide you will see them using Put between the create and the setinfo().
So whats happening? I think its the .NET class that objects to modifying the object before it is written to AD. The Put "bypasses" the .NET in that it seems to implement the ADSI methods in a more direct manner.
Which one should you use - personal preference but I would use the $object.attribute = "value" version because it is simpler to understand, uses the same approach as the rest of PowerShell and is a bit less typing.
Hope this helps.

