PowerShell是否编译脚本

本文关键字:脚本 编译 是否 PowerShell | 更新日期: 2023-09-27 18:26:17

假设我有一个简单的PowerShell脚本:

1..3 | Write-Host 
  • PowerShell如何处理它
  • 它是在内存程序集或某个临时.dll文件中生成的
  • 我可以使用一些工具(例如ILSpy、VS、WinDbg)检查此程序集和MSIL吗
  • PowerShell是否以相同的方式处理文件脚本和REPL命令行输入(即编译/解释)
  • 我可以将此已编译的程序集与C#和其他.Net语言一起使用吗
  • PS脚本是否可以编译为本地二进制代码

PowerShell是否编译脚本

PowerShell V2和早期版本从未编译过脚本,它总是通过解析树中的虚拟"eval"方法进行解释。

PowerShell V3和稍后将解析树(AST)编译为LINQ表达式树,然后将其编译为字节码,然后对其进行解释。

如果脚本执行了16次,则脚本将在后台进行JIT编译,一旦JIT编译完成,就不会使用解释的代码。这同样适用于循环:如果一个循环迭代16次,则循环体将被JIT编译,并且循环体将尽早从解释切换到JIT编译。

许多操作,如访问成员或调用C#方法,总是在小型动态方法中进行JIT编译。这些动态站点针对PowerShell的动态特性进行了优化,可根据需要适应不同类型的输入。

JIT编译的代码托管在"匿名方法"程序集中,无法保存。使用WinDbg,您可以反汇编生成的代码的IL。

将编译后的IL代码保存为DLL是不可能的,因为生成的代码依赖于活动对象。从技术上讲,PowerShell可以生成可以保存为DLL的代码,但尚未实现。

脚本和REPL(交互式命令提示符)的工作原理完全相同。

请注意,如果PowerShell确实生成了程序集,它仍然需要安装编译脚本的PowerShell版本,则无法生成完全可移植的exe。

从其他语言调用PowerShell脚本会有些困难和尴尬,因为有几个因素——主要是流水线和参数绑定-与正常的方法调度有些不同。

您可以在C#中使用从PowerShell脚本返回的对象。从V3开始,如果在C#中使用dynamic关键字,则可以访问PSObject实例上的属性、调用脚本方法等,就像访问任何其他对象一样。在V3之前,您必须使用像psobj.Properties['SomeProperty']这样的API。