-2

所以这是交易。由于许多......让我们说不是 PowerShell 聪明人,他们将使用我刚刚完成的极其复杂的应用程序,我需要能够将其打包在 exe 包装器中。

这不应该那么难

我能够成功使用PS2EXE,除了 AD 的某些原因之外,它会抛出一堆我无法摆脱的 AD 文本。试图解决这个问题几天,然后感到沮丧并继续前进。

然后,我发现PowerGUI. 我不能说我喜欢它。然而,它的编译器正是我想要的!除了 Exchange 2010 管理单元与.NET 4.5此应用程序不兼容之外。

我想非常清楚地表明我的脚本在多台不同的计算机上都能完美运行,但是一旦我使用这些工具中的任何一个,一切都会中断

一个 exe 是我能想到的最好的东西,它可以简化界面,并防止技术上智障人士破坏一切,或者因为每一个小错误都向我跑来,因为他们以某种方式进入了代码并输入了一些东西并保存了它,现在没有任何效果,这是世界末日,他们不知道发生了什么

如果你们知道任何将其包装成 exe 的工具,或者对如何提供帮助有任何其他想法,我将非常感谢你们能给我的任何东西。

你过去从来没有让我失望过!

4

2 回答 2

1

从我的角度来看,如果你真的想要一个 EXE 文件,你应该编写一个 .NET 应用程序,嵌入 PowerShell CmdLets 并不难。

为了避免最终用户修改您的代码,我知道两种解决方案:

首先:在用户计算机上设置执行策略AllSigned并签署您部署的脚本。您可以设法使用我们自己的证书(一点也不贵)或公共证书(更贵)。此解决方案的一个缺点是它不会阻止用户查看代码。另一个大缺点是 PKI 和签名代码基础设施会浪费大量时间。

第二:对于非交互式脚本(小心这是一种临时工作):

  1. 创建一个新的用户帐户
  2. 只允许访问新帐户的脚本文件。
  3. 在 Windows 调度程序中设置一个任务,以在该特定帐户下使用 PowerShell 运行该脚本文件。计划任务的权限允许对用户进行读取和执行访问。然后将任务设置为“禁用”。
  4. 每当需要运行脚本文件时,用户手动启动相应的任务。

使用此解决方案还可以让您远程执行脚本。

于 2015-11-24T04:54:55.313 回答
0

当我遇到类似的部署问题时 - 1)用户不知道 powershell 2)我不希望他们必须了解诸如执行策略之类的东西,3)如何启动 PS,4)等等。我将它打包成一批文件。我还想确保有经验的 PS 用户仍然具有 PS 的功能,因此批处理文件确定它是否在 PS 下运行,并在适用的情况下在当前 PS 会话中运行。我从不担心用户会弄乱脚本——如果它“正常工作”他们会很高兴。因此,无论用户喜欢 Explorer、CMD.EXE 还是 PS,它们都得到了满足。

我写的批处理文件首先运行了一些powershell代码来确定批处理文件的进程是否是powershell进程的孙子进程。如果是,则从 PS 调用批处理文件。还会检查执行策略,如果它足够宽松,则使用 Wscript.SendKeys 将击键发送到 PS 以使脚本在当前 PS 会话中运行。如果不是,则它使用 -ExecutionPolicy 参数启动一个新的 PS 会话并将脚本作为命令行参数 (-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. 否则,它被设置为定义一个“空”函数,然后调用空函数。null 不执行任何操作,因此不会输出作为函数参数的消息。

注意调用 SendKeys 时的转义。^ 是 CMD.EXE 转义字符,SendKeys 和 PS 一样有自己的转义机制。

如果从 PS 运行,由于 SendKeys,您最终会进入 PS 会话。否则批处理文件会这样做:

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 创建一个凭据以发送到您的脚本。

于 2015-11-24T20:15:50.660 回答