get or set inexistant properties of Powershell object
05:43 12 May 2026

In Powershell, if I create a Hashtable I can get/set values via pseudo properties

$h = @{ }

$h.a
# returns $null

# add a key/value with key 'a'
$h.a = 'abc'
$h.a
# returns 'abc'

This is not limited to Hashtable if I now use Get-ADUser,

# get the main properties of user 'foo'
$user = Get-ADUser foo
$user | gm

   TypeName: Microsoft.ActiveDirectory.Management.ADUser

Name              MemberType            Definition
----              ----------            ----------
Contains          Method                bool Contains(string propertyName)
Equals            Method                bool Equals(System.Object obj)
GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEnumerator()
GetHashCode       Method                int GetHashCode()
GetType           Method                type GetType()
ToString          Method                string ToString()
Item              ParameterizedProperty Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item(string propertyName) {get;}
DistinguishedName Property              System.String DistinguishedName {get;set;}
Enabled           Property              System.Boolean Enabled {get;set;}
GivenName         Property              System.String GivenName {get;set;}
Name              Property              System.String Name {get;}
ObjectClass       Property              System.String ObjectClass {get;set;}
ObjectGUID        Property              System.Nullable`1[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] ObjectGUID {get;set;}
SamAccountName    Property              System.String SamAccountName {get;set;}
SID               Property              System.Security.Principal.SecurityIdentifier SID {get;set;}
Surname           Property              System.String Surname {get;set;}
UserPrincipalName Property              System.String UserPrincipalName {get;set;}

I can set/update properties not present in $user

$user.telephoneNumber = '+330000000'
$user | gm

   TypeName: Microsoft.ActiveDirectory.Management.ADUser

Name              MemberType            Definition
----              ----------            ----------
Contains          Method                bool Contains(string propertyName)
Equals            Method                bool Equals(System.Object obj)
GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEnumerator()
GetHashCode       Method                int GetHashCode()
GetType           Method                type GetType()
ToString          Method                string ToString()
Item              ParameterizedProperty Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item(string propertyName) {get;}
DistinguishedName Property              System.String DistinguishedName {get;set;}
Enabled           Property              System.Boolean Enabled {get;set;}
GivenName         Property              System.String GivenName {get;set;}
Name              Property              System.String Name {get;}
ObjectClass       Property              System.String ObjectClass {get;set;}
ObjectGUID        Property              System.Nullable`1[[System.Guid, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] ObjectGUID {get;set;}
SamAccountName    Property              System.String SamAccountName {get;set;}
SID               Property              System.Security.Principal.SecurityIdentifier SID {get;set;}
Surname           Property              System.String Surname {get;set;}
telephoneNumber   Property              System.String telephoneNumber {get;set;}
UserPrincipalName Property              System.String UserPrincipalName {get;set;}

I now have a new real property telephoneNumber and a new property(?) ModifiedProperties, of type HashSet, not visible in Get-Member, only in $user | Format-List * -Force witch contains the list of set/updated properties, whether or not it is present in the Get-ADUser result.

Apparently, whether for hastables or the result of Get-ADUser, a mechanism unknown to me allows intercepting get/set operations on unknown/inexistant properties to perform ad-hoc processing.

I would like to learn how to do the same. where can I find such information?

context

Name                           Value
----                           -----
PSVersion                      5.1.19041.6456
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.19041.6456
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
c# powershell