PowerShell: преодоливая ограничения

в 16:58, , рубрики: powershell, книга

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

Хотя помянать второй PowerShell все же еще рановато.

Операторы -shl и -shr

Как известно, операторы побитового сдвига влево (-shl) и вправо (-shr) появились в PowerShell начиная с третьей версии, к слову, не самой удачной. До этого некоторые администраторы и, что более удивительно, программисты негодовали на данное упущение, правда находились из них бившие себя пяткой в грудь, дескать, проблема решается следующим образом:

Add-Type @"
public class Shift {
   public static int   Right(int x,   int count) { return x >> count; }
   public static uint  Right(uint x,  int count) { return x >> count; }
   public static long  Right(long x,  int count) { return x >> count; }
   public static ulong Right(ulong x, int count) { return x >> count; }
   public static int    Left(int x,   int count) { return x << count; }
   public static uint   Left(uint x,  int count) { return x << count; }
   public static long   Left(long x,  int count) { return x << count; }
   public static ulong  Left(ulong x, int count) { return x << count; }
}                    
"@

Совершенно очевидно, что каждый из вышеобозначенных пяточников просто тупо копипастил код, не удосужившись припомнить математику. Ибо что есть побитовый сдвиг на одну позицию влево с точки зрения последней? Правильно — умножение на 2. Иными словами запись 7 -shl 1 можно представить:

PS E:> 7 * [Math]::Pow(2, 1)
14

А 7 -shl 2:

PS E:> 7 * [Math]::Pow(2, 2)
28

И т.д. Сдвиг вправо на одну позицию противоположен сдвигу влево, т.е. эквивалентен делению на 2 с отбрасываением остатка от деления.

PS E:> [Math]::Floor(7 / [Math]::Pow(2, 1))
3

Иными словами, создание сборки на этом фоне кажется не то, что неубедительным, а просто недоразумением.
Альтернативный способ — определить динамический метод с использованием MSIL, в переводе на который сдвиг представляется как:

Ldarg_0
Ldarg_1
Ldc_I4_S, 31
And
Shl          //или Shr, если сдвигать нужно вправо
Ret

Концептуально это будет выглядеть так:

#акселераторы
@(
  [Reflection.Emit.DynamicMethod],
  [Reflection.Emit.OpCodes]
) | ForEach-Object {
  $keys = ($ta = [PSObject].Assembly.GetType(
    'System.Management.Automation.TypeAccelerators'
  ))::Get.Keys
  $collect = @()
}{
  if ($keys -notcontains $_.Name) {
    $ta::Add($_.Name, $_)
  }
  $collect += $_.Name
}

function Set-ShiftMethod {
  param(
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [ValidateSet('Left', 'Right')]
    [String]$X = 'Left'
  )
  
  #массив опкодов - не будем же мы писать несколько методов
  #из-за разницы всего в одном опкоде, верно?!
  @(
    'Ldarg_0'
    'Ldarg_1'
    'Ldc_I4_S, 31'
    'And'
    $(if ($X -eq 'Right') { 'Shr' } else { 'Shl' })
    'Ret'
  ) | ForEach-Object {
    #наш динамический метод
    $def = New-Object DynamicMethod(
      $X, [Int32], @([Int32], [Int32])
    )
    $il = $def.GetILGenerator()
  }{
    if ($_ -notmatch ',') { $il.Emit([OpCodes]::$_) }
    else {$il.Emit(
      [OpCodes]::(($$ = $_.Split(','))[0]), [Int32]($$[1].Trim())
    )}
  }
  #создаем делегат
  $def.CreateDelegate([Func[Int32, Int32, Int32]])
}

#примеры
(Set-ShiftMethod Left).Invoke(7, 3)  #7 -shl 3 -> 56
(Set-ShiftMethod Right).Invoke(7, 1) #7 -shr 1 -> 3

#удаляем акселераторы
$collect | ForEach-Object { [void]$ta::Remove($_) }

Примерные скроки выхода книги о PowerShell
План книги, о которой была речь в предыдущем посте, составлен и в черновом варианте, в котором он и прибывает, пока что выглядит так.

  • Внутреннее устройство PowerShell
  • Командлеты и модули
  • Типы и рефлексия
  • Использование MSIL в PowerShell
  • Все о PInvoke
  • Приложения

Все это планируется рассматривать с учетом x64, однако пересчитав свои скромные сбережения, выяснилось — тот максимум, на который их хватит не шибко велик и в лучшем случае составит месяц. По этой причине, если конечно вдруг не произойдет чуда или кто-то не изъявит поддержать материально, работа над книгой приостанавливается. Если есть желание все же прочесть в будущем книгу, можете начинать сбор подписей (а вместе с ними и средств :) на ее создание. Адрес для сбора подписей powershellbook@mail.ru

Автор: GrigoriZakharov

Источник

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


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