.NET Reflection in PowerShell

Image Description

Daily PowerShell #6

Scripting DotNet Daily PowerShell

October 23, 2021

About .NET Reflection

Reflection allows you to inspect, invoke and access .NET type data which includes both public and private members. By default, PowerShell provides access to publicly accessible properties and methods but using the reflection APIs, you can access the internals of types in .NET.

Accessing .NET Types

You can easily invoke .NET methods in PowerShell with standard syntax. For example, you can call IsDaylightSavingTime() on a DateTime object directly in PowerShell.

$DateTime = Get-Date
$DateTime.IsDaylightSavingTime()

You can also invoke the same method using the reflection APIs.

$DateTime = Get-Date
[System.DateTime].GetMethod('IsDaylightSavingTime').Invoke($DateTime, @())

Below, you will find how to call access members of objects using reflection.

GetType()

The GetType() method can be called on an object to retrieve the System.Type for that object.

$DateTime = Get-Date
$Type = $DateTime.GetType()
$Type

Type Reference

You can also get a type by referencing the type directly.

[System.DateTime]

Locating Members

Members are the variables features of a type. This includes fields, properties and methods. You can locate members by using various reflection APIs.

Locating Methods

The GetMethod() and GetMethods() methods can be used to list methods of a type.

The following will list public methods of the System.DateTime type.

[System.DateTime].GetMethods() | Select-Object Name

If you wish to locate non-public methods (like internal and private), you can using binding flags.

The following example will return non-public, instance methods.

[System.DateTime].GetMethods([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Instance) | Select-Object Name

You can also return non-public, static methods by changing the binding flags.

[System.DateTime].GetMethods([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Static) | Select-Object Name

Locating Properties

Similar to locating methods, you can also locate properties by using the GetProperty() and GetProperties() methods.

For example, you can locate non-public, instance properties with the following.

[System.DateTime].GetProperties([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Instance) | Select-Object Name

Locating Fields

Finally, you can also locate fields by using the GetField() and GetFields() methods. Typically, fields are not public facing and will contain the internals of a type.

[System.DateTime].GetFields([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Instance) | Select-Object Name

Invoking Members

Once you have access to the type and member you wish to access, you can use the information to access those members.

Invoking a Method

Invoking a method involves retrieving a reference to the MethodInfo object through the GetMethod or GetMethods methods. Then, you can use the Invoke method of that class to invoke the method directly. This means you can invoke non-public methods.

$DateTime = Get-Date
$MethodInfo = [System.DateTime].GetMethods([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Instance) | Where-Object Name -eq 'IsAmbiguousDaylightSavingTime'
$MethodInfo.Invoke($DateTime, @())

If you were to attempt to execute that method directly, you would get an error.

$DateTime = Get-Date
$DateTime.IsAmbiguousDaylightSavingTime()

Getting a Property Value

To get a property value, you need to look up the property with GetProperty or GetProperties. Once you have a reference to the PropertyInfo object, you can then invoke the getter or setter for that property.

$DateTime = Get-Date
$PropertyInfo = [System.DateTime].GetProperties([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Instance) | Where-Object Name -eq 'InternalTicks'
$PropertyInfo.GetGetMethod($true).Invoke($DateTime, @())

You’ll notice that the InternalTicks property does not exist on a regular DateTime object.

Getting a Field Value

To get a field value, you need to look up a field with GetField or GetFields. Once you have a reference to the FieldInfo object, you can then retrieve the value of the field.

$DateTime = Get-Date
$FieldInfo = [System.DateTime].GetFields([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Instance) | Where-Object Name -eq '_dateData'
$FieldInfo.GetValue($DateTime)

Invoke a Static Method

Static methods do not require an instance of an object to be present. You can invoke them on the type themselves.

Rather than passing in a value to the Invoke method, you can pass in $null.

 $MethodInfo = [System.DateTime].GetMethods([Reflection.BindingFlags]::NonPublic -bor [Reflection.BindingFlags]::Static) | Where-Object Name -eq 'SystemSupportsLeapSeconds'
 $MethodInfo.Invoke($null, @())

Decompiling Types

Sometimes, .NET code is open source and you can look at the source code directly on GitHub. You can also use the .NET reflection APIs to enumerate members within a .NET type. A quicker way to access .NET type information is to decompile to assemblies to view the source code.

PowerShell Pro Tools provides a decompiler to view source code for assemblies loaded into your PowerShell environment.