# encoding: ascii
# api: powershell
# title: Get-CoolingMode
# description: https://github.com/gregzakh/alt-ps/blob/master/diag/Get-CoolingMode.ps1
# version: 0.1
# type: function
# author: greg zakharov
# license: CC0
# function: Import-FromDll
# x-poshcode-id: 6706
# x-archived: 2017-01-24T13:41:52
# x-published: 2017-01-20T11:24:00
#
#
function Import-FromDll {
<#
.SYNOPSIS
Allows to invoke some WinAPI functions without using Add-Type
cmdlet.
.DESCRIPTION
This is possible due to reflection and Func and Action delegates.
Import-FromDll uses GetModuleHandle and GetProcAddress functions
stored into Microsoft.Win32.Win32Native type of mscorlib.dll
.PARAMETER Module
Library module name (DLL). Note that it should be currently loaded
by host, to check this:
(ps -Is $PID).Modules | ? {$_.FileName -notmatch '(\.net|assembly)'}
.PARAMETER Signature
Signatures storage which presented as a hashtable.
.EXAMPLE
$kernel32 = Import-FromDll kernel32 -Signature @{
CreateHardLinkW = [Func[[Byte[]], [Byte[]], IntPtr, Boolean]]
GetCurrentProcessId = [Func[Int32]]
}
$kernel32.GetCurrentProcessId.Invoke()
This will return value which is equaled $PID variable.
$kernel32.CreateHardLinkW.Invoke(
[Text.Encoding]::Unicode.GetBytes('E:\to\target.ext'),
[Text.Encoding]::Unicode.GetBytes('E:\from\source.ext'),
[IntPtr]::Zero
)
Establishes a hard link between an existing file and a new file.
.OUTPUTS
Hashtable
.NOTES
Author: greg zakharov
#>
param(
[Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[String]$Module,
[Parameter(Mandatory=$true, Position=1)]
[ValidateNotNull()]
[Hashtable]$Signature
)
begin {
function script:Get-ProcAddress {
[OutputType([Hashtable])]
param(
[Parameter(Mandatory=$true, Position=0)]
[ValidateNotNullOrEmpty()]
[String]$Module,
[Parameter(Mandatory=$true, Position=1)]
[ValidateNotNull()]
[String[]]$Function
)
begin {
[Object].Assembly.GetType(
'Microsoft.Win32.Win32Native'
).GetMethods(
[Reflection.BindingFlags]40
) | Where-Object {
$_.Name -cmatch '\AGet(ProcA|ModuleH)'
} | ForEach-Object {
Set-Variable $_.Name $_
}
if (($mod = $GetModuleHandle.Invoke(
$null, @($Module)
)) -eq [IntPtr]::Zero) {
throw New-Object InvalidOperationException(
'Could not find specified module.'
)
}
}
process {}
end {
$table = @{}
foreach ($f in $Function) {
if (($$ = $GetProcAddress.Invoke(
$null, @($mod, $f)
)) -ne [IntPtr]::Zero) {
$table.$f = $$
}
}
$table
}
}
function private:New-Delegate {
param(
[Parameter(Mandatory=$true, Position=0)]
[ValidateScript({$_ -ne [IntPtr]::Zero})]
[IntPtr]$ProcAddress,
[Parameter(Mandatory=$true, Position=1)]
[ValidateNotNull()]
[Type]$Prototype,
[Parameter(Position=2)]
[ValidateNotNullOrEmpty()]
[Runtime.InteropServices.CallingConvention]
$CallingConvention = 'StdCall'
)
$method = $Prototype.GetMethod('Invoke')
$returntype = $method.ReturnType
$paramtypes = $method.GetParameters() |
Select-Object -ExpandProperty ParameterType
$holder = New-Object Reflection.Emit.DynamicMethod(
'Invoke', $returntype, $(
if (!$paramtypes) { $null } else { $paramtypes }
), $Prototype
)
$il = $holder.GetILGenerator()
if ($paramtypes) {
0..($paramtypes.Length - 1) | ForEach-Object {
$il.Emit([Reflection.Emit.OpCodes]::Ldarg, $_)
}
}
switch ([IntPtr]::Size) {
4 { $il.Emit([Reflection.Emit.OpCodes]::Ldc_I4, $ProcAddress.ToInt32()) }
8 { $il.Emit([Reflection.Emit.OpCodes]::Ldc_I8, $ProcAddress.ToInt64()) }
}
$il.EmitCalli(
[Reflection.Emit.OpCodes]::Calli, $CallingConvention, $returntype,
$(if (!$paramtypes) { $null } else { $paramtypes })
)
$il.Emit([Reflection.Emit.OpCodes]::Ret)
$holder.CreateDelegate($Prototype)
}
}
process {}
end {
$scope, $fname = @{}, (Get-ProcAddress $Module $Signature.Keys)
foreach ($key in $fname.Keys) {
$scope[$key] = New-Delegate $fname[$key] $Signature[$key]
}
$scope
}
}
function Get-CoolingMode {
<#
.SYNOPSIS
Gets the current system cooling mode.
.NOTES
Author: greg zakharov
#>
begin {
$ntdll = Import-FromDll ntdll -Signature @{
NtPowerInformation = [Func[Int32, IntPtr, Int32, IntPtr, Int32, Int32]]
}
$sz = 0x10 # sizeof(SYSTEM_POWER_INFORMATION)
$COOLING_MODE = @('PO_TZ_ACTIVE', 'PO_TZ_PASSIVE', 'PO_TZ_INVALID_MODE')
}
process {
try {
$spi = [Runtime.InteropServices.Marshal]::AllocHGlobal($sz)
if ($ntdll.NtPowerInformation.Invoke(
12, [IntPtr]::Zero, 0, $spi, $sz
) -ne 0) {
throw New-Object InvalidOperationException(
'Could not retrieve current cooling mode.'
)
}
$COOLING_MODE[[Runtime.InteropServices.Marshal]::ReadByte($spi, 0xC)]
}
catch { Write-Verbose $_ }
finally {
if ($spi) { [Runtime.InteropServices.Marshal]::FreeHGlobal($spi) }
}
}
end {}
}