Skip to content

Instantly share code, notes, and snippets.

@mutaguchi
Last active October 31, 2023 06:27
Show Gist options
  • Save mutaguchi/36b7e6094e2053c6d3dd12cea67ca058 to your computer and use it in GitHub Desktop.
Save mutaguchi/36b7e6094e2053c6d3dd12cea67ca058 to your computer and use it in GitHub Desktop.

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.

$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