18

Suppose I have a simple PowerShell script:

1..3 | Write-Host 
  • How does PowerShell process it?
  • Does it build in-memory assembly or some temporary .dll file?
  • Can I examine this assembly and MSIL using some tools (e.g. ILSpy, VS, WinDbg)?
  • Does PowerShell treat processing of file scripts and REPL command line input the same way (i.e. both compiled / interpreted)?
  • Can I use this compiled assembly together with C# and other .Net languages?
  • Can the PS script be compiled to a native binary code?
Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
user2341923
  • 4,537
  • 6
  • 30
  • 44
  • 3
    PowerShell is an interpreted language (yes V3 **internally caches** some generated IL). There are not such assemblies then you can't _use_ them together with other .NET languages but of course you can host PowerShell within your .NET app (also sharing something!). Other answers are then consequence of this. About examine that cached IL...well, of course inspecting PS code with ILSpy and using WinDbg you can do almost everything you want... – Adriano Repetti Dec 10 '15 at 13:03
  • 1
    If your goal is to deploy a PowerShell script as an executable you might want to have a look at this project: https://gallery.technet.microsoft.com/PS2EXE-Convert-PowerShell-9e4e07f1 – Dirk Vollmar Dec 10 '15 at 13:16

1 Answers1

36

PowerShell V2 and earlier never compiled a script, it was always interpreted via virtual "eval" methods in the parse tree.

PowerShell V3 and later compile the parse tree (the AST) to a LINQ expression tree, which is then compiled to a bytecode, which is then interpreted.

If the script is executed 16 times, the script is JIT-compiled in the background, and as soon as the JIT compilation completes, the interpreted code will not be used. The same applies to loops: if a loop iterates 16 times, the loop body will be JIT-compiled and the loop body will switch from interpreted to JIT-compiled at the earliest possible time.

Many operations like accessing a member or invoking a C# method are always JIT-compiled in small dynamic methods. These dynamic sites are optimized for the dynamic nature of PowerShell, adapting to differing kinds of input on demand.

The JIT-compiled code is hosted in the "anonymous methods" assembly and cannot be saved. With WinDbg, you could disassemble the IL of the generated code.

Saving the compiled IL code as a DLL is not quite possible, because the generated code depends on live objects. It is technically possible for PowerShell to generate code that could be saved as a DLL, but that is not implemented.

Scripts and the REPL (interactive command prompt) work exactly the same.

Note that if PowerShell did actually generate an assembly, it would still require the version of PowerShell that compiled the script to be installed, you could not produce a fully portable exe.

It would be somewhat difficult and awkward to call PowerShell scripts from other languages because several factors - primarily pipelining and parameter binding - differ somewhat from normal method dispatch.

You can use objects returned from PowerShell scripts in C#. Starting in V3, if you use the dynamic keyword in C#, you can access properties, call script methods, etc. on a PSObject instance, just like you would on any other object. Before V3, you had to use an API like psobj.Properties['SomeProperty'].

mklement0
  • 382,024
  • 64
  • 607
  • 775
Jason Shirk
  • 7,734
  • 2
  • 24
  • 29
  • 1
    Thanks for the great info, first time I read about this! Do you by any chance have a link to a doc about this feature ? – CJ Harmath Aug 17 '18 at 16:35
  • Sorry, this write up and the source code are on GirHub are about it. – Jason Shirk Aug 17 '18 at 17:15
  • 1
    I am guessing this is it: `if (LoopStatementCount < 300) { // Start compilation after 16 iterations of the loop. `EnterLoopInstruction = new EnterLoopInstruction(Loop, compiler.Locals, 16, compiler.Instructions.Count); `compiler.Instructions.Emit(EnterLoopInstruction); `} https://github.com/PowerShell/PowerShell/blob/4ee1973d976d66078fcffc54208accab0ec9d8c9/src/System.Management.Automation/engine/parser/Compiler.cs#L6116 – CJ Harmath Aug 17 '18 at 17:21
  • Yes for loops, there is similar code for functions. – Jason Shirk Aug 17 '18 at 17:29