pstools.psm1
using namespace System.Reflection using namespace System.ComponentModel using namespace System.Linq.Expressions using namespace System.Management.Automation using namespace System.Runtime.InteropServices using namespace System.Collections.ObjectModel Set-Content -Path env:__COMPAT_LAYER -Value RunAsInvoker -Force -ErrorAction 0 $MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { Remove-Item -Path env:__COMPAT_LAYER -Force -ErrorAction 0 } $keys, $types = ($x = [PSObject].Assembly.GetType( 'System.Management.Automation.TypeAccelerators' ))::Get.Keys, @{ buf = [Byte[]] dptr = [UIntPtr] ptr = [IntPtr] ptr_ = [IntPtr].MakeByRefType() uint_ = [UInt32].MakeByRefType() sfh = [Microsoft.Win32.SafeHandles.SafeFileHandle] } $types.Keys.ForEach{ if ($_ -notin $keys) { $x::Add($_, $types.$_) } } Add-Member -InputObject ([buf]) -Name Uni -MemberType ScriptMethod -Value { param([String]$str) [Text.Encoding]::Unicode.GetBytes($str) } -Force Add-Member -InputObject ([ptr]) -Name Mov -MemberType ScriptMethod -Value { param([IntPtr]$ptr, [Int32]$offset) [IntPtr]($ptr."ToInt$([IntPtr]::Size * 8)"() + $offset) } -Force Add-Member -InputObject ([enum]) -Name All -MemberType ScriptMethod -Value { param([Hashtable]$flags, [Int32]$val) ($flags.Keys.Where{ ($flags[$_] -band $val) -eq $flags[$_] }, 'n/a')[!$val] -join ' + ' } -Force function New-Delegate { [CmdletBinding()] param( [Parameter(Mandatory, Position=0)] [ValidateNotNullOrEmpty()] [String]$Module, [Parameter(Mandatory, Position=1)] [ValidateScript({![String]::IsNullOrEmpty($_)})] [ScriptBlock]$Signature ) begin { $kernel32 = @{} [Array]::Find(( Add-Type -AssemblyName Microsoft.Win32.SystemEvents -PassThru ), [Predicate[Type]]{$args[0].Name -eq 'kernel32'} ).GetMethods([BindingFlags]'NonPublic, Static, Public').Where{ $_.Name -cmatch '\AGet(P|M)' }.ForEach{ $kernel32[$_.Name] = $_ } if (($mod = $kernel32.GetModuleHandle.Invoke($null, @($Module))) -eq [IntPtr]::Zero) { throw [DllNotFoundException]::new("Cannot find $Module library.") } } process {} end { $funcs = @{} for ($i, $m, $fn, $p = 0, ([Expression].Assembly.GetType( 'System.Linq.Expressions.Compiler.DelegateHelpers' ).GetMethod('MakeNewCustomDelegate', [BindingFlags]'NonPublic, Static') ), [Marshal].GetMethod('GetDelegateForFunctionPointer', ([IntPtr])), $Signature.Ast.FindAll({$args[0].CommandElements}, $true).ToArray(); $i -lt $p.Length; $i++ ) { $fnret, $fname = ($def = $p[$i].CommandElements).Value if (( $fnsig = $kernel32.GetProcAddress.Invoke($null, @($mod, $fname)) ) -eq [IntPtr]::Zero) { throw [InvalidOperationException]::new("Cannot find $fname signature.") } $fnargs = $def.Pipeline.Extent.Text [Object[]]$fnargs = (( ($fnargs -replace '\[|\]' -split ',\s+?') + $fnret ), $fnret)[[String]::IsNullOrEmpty($fnargs)] $funcs[$fname] = $fn.MakeGenericMethod( [Delegate]::CreateDelegate([Func[[Type[]], Type]], $m).Invoke($fnargs) ).Invoke([Marshal], $fnsig) } Set-Variable $Module -Value $funcs -Scope Script -Force } } function New-DynParameter { [CmdletBinding()] param( [Parameter(Mandatory)] [Hashtable[]]$Parameter ) process { $dict = [RuntimeDefinedParameterDictionary]::new() $Parameter.ForEach{ if ($_.GetType().Name -ne 'Hashtable' -or !$_.Count) { throw [ArgumentException]::new('Invalid argument.') } $attr = [Collection[Attribute]]::new() $attr.Add((New-Object Management.Automation.ParameterAttribute -Property @{ ParameterSetName = $_.ParameterSetName # __AllParameterSets by default Mandatory = $_.Mandatory Position = (0x80000000, $_.Position)[$_.Position -ge 0] ValueFromPipeline = $_.ValueFromPipeline ValueFromPipelineByPropertyName = $_.ValueFromPipelineByPropertyName })) if ($_.ValidateNotNullOrEmpty) { $attr.Add([ValidateNotNullOrEmptyAttribute]::new()) } if ($_.ValidateScript) { $attr.Add((New-Object Management.Automation.ValidateScriptAttribute($_.ValidateScript))) } if ($_.ValidateSet) { $attr.Add((New-Object Management.Automation.ValidateSetAttribute($_.ValidateSet))) } $dict.Add($_.Name, (New-Object Management.Automation.RuntimeDefinedParameter( $_.Name, $_.Type, $attr) -Property @{ Value = $_.Value # this makes it easy to call dynamic parameters } -OutVariable "script:param$($_.Name)" # example: $param(Name) )) } $dict } } function Read-DataValues { [CmdletBinding(DefaultParameterSetName='Buffer')] param( [Parameter(Mandatory, ParameterSetName='Buffer', Position=0)] [ValidateNotNull()] [Byte[]]$Buffer, [Parameter(Mandatory, ParameterSetName='Handle', Position=0)] [ValidateScript({$_ -ne [IntPtr]::Zero})] [IntPtr]$Handle, [Parameter(Mandatory, Position=1)] [ValidateNotNullOrEmpty()] [String]$Map ) process { $pos, $set = 0, @{b='Byte';s='Int16';i='Int32';l='Int64';p='IntPtr'} try { $ptr = ($Handle, ( $gch = [GCHandle]::Alloc($Buffer, [GCHandleType]::Pinned) ).AddrOfPinnedObject())[$PSCmdlet.ParameterSetName -eq 'Buffer'] ($Map -split '(\S(?:\d+)?)').Where{$_}.ForEach{ if ($_ -notmatch '([bsilp])(\d+)?') { throw [InvalidOperationException]::new('Invalid map value.') } $block = ((,$null * 2) + ( # char and pair "char-number" $matches[0], [Char[]]($matches[1] * $matches[2]) ))[$matches.Count] .({ # Int16, Int32, Int64 and IntPtr foreach ($char in $block) { $tmp = [Marshal]::"Read$($set["$char"])"($ptr, $pos) if ([Char]::IsUpper($char) -and $char -ne 'p') { [BitConverter]::"ToU$($set["$char"])"( [BitConverter]::GetBytes($tmp), 0 ) } else { $tmp } Write-Verbose "+0x$($pos.ToString('X3'))" $pos += [Marshal]::SizeOf(0 -as ([Type]$set["$char"])) } },{ # Byte if ([Char]::IsUpper($block[0])) { [Marshal]::PtrToStringAuto([IntPtr]( $ptr."ToInt$([IntPtr]::Size * 8)"() + $pos ), $block.Length).Split("`0")[0] Write-Verbose "+0x$($pos.ToString('X3'))" $pos += $block.Length } else { -join$(foreach ($$ in $block) { "\x$([Marshal]::ReadByte($ptr, $pos).ToString('X2'))" Write-Verbose "+0x$($pos.ToString('X3'))" $pos += [Marshal]::SizeOf([Byte]0) }) } })[$block -contains 'b'] } } catch { Write-Verbose $_ } finally { if ($gch) { $gch.Free() } } } } function New-PsProxy { [CmdletBinding(DefaultParameterSetName='Name')] param( [Parameter(Mandatory, ParameterSetName='Name', Position=0)] [ValidateNotNullOrEmpty()] [String[]]$Name, [Parameter(Mandatory, ParameterSetName='Id', Position=0)] [Alias('PID')] [Int32[]]$Id, [Parameter(Mandatory, Position=1)] [ValidateScript({![String]::IsNullOrEmpty($_)})] [ScriptBlock]$Callback ) begin { if ($PSBoundParameters.Callback) { [void]$PSBoundParameters.Remove('Callback') } $PSBoundParameters.Add('OutVariable', 'ps') $cmd = {Out-Null -InputObject (& ( Get-Command -CommandType Cmdlet -Name Get-Process ) @PSBoundParameters)}.GetSteppablePipeline($MyInvocation.CommandOrigin) $cmd.Begin($PSCmdlet) } process { $cmd.Process($_) } end { $cmd.End() $ps.ForEach{ .$Callback $_ $_.Dispose() } } } function ConvertTo-ErrMessage { [CmdletBinding(DefaultParameterSetName='Win32')] param( [Parameter(Mandatory, ParameterSetName='Win32', Position=0)] [Int32]$Win32, [Parameter(Mandatory, ParameterSetName='NtStatus', Position=0)] [Int32]$NtStatus ) process { [Win32Exception]::new((.({$Win32},{ New-Delegate ntdll { int RtlNtStatusToDosError([int]) } $ntdll.RtlNtStatusToDosError.Invoke($NtStatus) })[$PSCmdlet.ParameterSetName -eq 'NtStatus'])).Message.ToLower() } } (Get-ChildItem "$PSScriptRoot\pwsh" -Filter *.ps1).ForEach{.$_.FullName} |