How to avoid PSAMSIMethodInvocationLogging. In the previously introduced method, a cmdlet is dynamically generated to execute a method by reflection. In this method, the method is executed by reflection by defining a type for the method invocation and having the Hashtable cast to that type. In the example, with Windows Defender real-time protection enabled, a process that would take up to 35 seconds to complete would take about 1 second using this method.
Last active
October 31, 2023 06:27
-
-
Save mutaguchi/36b7e6094e2053c6d3dd12cea67ca058 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$code = @" | |
using System; | |
using System.Management.Automation; | |
using System.Linq; | |
using System.Collections.Generic; | |
using System.Reflection; | |
using System.Collections; | |
using System.ComponentModel; | |
using System.Xml.Linq; | |
public class Invoke | |
{ | |
public Invoke(Hashtable methodInvocation) | |
{ | |
string name = null; | |
object target = null; | |
object[] arguments = null; | |
foreach (DictionaryEntry item in methodInvocation) | |
{ | |
var keyObj = GetBaseObject(item.Key); | |
if (keyObj is not string key) | |
return; | |
key = key.ToLower(); | |
var val = GetBaseObject(item.Value); | |
switch (key) | |
{ | |
case "n" or "name": | |
if (val is string v) | |
name = v; | |
break; | |
case "t" or "target": | |
target = val; | |
break; | |
case "a" or "arg" or "args" or "argument" or "arguments": | |
if (val is object[] objs) | |
{ | |
arguments = objs; | |
} | |
else | |
{ | |
arguments = new object[] { val }; | |
} | |
break; | |
} | |
} | |
if (target is null || name is null) | |
throw new InvalidOperationException($"Insufficient method information."); | |
arguments ??= new object[0]; | |
var method = target.GetType().GetMethod(name, | |
arguments.Select(arg => arg.GetType()).ToArray()); | |
if(method is null) | |
throw new InvalidOperationException($"Method is not found."); | |
_result = method.Invoke(target, arguments); | |
} | |
private object _result = null; | |
public object Result { get => _result; } | |
private object GetBaseObject(object obj) => obj switch | |
{ | |
PSObject pso => pso.BaseObject, | |
_ => obj | |
}; | |
} | |
"@ | |
Import-Module -Assembly (Add-Type -TypeDefinition $code -PassThru).Assembly | |
$test = "a" | |
$result = ([Invoke]@{target = $test; Name = "PadRight"; Args = 10, [char]"x" }).Result | |
Write-Host $result | |
$obj = 'x' | |
$short_arg = 'a' * 100 | |
$long_arg = 'a' * 1000 | |
$range = 1..1000000 | |
Write-Host "method invoke (with short_arg): $((Measure-Command {foreach ($i in $range) {$y=$obj.Contains($short_arg)}}).TotalSeconds) sec" | |
Write-Host "method invoke (with long_arg): $((Measure-Command {foreach ($i in $range) {$y=$obj.Contains($long_arg)}}).TotalSeconds) sec" | |
Write-Host "type invoke (with short_arg): $((Measure-Command {foreach ($i in $range) {$y=([Invoke]@{t=$obj;n="Contains";args=$short_arg}).Result }}).TotalSeconds) sec" | |
Write-Host "type invoke (with long_arg): $((Measure-Command {foreach ($i in $range) {$y=([Invoke]@{t=$obj;n="Contains";args=$long_arg}).Result }}).TotalSeconds) sec" | |
Read-Host Press any key. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment