Совет PowerShell для EXE инструмента

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

Это не должно быть так сложно

Я смог успешно использовать PS2EXE За исключением некоторых причин, связанных с AD, он выбрасывает целую кучу текста AD, от которого я не могу избавиться. Пытался исправить это в течение нескольких дней, прежде чем расстраиваться и двигаться дальше.

Затем я обнаружил PowerGUI, Я не могу сказать, что мне это нравится, вообще. Однако его компилятор был именно тем , что я искал! За исключением того факта, что оснастки Exchange 2010 не совместимы с .NET 4.5 через это приложение.

Я хочу пояснить, что мой сценарий отлично работает на нескольких разных компьютерах, но как только я использую любой из этих инструментов, все ломается.

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

Если вы, ребята, знаете о каких-либо инструментах, чтобы превратить это в exe, или у вас есть другие идеи о том, как помочь, я был бы очень признателен за все, что вы, ребята, можете дать мне.

Вы никогда не подводили меня в прошлом!

2 ответа

Решение

Когда у меня была похожая проблема с развертыванием - 1) пользователь не знал powershell 2) я не хотел, чтобы он понимал такие вещи, как политика выполнения, 3) как запустить PS, 4) и т. Д. Я обернул его в пакетном режиме файл. Я также хотел убедиться, что опытные пользователи PS по-прежнему имеют возможности PS, поэтому пакетный файл определил, работает ли он под PS или нет, и работал в текущем сеансе PS, если это применимо. Меня никогда не беспокоило, что пользователи будут связываться со сценарием - они были счастливы, если он "просто сработал" Итак, нравится ли пользователям Explorer, CMD.EXE или PS, все они были приняты.

Сначала написанный мной пакетный файл запускает немного кода powershell, чтобы определить, является ли процесс пакетного файла внуком процесса powershell. Если это так, то пакетный файл вызывается из PS. Политика выполнения также проверяется, и, если она достаточно мягкая, то Wscript.SendKeys используется для отправки нажатий клавиш на PS для запуска сценария в текущем сеансе PS. Если это не так, он запускает новый сеанс PS с использованием параметра -ExecutionPolicy и передает сценарий в качестве аргумента командной строки (-Command).

Этот фрагмент кода powershell сообщается обратно в файл.CMD с помощью кода возврата. Извините, это загадочно, но длина параметров командной строки ограничена. Вот код:

set scr=       $mp=[diagnostics.process]::getcurrentprocess().id
set scr=%scr%; $pp=([wmi]\"win32_process.handle='$mp'\").parentprocessid
set scr=%scr%; $gp=([wmi]\"win32_process.handle='$pp'\").parentprocessid
set scr=%scr%; $ep=[int][microsoft.powershell.executionpolicy](get-executionpolicy)
set scr=%scr%; try {$pnp=1-[int](([wmi]\"win32_process.handle='$gp'\").Name -eq \"powershell.exe\")
set scr=%scr%; } catch {$pnp=1}
set scr=%scr%; $ev = (8 * $pnp + $ep) -band 0xB; %wo% pp: $pp gp: $gp ev: $ev; if ($ev -le 1) {
set scr=%scr%    %wo% Launching within existing powershell session...`n;
set scr=%scr%    $w=new-object -com wscript.shell;$null=$w.appactivate($gp);

set scr=%scr%;   $w.sendkeys(\"^&{{}`$st =cat "%me%";`$sc=`$st -join [char]10 -split 'rem PS script';
set scr=%scr%     `$script:myArgs = `\" %*`\";`$sb=[scriptblock]::create{(} `$sc[3]{)};. `$sb{}}~\")
set scr=%scr%; }
set scr=%scr%; exit $ev
powershell -noprofile -Command %scr%

%wo% - разрешить отладку этого "сценария проверки". Если отладка включена, для%wo% установлено значение write-host, В противном случае устанавливается определение "нулевой" функции, а затем вызывается нулевая функция. Нуль ничего не делает, поэтому сообщение, являющееся аргументом функции, не выводится.

Обратите внимание на экранирование при вызове SendKeys. ^ является escape-символом CMD.EXE, а SendKeys имеет свой собственный escape-механизм, как и PS.

Если запустить из PS, вы в конечном итоге в сеансе PS благодаря SendKeys. В противном случае командный файл делает это:

set scr=       ren function:prompt prompto
set scr=%scr%; function prompt{ 'myApp: '+(prompto)}
set scr=%scr%; $st= (cat %me%) -join \"`n\";
set scr=%scr%; $sx=($st -split 'rem PS script')
set scr=%scr%; $sc=$sx[3]
set scr=%scr%; %wo% myArgs: $myArgs script length: $sc.length 
set scr=%scr%; ^&{$script:myArgs=\"%*\"; iex $sc}

title MyApp
rem Change the number of lines on the console if currently set to 25
for /f "tokens=2" %%i in ('mode con^|findstr Lines:') do if %%i LEQ 25 (mode con lines=50&color 5F)
powershell -noexit -noprofile -command "%scr%"

Этот "вспомогательный скрипт" также не может быть слишком длинным. Таким образом, вспомогательный скрипт читает исходный файл.CMD и затем разбивает его, используя строку "rem PS script". Эта строка будет как в этом вспомогательном скрипте, так и в командном файле (отделяя операторы командного файла от операторов PS). В моем случае строка также находится в комментариях к пакетному файлу, поэтому используется индекс 3.

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

Вместо того, чтобы просто использовать командную строку PS, ваш сценарий PS может создать свою собственную интерактивную среду (например, с помощью Read-Host). Однако я не хотел этого делать, потому что это помешало бы опытным пользователям PS использовать свои знания о PS. Например, если вашему сценарию требуется имя пользователя / пароль, опытный пользователь PS может использовать get-credential для создания учетных данных для отправки в ваш сценарий.

С моей точки зрения, если вы действительно хотите файл EXE, вы должны написать приложение.NET, не так сложно встроить PowerShell CmdLets.

Чтобы избежать модификации вашего кода конечным пользователем, я знаю два решения:

Первое: установите политику выполнения на AllSigned на компьютере пользователя и подпишите сценарии, которые вы развернете. Вы можете использовать наши собственные сертификаты (совсем не дорого) или публичные (дороже). Одним из недостатков этого решения является то, что оно не мешает пользователям видеть код. Еще один большой недостаток заключается в том, что инфраструктура PKI и кода для подписи требует много времени.

Второе: для неинтерактивных сценариев (будьте осторожны, это некая временная работа):

  1. Создать новую учетную запись пользователя
  2. Разрешить доступ к файлу сценария только для новой учетной записи.
  3. Настройте задачу в планировщике Windows для запуска этого файла сценария с PowerShell под этой конкретной учетной записью. Разрешения для запланированных задач позволяют читать и выполнять доступ для пользователя (ей). Затем установите задачу на "отключено".
  4. Всякий раз, когда необходимо запустить файл сценария, пользователь запускает соответствующую задачу вручную.

Использование этого решения также позволит вам удаленно выполнить ваш скрипт.

Другие вопросы по тегам