当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 将PowerShell脚本编译为exe

作者:精品下载站 日期:2024-12-14 07:14:26 浏览:15 分类:玩电脑

将PowerShell脚本编译为exe


介绍

我被问到“如何将脚本转换为 exe 文件”这个问题的次数比我记得的还要多。我的答案一直是:
-“只需将 Windows PowerShell 托管在可执行文件中,然后运行您喜欢的任何代码。”

大多数害怕使用 C# 的人都忽略了我的建议,并使用某种工具来做到这一点,这并没有错(只要你从你信任的提供商那里选择一个工具,而不是从某个阴影网站上随机选择一个工具)互联网)。今天我将向您展示在 exe 文件中嵌入脚本是多么容易。

免责声明 在 exe 中嵌入脚本并不会使代码保密,从二进制文件中提取代码非常容易,这不是您所需要的技术应该用来隐藏您的代码或您不希望用户读取的任何其他内容(例如密码)!另外,我并不是说这是推荐的,甚至不是说这样做很好,我只是展示在您自己的应用程序中托管 Windows PowerShell 是多么容易,并且希望 C# 并不那么可怕。请将此视为一个 概念证明。

先决条件

在开始之前,我们需要一些软件。 Visual Studio 2017 Community 可以从 https://visualstudio.microsoft.com/ 下载,并且可以免费用于开源项目。对于任何其他用途,请参阅 Visual Studio Community 许可条款。在本示例中,我将使用 Visual Studio 2017 Enterprise,但它在社区版或专业版中看起来完全相同。安装时请确保选择对 C# 的支持,这样就一切顺利了。

创建一个新项目

现在,让我们开始吧!

启动 Visual Studio 后(一旦你习惯了它实际上一点也不可怕,跟着我,你就会看到)我们需要通过文件 -> 新建 -> 项目来创建一个新项目。在“Visual C#”下,您应该找到一个名为“Console App”的模板,选择该模板并填写文本框。我还让 Visual Studio 为我初始化一个 git 存储库,但我不需要为我的解决方案创建目录,因为该项目只有一个解决方案。

[玩转系统] 将PowerShell脚本编译为exe

接下来,我需要添加对 System.Management.Automation 的引用。 (听起来很熟悉?这就是 PowerShell 所在的地方!) 如果您像我一样是 Visual Studio 新手,您可能会使用默认布局,并且您会在右上角找到解决方案资源管理器。如果您发现它放错了地方,不用担心,只需转到“查看”->“解决方案资源管理器”,它就会弹出。在解决方案资源管理器中,右键单击“引用”并选择“管理 NuGet 包”。

[玩转系统] 将PowerShell脚本编译为exe

这就像 PowerShell Gallery 的 C# 版本,但适用于 DLL 文件。转到“浏览”选项卡,然后在搜索字段中输入“Microsoft.PowerShell.5.ReferenceAssemblies”,然后单击“安装”。同意许可协议等后,我们就可以关闭 NuGet 选项卡了。

[玩转系统] 将PowerShell脚本编译为exe

接下来,我们需要通过将此行添加到 Program.cs 的顶部来添加对命名空间的引用:

using System.Management.Automation;

现在让我们创建一个脚本文件,通过右键单击解决方案资源管理器中的 Project PS2exe,选择“添加”->“新建项目”来存储 PowerShell 代码。 在这个新窗口中,选择“文本文件”并将其命名为“Script.ps1”。现在打开 Script.ps1 并在其中放入一些 PowerShell 代码。我只想用一个简单的例子:

Get-Service -Name W32Time

在开始编码之前我们需要做的最后一件事是将 Script.ps1 添加为资源,这将使其在我们的可执行文件中可用。为此,我们右键单击 Project PS2exe,单击“属性”并选择“资源”。这应该告诉我们:

该项目不包含默认资源文件。单击此处创建一个。

因此,让我们单击“此处”,这将为我们提供一个类似表格的视图。顶部有一个名为“添加资源”的按钮。我们单击它并选择“添加现有文件”,这让我们可以浏览并选择新创建的 Script.ps1。按 Ctrl+S 保存属性并关闭选项卡。

写一些 C#

现在终于可以开始编码了!让我们打开 Program.cs 并开始吧! 现在它应该看起来像这样:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

namespace PS2exe
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Console.ReadKey();
}
}
}

让我们首先读取脚本文件的内容并将其放入字符串中。如果我们的脚本使用带有字节顺序标记 (BOM) 的 UTF8 进行编码,我们需要将其删除。我使用这两行来定义要修剪的字符,然后将整个脚本作为字符串读取:

var unwantedChars = new Char[] { '\uFEFF', '\B' };
var scriptString = Encoding.UTF8.GetString(Properties.Resources.Script).Trim(unwantedChars);

这是 PowerShell 中的 C# 版本,如下所示:

$unwantedChars = [char[]](0xFEFF, 0x200B)
$scriptString = ([System.Text.Encoding]::UTF8.GetString($Properties.Resources.Script)).Trim($unwantedChars)

很相似不是吗?

接下来我们需要启动一个 PowerShell 实例,这就是我们需要 System.Management.Automation 的目的。为了确保我们的 PowerShell 实例退出并正确收集垃圾,我们将使用称为 using 语句的东西。这将确保一旦我们超出了 using-block 的范围,dotnet 框架就知道可以从内存中清除我们的 PowerShell 实例,并且我们不会遇到文件锁和其他不良问题的问题。它看起来像这样:

using (PowerShell ps = PowerShell.Create())
{
    ps
        .AddScript(scriptString)
        .AddCommand("Out-String");

    var result = ps.Invoke();
    foreach (var line in result)
    {
        Console.WriteLine(line);
    }
}

在这里,我们创建一个 PowerShell 实例并将对该实例的引用存储在变量 ps 中。 然后我们调用 AddScript 方法将代码添加到管道中。之后直接调用 AddCommand 会将命令添加到管道中,类似于:

Invoke-Expression -Command $scriptString | Out-String

现在我们已经创建了一个管道,但还没有执行任何代码。要调用管道,我们只需调用方法 Invoke() 并将输出存储在变量 result 中。由于我们将脚本通过管道传输到 Out-String,我们知道我们只返回了字符串,并且可以安全地循环结果并将每一行写入控制台。

现在请注意,我们仅从此处的输出流获取输出(流的新手?请查看我关于流的帖子),任何错误、警告或详细消息都将被忽略。

现在我们完成了!您可以通过单击工具栏中的“运行”或按 F5 来测试您的解决方案。当您对结果感到满意时,您可以删除写着“Hello World”的两行并在退出之前等待用户输入。现在,通过按 F6 或使用菜单构建您的解决方案,您将在 .\bin\Debug\PS2exe.exe 中找到可执行文件。如果将构建配置更改为 Release,您将在 .\bin\Release\PS2exe.exe 中找到该文件。

现在您可以在任何运行 PowerShell 5 的系统上运行您的 exe 文件! 那不太难吧?如果您愿意,可以从 GitHub 下载我的项目,然后将 Script.ps1 的内容替换为您自己的代码。

谁知道呢,也许有一天您会意识到 C# 并不是那么不可能学习并尝试更多。

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯