Безделушка для транслитерации на PowerShell скомпилированная в исполняемый файл.

imageВ организации изменились правила транслитерации имён пользователей при создании почтовых ящиков email. И захотелось сделать какой-нибудь простенький инструмент на Powershell для автоматической транслитерации имён, чтобы не ломать голову каждый раз вспоминая правила сопоставления символов при необходимости создания нового мылбокса. За основу был взята PS-функция транслитерации Ильи Сазонова (с учётом правки правил преобразования для нужд нашей организации) и добавлен код для поддержки простой диалоговой формы.

Сам скрипт:

[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

function TranslitRU2LAT{
    param([string]$inString)
    $Translit = @{ 
    [char]'а' = "a";[char]'А' = "A";
    [char]'б' = "b";[char]'Б' = "B";
    [char]'в' = "v";[char]'В' = "V";
    [char]'г' = "g";[char]'Г' = "G";
    [char]'д' = "d";[char]'Д' = "D";
    [char]'е' = "e";[char]'Е' = "E";
    [char]'ё' = "ye";[char]'Ё' = "Ye";
    [char]'ж' = "zh";[char]'Ж' = "Zh";
    [char]'з' = "z";[char]'З' = "Z";
    [char]'и' = "i";[char]'И' = "I";
    [char]'й' = "y";[char]'Й' = "Y";
    [char]'к' = "k";[char]'К' = "K";
    [char]'л' = "l";[char]'Л' = "L";
    [char]'м' = "m";[char]'М' = "M";
    [char]'н' = "n";[char]'Н' = "N";
    [char]'о' = "o";[char]'О' = "O";
    [char]'п' = "p";[char]'П' = "P";
    [char]'р' = "r";[char]'Р' = "R";
    [char]'с' = "s";[char]'С' = "S";
    [char]'т' = "t";[char]'Т' = "T";
    [char]'у' = "u";[char]'У' = "U";
    [char]'ф' = "f";[char]'Ф' = "F";
    [char]'х' = "kh";[char]'Х' = "Kh";
    [char]'ц' = "ts";[char]'Ц' = "Ts";
    [char]'ч' = "ch";[char]'Ч' = "Ch";
    [char]'ш' = "sh";[char]'Ш' = "Sh";
    [char]'щ' = "sch";[char]'Щ' = "Sch";
    [char]'ъ' = "";[char]'Ъ' = "";
    [char]'ы' = "y";[char]'Ы' = "Y";
    [char]'ь' = "";[char]'Ь' = "";
    [char]'э' = "e";[char]'Э' = "E";
    [char]'ю' = "yu";[char]'Ю' = "Yu";
    [char]'я' = "ya";[char]'Я' = "Ya"
    }
    $outChars = ""
    $Result.Text = ""
    $inString = $InputName.Text +"."+ $InputSName.Text
    foreach ($c in $inChars = $inString.ToCharArray())
        {
        if ($Translit[$c] -cne $Null ) 
            {$outChars += $Translit[$c]}
        else
            {$outChars += $c}
        }
    $Result.Text = $outChars
 }
#
#
function SplitFName{
    $inStr = $InputFName.Text -split " "
    $InputSName.Text = $inStr[0]
    $InputName.Text = $inStr[1]
    $InputInitName.Text = $inStr[2]
    TranslitRU2LAT
}
#
function SetToClipboard{
    param($cltext)
    if($cltext){
    [Windows.Forms.Clipboard]::SetText($cltext);
    $Form.close()
     }
}
#
# Форма GUI
#    
$labFName = New-Object windows.Forms.Label 
$labFName.text = "Фамилия Имя Отчество полностью:"
$labFName.left = "8"
$labFName.top = "10"
$labFName.Width = "300"

$labSName = New-Object windows.Forms.Label 
$labSName.text = "Фамилия:"
$labSName.left = "8"
$labSName.top = "65"
$labSName.Width = "80"

$labName = New-Object windows.Forms.Label 
$labName.text = "Имя:"
$labName.left = "113"
$labName.top = "65"
$labName.Width = "80"

$labInitName = New-Object windows.Forms.Label 
$labInitName.text = "Отчество:"
$labInitName.left = "218"
$labInitName.top = "65"
$labInitName.Width = "80"

$InputFName = New-Object windows.Forms.TextBox
$InputFName.Left ="10"
$InputFName.Top = "34"
$InputFName.Width = "310"
$InputFName.add_TextChanged($Function:SplitFName)

$InputSName = New-Object windows.Forms.TextBox
$InputSName.Left ="10"
$InputSName.Top = "88"    
        
$InputName = New-Object windows.Forms.TextBox
$InputName.Left ="115"
$InputName.Top = "88"    

$InputInitName = New-Object windows.Forms.TextBox
$InputInitName.Left ="220"
$InputInitName.Top = "88"

$button1 = New-Object Windows.Forms.Button
$button1.Text="Транслитерация : Загранпаспорт (1997—2010)"
$button1.Left ="10"
$button1.Top = "120"
$button1.Width = "310"
$button1.add_click($Function:TranslitRU2LAT)

$Result = New-Object windows.Forms.TextBox 
$Result.Left= "10"
$Result.Top="154"
$Result.Width = "200"
$Result.Height = "200"
$Result.ReadOnly = "true"
$Result.Text = ""

$button2 = New-Object Windows.Forms.Button  
$button2.Text = "В буфер обмена" 
$button2.Left ="212"
$button2.Top = "153"
$button2.Width = "108" 
$button2.Height = "22" 
$button2.add_click({SetToClipboard $Result.Text})

$Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($PSHOME + "\powershell.exe")

$Form = New-Object Windows.Forms.Form
$Form.Height  = 220
$Form.Width = 350
$Form.Text = "Транслит ФИО для Email"
$Form.Icon = $Icon
$Form.AutoSize = $True
$Form.AutoSizeMode = "GrowOnly"
#$Form.StartPosition = "CenterScreen"
$Form.controls.add($labFName)
$Form.controls.add($labName)
$Form.controls.add($labInitName)
$Form.controls.add($labSName)
$Form.controls.add($inputFName)
$Form.controls.add($inputSName)
$Form.controls.add($inputName)
$Form.controls.add($inputInitName)
$Form.controls.add($button1)
$Form.controls.add($button2)
$Form.controls.add($Result)
$Form.Add_Shown({$Form.Activate()})
$Form.ShowDialog()

Однако при запуске скрипта из под обычного пользователя возможно будут появляться всевозможные предупреждения безопасности, типа того, что скрипт не подписан и т.п. Можно конечно изменять настройки безопасности PS, а можно пойти по другому пути – скомпилировать скрипт в исполняемое .net приложение. Для этого можно использовать разные инструменты, например можно использовать утилиту PowerGUI Script Editor (меню Tools > Compile Script)

image

При компиляции скрипта мы можем указать имя результирующего исполняемого файла, выбрать версию .Net Framework (3.5/4.0), выбрать иконку и запретить открытие консольного окна Powershell при запуске…

image

В результате компиляции мы получим два файла – сам исполняемый *.exe файл и его вспомогательный конфигурационный файл *.config

image

Если компилируемый скрипт может принимать входящие параметры, то судя по заметке Дмитрия Сотникова, скомпилированный исполняемый файл можно использовать в режиме передачи аргументов, например:

Generated.exe -Arguments -MyParam2 "Value2" -MyParam1 "Value1"

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

Если мы скачаем с Codeplex текущую версию скрипта v0.4.0.0 (03/09/2013), то при попытке использовать его с PowerShell 4, узнаем о том, что максимально поддерживаемая версия – 3. На свой страх и риск можем добавить поддержку PS4 внеся небольшую правку в ps2exe.ps1

Меняем фрагмент кода проверки версии…

$psversion = 0
if($PSVersionTable.PSVersion.Major - 3) {
    $psversion = 3
    write-host "You are using PowerShell 3.0."
}

на что-нибудь типа…

$psversion = 0
if($PSVersionTable.PSVersion.Major -ge 3) {
    $psversion = 3
    write-host "You are using PowerShell 3.0. or newer"
}

Попробуем выполнить компиляцию нашего исходного PS-скрипта (в консоли Powershell):

C:\Tools\PS2EXE-v0.4.0.0\ps2exe.ps1 -inputFile "C:\Tools\Scripts\TranslitRU2EN.ps1" -outputFile "C:\Tools\Scripts\TranslitRU2EN.exe" -sta -noconsole

Обратите внимание на то, что при компиляции используется ключ –sta (однопоточный режим - single thread apartment), так как в приведённом выше скрипте есть необходимость работы с буфером обмена Windows, а это имеет свои особенности. В результате такой компиляции также получается 2 файла (*.exe и *.config) и теперь наш скрипт полностью выглядит как самостоятельная утилита. 

image

Позже был найден ещё один вариант компиляции с помощью скрипта Make-PS1ExeWrapper, но до его испытания руки не добрались, так как меня вполне устроил результат работы скрипта PS2EXE

Всего комментариев: 9 Комментировать

  1. Eugene Leitan /

    Спасибо, Алексей за интересные и полезные примеры использования Powershell в качестве exe варианта.

    Для трансляции использую в QIP комбинацию клавиш CTRL+T.

  2. Михаил /

    Пользуюсь PuntoSwitcher для транслитерации, а за PowerShellGUI спасибо)

  3. Alexander /

    Нечто подобное у меня делается vbs скриптом,очень удобно для создания учеток в домене.

  4. Алексей Максимов / Автор записи

    Нашёл онлайн ресурс, на котором можно слепить форму с нужными контролами, для которой генерируется код:
    http://www.poshgui.com
    Всё что остается, добавить код логики работы контролов.

  5. Matyushin Alexander /

    Что-то не так с Верхним регистром - в логине все маленькие буквы. пробовал добавить .ToUpper() - не помогло. подскажите как поправить

    1. Алексей Максимов / Автор записи

      В каком ещё логине ? "Свистелка" вполне рабочая. Пользуюсь ей до сих пор :)

  6. Yaromax (@Yaromax) /

    Огромное спасибо, написал скрипт резервного копирования в облако, но в нём были открытым текстом учётные данные - теперь они спрятаны от любопытных глаз. Защита от перехвата данных в данном конкретном случае не понадобится :)

  7. Сергей /

    А как можно сделать несколько вариантов транслитерации для символов ? Например символ "и", встречается сочетание "ьи" или "ъи" то переводится в "yi", в остальных случаях в "i". Голову себе ломаю сижу, а сообразить не получается.

    1. Алексей Максимов / Автор записи

      "А как можно сделать "...переписать скрипт, расширив его логику.

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