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

от автора

Привычные вещи отнюдь не статичны как о них положено думать, и если на них посмотреть под иным углом, причем не обязательно с высоким градусом и вызывающим похмелье, можно открыть для себя нечто новое, способное во многом повысить эффективность работы.

Если проводить аналогии, профили PowerShell — те же конфигурационные файлы терминалов *nix, основное назначение которых хранить пользовательские настройки. Более подродно о профилях можно почитать во встроенном руководстве:

PS C:\> man about_Profiles 

Совершенно очевидно, что пихать в профиль все что ни поподя не следует — чем больше вес файла, тем менее скорость загрузки хоста, если конечно не был указан параметр /noprofile при вызове последнего. Обычно профили применяются для упреждения неоднозначностей (о них чуть позже), настройки окружения и определения часто используемых функций. Попробуем пояснить это на примере.

PS C:\> ni -Type File -Path $Profile -Force PS C:\> vim $Profile #vim - сугубо личное предпочтение 

Было бы неплохо иметь постоянно доступ к ускорителям типов.

if (($ta = [PSObject].Assembly.GetType(   'System.Management.Automation.TypeAccelerators' ))::Get.Keys -notcontains 'accelerators') {   $ta::Add('accelerators', $ta) } 

Для того, чтобы изменения вступили в силу, требуется перезапустить хост.

PS C:\> ii (ls $env:allusersprofile -r -ea 0).Where({$_.Name -match 'shell.lnk'}).FullName;kill $pid ... PS C:\> [accelerators]::Get  Key                    Value ---                    ----- Alias                  System.Management.Automation.AliasAttribute AllowEmptyCollection   System.Management.Automation.AllowEmptyCollectionAttribute AllowEmptyString       System.Management.Automation.AllowEmptyStringAttribute AllowNull              System.Management.Automation.AllowNullAttribute array                  System.Array bool                   System.Boolean byte                   System.Byte char                   System.Char CmdletBinding          System.Management.Automation.CmdletBindingAttribute datetime               System.DateTime ... 

Ранее упомяналось о неких неоднозначностях, самая пора к ним вернуться. Дело в том, что от использования переменных env: следует отказаться по причине возможности их изменения.

PS C:\> gc env:allusersprofile C:\ProgramData PS C:\> $old = gc env:allusersprofile PS C:\> sc env:allusersprofile C:\ PS C:\> gc env:allusersprofile C:\ PS C:\> sc env:allusersprofile $old PS C:\> gc env:allusersprofile C:\ProgramData 

Иными словами перезапуск хоста способом выше без предварительной проверки переменной allusersprofile — не самая лучшая идея, и, если в том возникает необходимость, лучше использовать переменные окружения определенные в Environment+SpecialFolder или просто предопределить некоторые переменные env: в виде констант.

Так как Корзина используется некоторыми как пункт промежуточного хранения файлов, почему бы не упростить себе задачу и в этом случае?!

Set-Content function:trash {   param(     [Parameter(Mandatory=$true)]     [ValidateScript({Test-Path $_})]     [String]$Path   )    (New-Object -ComObject Shell.Application).NameSpace(0xA).MoveHere(     (Convert-Path $Path)   ) } 

В итоге помещать файлы в Корзину станет проще:

PS C:\> trash E:\doc\foo 

Требуется возможностью перевода незнакомых слов? Денег на покупку дорогостоящих приложений у нас нет, поэтому будем использовать онлайн-переводчик, а точнее — Яндекс.Перевод, благо у того вменяемое API, да и качество переводов неплохое. Устанавливаем API-ключ.

PS C:\> $key = '...' #API-ключ PS C:\> $bin = "$([Environment]::GetFolderPath('UserProfile'))\yatrans.bin" PS C:\> Add-Type -AssemblyName System.Security PS C:\> [IO.File]::WriteAllBytes( >> $bin, >> [Security.Cryptography.ProtectedData]::Protect( >> [Text.Encoding]::Unicode.GetBytes($key), >> $null, >> [Security.Cryptography.DataProtectionScope]::CurrentUser >> )) >> PS C:\> attrib +h $bin 

Ключ установили, теперь можно приступать к чтению документации API. Если же совсем невтерпеж, то в самом простом варианте, функция перевода может выглядеть так.

function Get-Translation {   param(     [Parameter(Mandatory=$true)]     [ValidateNotNullOrEmpty()]     [String]$Data   )      begin {     Add-Type -AssemblyName System.Security     # декодирование ключа     if (Test-Path ($key = "$([Environment]::GetFolderPath('UserProfile'))\yatrans.bin")) {       $key = [Text.Encoding]::Unicode.GetString(         [Security.Cryptography.ProtectedData]::Unprotect(           [IO.File]::ReadAllBytes($key),           $null,           [Security.Cryptography.DataProtectionScope]::CurrentUser         )       )     }     else {       throw 'API-ключ Яндекс.Перевод не найден.'     }     # url-root     $url = 'https://translate.yandex.net/api/v1.5/tr/'     # определение языка оригинала     $detect = "$($url)detect?key=$key&text="     # перевод     $transl = "$($url)translate?key=$key&text=%t&lang=%l-ru&format=plain"     # user agent     $usr = 'Mozilla/5.0 (Windows NT 6.3; rv:37.0.1) Gecko/20100101 Firefox/37.0.1'   }   process {     # для перевода текстовых файлов     $Data = if (Test-Path $Data) { gc $Data } else { $Data }     $res = [xml](wget "$detect$Data" -DisableKeepAlive -UseBasicParsing -UserAgent $usr).Content     if ($res.DetectedLang.code -ne 200) {       throw 'Невозможно определить язык.'     }          $transl = $transl -replace '%t', $Data     $transl = $transl -replace '%l', $res.DetectedLang.lang     $res = [xml](wget $transl -DisableKeepAlive -UseBasicParsing -UserAgent $usr).Content     if ($res.Translation.code -ne 200) {       throw 'Невозможно перевести текст.'     }     $res.Translation.text   } } 

Функция в действии:

PS C:\> Get-Translation 'Die Zeit ist auf!' - Время! PS C:\> vim foo Hey, teacher! Leave this kids alone! ... PS C:\> Get-Translation foo Эй, учитель! Оставить детей в покое! PS C:\> ri foo PS C:\> 

К слову, Яндекс предоставляет возможность узнать свой публичный IP — также может сгодиться в хозяйстве:

$par = @{   Uri = 'http://ipv4.internet.yandex.ru/internet/api/v0/ip'   DisableKeepAlive = $true   UseBasicParsing = $true   UserAgent = 'Mozilla/5.0 (Windows NT 6.3; rv:37.0.1) Gecko/20100101 Firefox/37.0.1' }  (wget @par).Content -replace [Char]34, '' 

Все, что не планируется использовать в повседневной работе, лучше выносить в отдельные модули.

ссылка на оригинал статьи http://habrahabr.ru/post/255973/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *