_working/callmethod.ps1
# internal static object CallMethod(Token token, object target, string methodName, object[] paramArray, bool callStatic, object valueToSet) $call = $( [psobject].Assembly.gettype("System.Management.Automation.ParserOps", $true).getmethods("NonPublic,Static") | ? {$_.name -eq "callmethod"} ) # System.Object Invoke(System.Object obj, # System.Reflection.BindingFlags invokeAttr, # System.Reflection.Binder binder, # System.Object[] parameters, # System.Globalization.CultureInfo culture) # System.Object Invoke(System.Object obj, System.Object[] parameters) $automationNull = [System.Management.Automation.Internal.AutomationNull]::Value <# $target = [string].UnderlyingSystemType $methodName = "Format" $paramArray = @("Hello, {0}.", "Oisin") trace-command -pshost memberresolution { $call.invoke($null, "NonPublic,Static", $null, @( $null, # token $target, # target $methodName, # method name $paramArray, # param array $true, # static call $automationNull # value to set (parameterized property, field?) ), $null) } #> <# static PSObject() { memberCollection = GetMemberCollection(PSMemberViewTypes.All); methodCollection = GetMethodCollection(); propertyCollection = GetPropertyCollection(PSMemberViewTypes.All); dotNetInstanceAdapter = new DotNetAdapter(); baseAdapterForAdaptedObjects = new BaseDotNetAdapterForAdaptedObjects(); dotNetStaticAdapter = new DotNetAdapter(true); dotNetInstanceAdapterSet = new AdapterSet(dotNetInstanceAdapter, null); ... #> <# # GetInstanceMethod*, GetInstanceProperty*, GetInstanceEvent*, GetStatic* private static CacheTable GetInstanceMethodReflectionTable(object obj) { lock (instanceMethodCacheTable) { CacheTable typeMethods = null; Type type = obj.GetType(); typeMethods = (CacheTable) instanceMethodCacheTable[type]; if (typeMethods == null) { typeMethods = new CacheTable(); PopulateMethodReflectionTable(type, typeMethods, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase); instanceMethodCacheTable[type] = typeMethods; } return typeMethods; } } # PopulateEvent*, PopulateProperty* private static void PopulateMethodReflectionTable(Type type, CacheTable typeMethods, BindingFlags bindingFlags) { MethodInfo[] methods = type.GetMethods(bindingFlags); PopulateMethodReflectionTable(type, methods, typeMethods); for (int i = 0; i < typeMethods.memberCollection.Count; i++) { typeMethods.memberCollection[i] = new MethodCacheEntry((MethodInfo[]) ((ArrayList) typeMethods.memberCollection[i]).ToArray(typeof(MethodInfo))); } } #> function Find-Type { param( [string]$TypeName, [reflection.bindingflags]$BindingFlags = "Public,NonPublic", [switch]$IncludePowershellAssemblies, [switch]$IncludeDotNetAssemblies, [switch]$IncludeWPFAssemblies, [switch]$CaseSensitive ) write-verbose "Searching for $typeName" $ps = @( 'CompiledComposition.Microsoft.PowerShell.GPowerShell', 'Microsoft.PowerShell.Commands.Diagnostics', 'Microsoft.PowerShell.Commands.Management', 'Microsoft.PowerShell.Commands.Utility', 'Microsoft.PowerShell.ConsoleHost', 'Microsoft.PowerShell.Editor', 'Microsoft.PowerShell.GPowerShell', 'Microsoft.PowerShell.Security', 'Microsoft.WSMan.Management', 'powershell_ise', 'PSEventHandler', 'System.Management.Automation') $wpf = @( 'PresentationCore', 'PresentationFramework', 'PresentationFramework.Aero', 'WindowsBase', 'UIAutomationProvider', 'UIAutomationTypes') $assemblies = [appdomain]::CurrentDomain.GetAssemblies() | ? { (!($_.getname().name -match '(mscorlib|^System$|^System\..*)')) -or $IncludeDotNetAssemblies} | ? { (!($ps -contains $_.getname().name)) -or $IncludePowershellAssemblies } | ? { (!($wpf -contains $_.getname().name)) -or $IncludeWPFAssemblies } $matches = @() $assemblies | % { write-verbose "Searching $($_.getname().name)..." $match = $_.gettype($typename, $false, $CaseSensitive) if ($match) { $matches += $match } } write-verbose "Found $($matches.length) match(es)." $matches } <# $iadapter.gettype().getmethods("NonPublic,Instance,Static") | ` select @{Name="Static";Expression={$_.isstatic}}, ` @{name="Name"; expression={$_.Name}}, ` @{Name="Definition"; Expression={$_.tostring()}} | ft -group static -auto #> # DotNetAdapter Fields # ========================== # instancePropertyCacheTable # staticPropertyCacheTable # instanceMethodCacheTable # staticMethodCacheTable # instanceEventCacheTable # staticEventCacheTable # instanceBindingFlags # staticBindingFlags #$stringCacheTable = $fields[0].getvalue( $dotnetinstanceadapter )[[string]] $instance = @{} $instance.adapter = $( [psobject].GetFields("NonPublic,Static")|?{$_.name -eq "dotNetInstanceAdapter"} ).GetValue([psobject]) $instance.adapter.gettype().getfields("NonPublic,Static") | % { $instance[$_.name] = $_.getvalue($instance.adapter); } $static = @{} $static.adapter = $( [psobject].GetFields("NonPublic,Static")|?{$_.name -eq "dotNetStaticAdapter"} ).GetValue([psobject]) $static.adapter.gettype().getfields("NonPublic,Static") | % { $static[$_.name] = $_.getvalue($static.adapter); } $binding = [reflection.bindingflags] $cacheTableType = [psobject].assembly.gettype("System.Management.Automation.CacheTable") $populateTableSig = [type[]]([type], $cacheTableType, $binding) $ipopulate = @{} $spopulate = @{} $ipopulate.method = $iadapter.gettype().getmethod("PopulateMethodReflectionTable", "NonPublic,Static", $null, $populateTableSig, @()) $spopulate.method = $sadapter.gettype().getmethod("PopulateMethodReflectionTable", "NonPublic,Static", $null, $populateTableSig, @()) function Get-StaticAdapter { $static.adapter } function Get-InstanceAdapter { $instance.adapter } function Get-MemberCacheTable { [cmdletbinding()] param( [parameter(mandatory=$true, position=0)] [validatenotnullorempty()] [string]$TypeName, [parameter(mandatory=$true, position=1)] [ValidateSet("Property","Method","Event")] [string]$MemberType, [parameter()] [switch]$Static ) $type = Find-Type -TypeName $TypeName -IncludeDotNetAssemblies -Verbose if ($Static) { $adapter = Get-StaticAdapter $cacheTableName = "static{0}CacheTable" $cacheTable = $static.$($cacheTableName -f $memberType) } else { $adapter = Get-InstanceAdapter $cacheTableName = "instance{0}CacheTable" $cacheTable = $instance.$($cacheTableName -f $memberType) } if ($type -is [type]) { $cacheTable[$type] } else { write-warning "Could not find $type in cacheTable." } } <# PS> $string = get-methodcachetable System.String Method PS> $ipopulate.method.invoke($instance.adapter, "NonPublic,Static", $null, @([string], $string, [reflection.bindingflags]"NonPublic,Public,Instance"), $null) PS C:\projects\powershell> $ipopulate.method.invoke($instance.adapter, "NonPublic,Static", $null, @([string], $string, [reflection.bindingflags]"NonPublic,Public,Instance"), $null) Exception calling "Invoke" with "5" argument(s): "Unable to cast object of type 'MethodCacheEntry' to type 'System.Collections.ArrayList'." At line:1 char:25 + $ipopulate.method.invoke <<<< ($instance.adapter, "NonPublic,Static", $null, @([string], $string, [reflection.bindingflags]"NonPublic,Public,Instance"), $null) + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : DotNetMethodTargetInvocation ________________________________________________________________________________________________________________________________________________________________________ PS C:\projects\powershell> $error[0].exception.tostring() System.Management.Automation.MethodInvocationException: Exception calling "Invoke" with "5" argument(s): "Unable to cast object of type 'MethodCacheEntry' to type 'System. Collections.ArrayList'." ---> System.InvalidCastException: Unable to cast object of type 'MethodCacheEntry' to type 'System.Collections.ArrayList'. at System.Management.Automation.DotNetAdapter.PopulateMethodReflectionTable(Type type, MethodInfo[] methods, CacheTable typeMethods) at System.Management.Automation.DotNetAdapter.PopulateMethodReflectionTable(Type type, CacheTable typeMethods, BindingFlags bindingFlags) --- End of inner exception stack trace --- at System.Management.Automation.DotNetAdapter.AuxiliaryMethodInvoke(Object target, Object[] arguments, MethodInformation methodInformation, Object[] originalArguments) at System.Management.Automation.DotNetAdapter.MethodInvokeDotNet(String methodName, Object target, MethodInformation[] methodInformation, Object[] arguments) at System.Management.Automation.Adapter.BaseMethodInvoke(PSMethod method, Object[] arguments) at System.Management.Automation.ParserOps.CallMethod(Token token, Object target, String methodName, Object[] paramArray, Boolean callStatic, Object valueToSet) at System.Management.Automation.MethodCallNode.InvokeMethod(Object target, Object[] arguments, Object value) at System.Management.Automation.MethodCallNode.Execute(Array input, Pipe outputPipe, ExecutionContext context) at System.Management.Automation.ParseTreeNode.Execute(Array input, Pipe outputPipe, ArrayList& resultList, ExecutionContext context) at System.Management.Automation.StatementListNode.ExecuteStatement(ParseTreeNode statement, Array input, Pipe outputPipe, ArrayList& resultList, ExecutionContext contex t) #> function Enable-ObjectPeek { param( [parameter(mandatory=$true)] [validatenotnull()] [type]$Type ) $flags = "FlattenHierarchy,Public,NonPublic,IgnoreCase" $cacheTableType = [psobject].assembly.gettype("System.Management.Automation.CacheTable") $populateTableSig = [type[]]([type], $cacheTableType, [reflection.bindingflags]) "Property","Method","Event" | % { $memberTypeName = $_ write-verbose "Scanning for $_" $dotNetInstanceAdapter.gettype().getmethods("NonPublic,Static") | ? { $_.name -eq ("GetInstance{0}ReflectionTable" -f $memberTypeName) } | % { $cache = $_.invoke($dotNetInstanceAdapter, $type) write-verbose "Retrieved instance cache for $membertypename" #System.Reflection.MethodInfo GetMethod(string name, System.Reflection.BindingFlags bindingAttr, # System.Reflection.Binder binder, type[] types, System.Reflection.ParameterModifier[] modifiers) $populate = $dotNetInstanceAdapter.gettype().getmethod($("Populate{0}ReflectionTable" -f $memberTypeName), "NonPublic,Static", $null, $populateTableSig, @()) write-verbose "Populating $type instance ${memberTypeName}: $_" # (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) $parameters = @([type]$type, $($cache -as $cacheTableType), $(($flags + ",Instance") -as $binding)) $host.EnterNestedPrompt() write-verbose "Invoking $populate" $populate.invoke($dotNetInstanceAdapter, "NonPublic,Static", $null, $parameters, $null) } $dotNetStaticAdapter.gettype().getmethods("NonPublic,Static") | ? { $_.name -eq ("GetStatic{0}ReflectionTable" -f $memberTypeName) } | % { $cache = $_.invoke($dotNetStaticAdapter, $type) $memberTypeName } } } function Disable-ObjectPeek { $flags = "FlattenHierarchy,Public,Static,IgnoreCase" } # | format-table -group name -auto new-alias peek enable-objectpeek -force new-alias unpeek disable-objectpeek -force #enable-objectpeek $([string]) -verbose |