PowerShell: за гранью. Часть третья

в 16:43, , рубрики: powershell, powershell2, Программирование

Каждый по-своему распоряжается свободным временем, мне, например, нравится реализовывать аналоги различных утилит на скриптовых языках и, нужно отметить, занятие это довольно забавное, так как в процессе работы над некоторыми из них невольно закрадывается мысль, что последние, возможно, всего лишь экзерсисы их авторов, позиционируемые как крайне необходимый в быту тулкит. Какая от всего этого практическая ценность? Ничего кроме независимости от чужих ошибок, а также возможности дополнитьурезать уже реализованный в оригинальной утилите функционал, на ум не приходит. Хотя, если брать в расчет отсутсвие исходных кодов оригиналов, ценным может статься сам опыт.

Среди моих коллег и знакомых, как ни странно, востребованными являются отнюдь не утилиты SysInternals, а собрание сочинений Нир Софера. Если честно, то из всего написанного последним ничем пользоваться не доводилось, более того, знакомство с его творчеством произошло совсем недавно и, следует заметить, оно не произвело эффекта, так как в некоторых случаях это не такие уж необходиммые в будничной практике вещи (о них-то и пойдет речь). Взять, к примеру, BatteryInfoView, какой смысл в этой утилите? Всего лишь GetSystemPowerStatus в упаковочном пенопласте и пометкой «не кантовать», а оно нам надо? Если голова и руки на том месте, где им и подобает быть согласно анатомии, можно нарисовать тот же BatteryInfoView всего двумя штрихами.

PS C:> Add-Type -AssemblyName System.Windows.Forms
PS C:> [Windows.Forms.PowerStatus].GetConstructor([Reflection.BindingFlags]36, $null, [Type[]]@(), $null).Invoke($null)

PowerLineStatus      : Offline
BatteryChargeStatus  : 0
BatteryFullLifetime  : -1
BatteryLifePercent   : 0,61
BatteryLifeRemaining : 10808

PS C:>

Ладно, возьмем что-то менее очевидное, например, ProduKey, — подобные утилиты пользуются большим спросом не то в виду рассеяности пользователей, не то из-за убежденности последних в неких сакраментальных знаниях разработчика. А между тем никакого волшебства нет: активационные ключи M$ храниятся в REG_BINARY параметрах DigitalProductId, а их декодирование (на примере ключа Windows) происходит примерно так.

PS C:> $cur = gp 'HKLM:SOFTWAREMicrosoftWindows NTCurrentVersion'
PS C:> $raw = $cur.DigitalProductId[52..66]
PS C:> $map = 'BCDFGHJKMPQRTVWXY2346789'
PS C:> $key = ''
PS C:> for ($i = 24; $i -ge 0; $i--) {
>> $k = 0
>> for ($j = 14; $j -ge 0; $j--) {
>> $k = ($k * 256) -bxor $raw[$j]
>> $raw[$j] = [Math]::Floor([Double]($k / 24))
>> $k %= 24
>> }
>> $key = $map[$k] + $key
>> if (($i % 5) -eq 0 -and $i -ne 0) {$key = '-' + $key}
>> }
>>
PS C:> New-Object PSObject -Property @{
>> Name = $cur.ProductName
>> ProductId = [Text.Encoding]::Default.GetString($cur.DigitalProductId[8..30])
>> ProductKey = $key
>> }
>>
...
PS C:>

Следующей на очереди утилитой оказалась GACView. И снова PowerShell спешит на помощь.

PS C:> [Collections.ArrayList]$al = New-Object Collections.ArrayList
PS C:> ($o = [Object].Assembly).GetType('Microsoft.Win32.Fusion').GetMethod('ReadCache').Invoke($null, @(
>> $al, $null, $o.GetType('Microsoft.Win32.ASM_CACHE').GetField('GAC').GetValue($null)))
>>
PS C:> $al | Out-GridView -Title GACView

Если нужен дополнительный функционал, можно использовать WinForms или WPF.
Далее — MUICacheView.

PS C:> ($rk = gi 'HKCU:SoftwareClassesLocal SettingsSoftwareMicrosoftWindowsShellMuiCache').GetValueNames() |
>> % {New-Object PSObject -Property @{ApplicationPath=$_;ApplicationName=$rk.GetValue($_)}} |
>> Out-GridView -Title MUICacheView
>>
PS C:> $rk.Close()

И напоследок — UserAssistView.

#requires -version 2.0
gp HKCU:SoftwareMicrosoftWindowsCurrentVersionExplorerUserAssist*Count | % {
  $rot13 = New-Object "Collections.Generic.Dictionary[Char, Char]"
  $table = {
    param([Int32[]]$arr, [Int32]$lim)
    
    $arr | % {
      $$ = if ($_ -le $lim) {$_ + 13} else {$_ - 13}
      $rot13.Add([Char]$_, [Char]$$)
    }
  }
  $table.Invoke(65..90, 77) #верхний регистр
  $table.Invoke(97..122, 109) #нижний регистр
}{
  $top = Split-Path -Leaf $_.PSParentPath
  $_.PSObject.Properties | ? {$_.Name -notlike 'PS*'} | % {
    if ($_.Value.Length -eq 16) {
      $idx = [BitConverter]::ToUInt32($_.Value[0..3], 0)
      $cnt = [BitConverter]::ToUInt32($_.Value[4..7], 0)
      
      $time = [BitConverter]::ToInt64($_.Value[8..15], 0)
      $time = if ($time -ne 0) {[DateTime]::FromFileTime($time)} else {[String]::Empty}
    }
    else {
      $idx = [BitConverter]::ToUInt32($_.Value[4..7], 0)
      $cnt = [String]::Empty
    }
    
    New-Object PSObject -Property @{
      Name    = -join ($_.Name.ToCharArray() | % {if ($rot13.ContainsKey($_)) {$rot13[$_]} else {$_}})
      Index   = $idx
      Count   = $cnt
      Time    = $time
      ClassId = $top
    }
  }
} | Out-GridView -Title UserAssistView

Вот такой антихит-парад утилит Нир Софера.

Автор: gregzakharov

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js