This post is less on doing something useful and more on just proving that I can do something even though PowerShell is trying to tell me that I cannot do it. That little thing is updating a property on an object that is set as Read-Only.
My example to show you how you can do something like this is by looking at $PSVersionTable which as we all know gives us some great information about what version of PowerShell that we are using.
$PSVersionTable
I am also using this as this was an example used in our previous user group meeting in which we were shown that the properties here could not be updated.
From this object, I am going to look more at the PSVersion property which of course is an object within this object.
$PSVersionTable.PSVersion
Looking at the properties of this object, we can see that each of the properties are shown as Read-Only by only having the Get method available to use.
$PSVersionTable.PSVersion | Get-Member
Furthermore, I am greeted with a nice error stating that my attempts to modify this have been foolish and that I should just give up.
$PSVersionTable.PSVersion.Major = 10
Yea, I guess I could just throw in the towel and move onto something more useful like updating some bugs on a module, but I think that I can do better here! And by using some reflection magic, I can make this happen!
To do this, I need to look at the hidden fields for the PSVersion object.
$PSVersionTable.PSVersion.GetType().GetFields('static,nonpublic,instance').Name
Here we can see that the field that we need to look at updating is _Major. Now we need to figure out how we can set this.
$Field = $PSVersionTable.PSVersion.GetType().GetField('_Major','static,nonpublic,instance') $Field | Get-Member
Looking at the methods, I see a SetValue that accepts a object and a value for the object. This seems pretty simple,right? Just call the method and update the value.
$Field.SetValue($PSVersionTable.PSVersion,10) $PSVersionTable.PSVersion
Perfect! We have now updated this “Read-Only” property to give us PowerShell V10! Now this will go away once we close and re-open PowerShell but it still a fun thing to do to show off how you can update these kinds of values.
Reblogged this on Process Studio and commented:
Try to link this to List CanReceiveEmail Enable/Disable.
Used this today for mocking purposes. Thank you!
Pingback: Quick Hits: Writing to a Read-Only Property - How to Code .NET
Love it! Do you have suggestions on how to discover the available methods?
For this specific example:
GetType().GetFields(‘static,nonpublic,instance’).Name
I was able to discover GetType().GetFields() with Get-Member easily enough.
$PSVersionTable.GetType().GetFields shows the overload definitions:
OverloadDefinitions
System.Reflection.FieldInfo[] GetFields()
System.Reflection.FieldInfo[] GetFields(System.Reflection.BindingFlags bindingAttr)
System.Reflection.FieldInfo[] _Type.GetFields(System.Reflection.BindingFlags bindingAttr)
System.Reflection.FieldInfo[] _Type.GetFields()
System.Reflection.FieldInfo[] IReflect.GetFields(System.Reflection.BindingFlags bindingAttr)
Checking MSDN I found the definition:
https://msdn.microsoft.com/en-us/library/6ztex2dc(v=vs.110).aspx
This explains the static,nonpublic portion however according to the article you must specify either Instance or Static….however you have specified both. From my testing it appears that you can specify both with no issue.
Is this a pretty standard method for discovering methods used with reflection, or is there a cleaner way to discover this?
Thanks!
Matthew
I think I specify both instance and static because there is a difference in the number of items that are returned. My methods example below is a good example of that.
For finding methods, the approach would be the same but instead you are using GetMethods() instead. Take this example below to see what happens:
Here you will see all of the available methods for the [string] type.