I knew that PowerShell constructs such [bool]
– which defines the boolean data type – were called accelerators, but I never knew why and didn’t bother much as I figured I’d learn more about them soon or later.
But yesterday while reading Bruce Payette’s “Windows PowerShell in Action” that book too mentioned the word accelerator without defining it, and so I started Googling a bit about it. This Googling introduced me to accelerators for WMI – very useful, something I must explore sometime – and that got me curious on how to find all the available accelerators in PowerShell. This in turn bought me to the topic of reflection as that’s what one uses to get a list of accelerators in PowerShell.
So what is reflection? Truth to be told it still does not make much sense to be but what I understand is that reflection is the act (or ability) of an object to look at itself (see it’s “reflection” in the mirror so to say) and learn what it’s capable of – what methods it has, what are it’s properties, and so on. And it is useful because sometimes you may encounter objects that you are getting from elsewhere, and reflection is what you need to learn more about the object.
I guess an example will make it clearer.
Say I define an object called $date
as below:
1 |
$date = [datetime]"13 March 2013" |
As the creator of this object I know it’s of type [datetime]
. And since PowerShell provides a cmdlet Get-Members
I know I can use it to examine the methods and properties of this object.
But what if I wasn’t the creator of this object. All I know is that I have a script which will get some object as input and I am supposed to examine it and take further action depending on what sort of an object it is. Further, assume the Get-Member
cmdlet isn’t available, or for some reason you can’t use it on the object you are receiving (or maybe Get-Member
itself depends on reflection, which we’ll talk about below, so it won’t work unless the concept of reflection is supported by PowerShell). Either ways – you don’t have Get-Member
available, period.
In such a situation how would you know what is contained inside the object? That’s where reflection comes into the picture.
Before we go further, it’s worth reading this WikiPedia page on reflection, and this and this StackOverflow post. All these links explain reflection, but the takeaway from the Wikipedia page are the examples it gives of reflection in various languages, and the takeaway from one of the answers in the second StackOverflow post is that all objects in Java have a getClass
method which lets one reflectively examine an unknown object.
I created a custom PowerShell object to see if PowerShell objects have a similar method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
PS> $blah = New-Object -TypeName PSObject -Property @{ Name = "Rakhesh"; Age = 34 } PS> $blah | Get-Member TypeName: System.Management.Automation.PSCustomObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() Age NoteProperty System.Int32 Age=34 Name NoteProperty System.String Name=Rakhesh |
Sure enough, GetType()
looks like what we are after. (GetHashcode()
and ToString
return an integer and string respectively (as seen from their definitions) so we can straightaway eliminate them).
Let’s dig deeper:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
PS> $blah.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True False PSCustomObject System.Object PS> get-member -InputObject $blah.GetType() TypeName: System.RuntimeType Name MemberType Definition ---- ---------- ---------- AsType Method type AsType() Clone Method System.Object Clone(), System.Object ICloneable.Clone() Equals Method bool Equals(System.Object obj), bool Equals(type o), bool _Membe... ... GetMember Method System.Reflection.MemberInfo[] GetMember(string name, System.Ref... GetMembers Method System.Reflection.MemberInfo[] GetMembers(System.Reflection.Bind... GetMethod Method System.Reflection.MethodInfo GetMethod(string name, System.Refle... GetMethods Method System.Reflection.MethodInfo[] GetMethods(System.Reflection.Bind... GetNestedType Method type GetNestedType(string fullname, System.Reflection.BindingFla... GetNestedTypes Method type[] GetNestedTypes(System.Reflection.BindingFlags bindingAttr... GetObjectData Method void GetObjectData(System.Runtime.Serialization.SerializationInf... GetProperties Method System.Reflection.PropertyInfo[] GetProperties(System.Reflection... GetProperty Method System.Reflection.PropertyInfo GetProperty(string name, System.R... GetType Method type GetType(), type _MemberInfo.GetType(), type _Type.GetType() ... Name Property string Name {get;} Namespace Property string Namespace {get;} ReflectedType Property type ReflectedType {get;} StructLayoutAttribute Property System.Runtime.InteropServices.StructLayoutAttribute StructLayou... TypeHandle Property System.RuntimeTypeHandle TypeHandle {get;} TypeInitializer Property System.Reflection.ConstructorInfo TypeInitializer {get;} UnderlyingSystemType Property type UnderlyingSystemType {get;} |
The GetType()
method returns an object of type RuntimeType
which contains many methods and properties. The interesting bits for us are GetProperties
, GetMethods
, and so on. Let’s explore these:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
PS> $blah.GetType().GetMethods() Name : ToString DeclaringType : System.Management.Automation.PSCustomObject ReflectedType : System.Management.Automation.PSCustomObject MemberType : Method MetadataToken : 100667351 Module : System.Management.Automation.dll IsSecurityCritical : True IsSecuritySafeCritical : True IsSecurityTransparent : False MethodHandle : System.RuntimeMethodHandle Attributes : PrivateScope, Public, Virtual, HideBySig CallingConvention : Standard, HasThis ReturnType : System.String ReturnTypeCustomAttributes : System.String ReturnParameter : System.String IsGenericMethod : False IsGenericMethodDefinition : False ContainsGenericParameters : False MethodImplementationFlags : IL IsPublic : True IsPrivate : False IsFamily : False IsAssembly : False IsFamilyAndAssembly : False IsFamilyOrAssembly : False IsStatic : False IsFinal : False IsVirtual : True IsHideBySig : True IsAbstract : False IsSpecialName : False IsConstructor : False CustomAttributes : {} # snipping out similar output for each of the other methods PS> $blah.GetType().GetProperties() # no result here as this is a custom PSObject and it doesn't # have properties, only NoteProperties. see get-member output above. |
Now let’s try this on our “unknown” $date
object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
PS> $date.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True DateTime System.ValueType # find the class name of the object PS> $date.GetType().Name DateTime # get its members, format the name field of the output as columns as there's a lot PS> $date.GetType().GetMethods() | fw Name -Column 4 get_Date get_Day get_DayOfWeek get_DayOfYear get_Hour get_Kind get_Millisecond get_Minute get_Month get_Now get_UtcNow get_Second get_Ticks get_TimeOfDay get_Today get_Year Add AddDays AddHours AddMilliseconds AddMinutes AddMonths AddSeconds AddTicks AddYears Compare CompareTo CompareTo DaysInMonth Equals Equals Equals FromBinary FromFileTime FromFileTimeUtc FromOADate IsDaylightSavingTime SpecifyKind ToBinary GetHashCode ... # how can I invoke a method of the object? # the output above is an array, I want to invoke the AddYears() method - that's at location 24 - so let's try: PS> $date.GetType().GetMethods()[24] Name : AddYears DeclaringType : System.DateTime ReflectedType : System.DateTime MemberType : Method MetadataToken : 100664410 ... # this gives the details of the method. but how do I invoke it? # I could use Get-Member here to examine the object above, but we don't have Get-Member remember? # so I'll use reflection again. PS> $date.GetType().GetMethods()[24].GetType().GetMethods() | fw Name -Column 4 get_Name get_DeclaringType get_ReflectedType get_MemberType get_MetadataToken get_Module get_IsSecurityCritical get_IsSecuritySafeCritical get_IsSecurityTransparent get_MethodHandle get_Attributes get_CallingConvention get_ReturnType get_ReturnTypeCustomAttr... get_ReturnParameter get_IsGenericMethod get_IsGenericMethodDefin... get_ContainsGenericParam... get_MethodImplementatio... get_IsPublic get_IsPrivate get_IsFamily get_IsAssembly get_IsFamilyAndAssembly get_IsFamilyOrAssembly get_IsStatic get_IsFinal get_IsVirtual get_IsHideBySig get_IsAbstract get_IsSpecialName get_IsConstructor get_CustomAttributes ToString GetHashCode Equals GetCustomAttributes GetCustomAttributes IsDefined GetCustomAttributesData GetParameters GetMethodImplementationF... GetMethodBody Invoke GetBaseDefinition CreateDelegate CreateDelegate MakeGenericMethod GetGenericArguments GetGenericMethodDefinition GetObjectData Invoke GetType # the Invoke method seems useful, so let's try that PS> $date.GetType().GetMethods()[24].Invoke OverloadDefinitions ------------------- System.Object Invoke(System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, cultureinfo culture) System.Object Invoke(System.Object obj, System.Object[] parameters) void _MemberInfo.Invoke(uint32 dispIdMember, [ref] guid riid, uint32 lcid, int16 wFlags, System.IntPtr pDispParams, System.IntPtr pVarResult, System.IntPtr pExcepInfo, System.IntPtr puArgErr) void _MethodBase.Invoke(uint32 dispIdMember, [ref] guid riid, uint32 lcid, int16 wFlags, System.IntPtr pDispParams, System.IntPtr pVarResult, System.IntPtr pExcepInfo, System.IntPtr puArgErr) System.Object _MethodBase.Invoke(System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, cultureinfo culture) System.Object _MethodBase.Invoke(System.Object obj, System.Object[] parameters) void _MethodInfo.Invoke(uint32 dispIdMember, [ref] guid riid, uint32 lcid, int16 wFlags, System.IntPtr pDispParams, System.IntPtr pVarResult, System.IntPtr pExcepInfo, System.IntPtr puArgErr) System.Object _MethodInfo.Invoke(System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, cultureinfo culture) System.Object _MethodInfo.Invoke(System.Object obj, System.Object[] parameters) # this gives me a list of defintions - good! - the second of these definitions seems to be what I am after, so lets try that # that definition says Invoke() takes two arguments - the object itself (reflection!) and an array of parameters to it PS> $date.GetType().GetMethods()[24].Invoke($date, 2) Friday, March 13, 2015 12:00:00 AM PS> |
As you can see, without knowing anything about the object we have managed to identify its type, the methods & properties it contains, and even invoke one of the methods. That’s reflection!
Now I have to figure how to use this info to get a list of accelerators in PowerShell. Which is the topic for another post, of course …