PowerShell: Oh Happy Days Are Here (Dynamically Compiling C# Code for Strongly Typed Objects within PowerShell)
Ever wanted to build native .NET objects to use while in a PowerShell script? Well I certainly have, and finally took the time to figure out how easy it is to actually do! Enjoy!
function Compile-Code { param ( [string[]] $code = $(throw "The parameter -code is required.") , [string[]] $references = @() , [switch] $asString = $false , [switch] $showOutput = $false , [switch] $csharp = $true , [switch] $vb = $false ) $options = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]"; $options.Add( "CompilerVersion", "v3.5") if ( $vb ) { $provider = New-Object Microsoft.VisualBasic.VBCodeProvider $options } else { $provider = New-Object Microsoft.CSharp.CSharpCodeProvider $options } $parameters = New-Object System.CodeDom.Compiler.CompilerParameters @( "mscorlib.dll", "System.dll", "System.Core.dll", "System.Xml.dll", ([System.Reflection.Assembly]::GetAssembly( [PSObject] ).Location) ) + $references | Sort -unique |% { $parameters.ReferencedAssemblies.Add( $_ ) } | Out-Null $parameters.GenerateExecutable = $false $parameters.GenerateInMemory = !$asString $parameters.CompilerOptions = "/optimize" if ( $asString ) { $parameters.OutputAssembly = [System.IO.Path]::GetTempFileName() } $results = $provider.CompileAssemblyFromSource( $parameters, $code ) if ( $results.Errors.Count -gt 0 ) { if ( $output ) { $results.Output |% { Write-Output $_ } } else { $results.Errors |% { Write-Error $_.ToString() } } } else { if ( $asString ) { $content = [System.IO.File]::ReadAllBytes( $parameters.OutputAssembly ) $content = [Convert]::ToBase64String( $content ) [System.IO.File]::Delete( $parameters.OutputAssembly ); return $content } else { return $results.CompiledAssembly } } }
Example usage:
Compile-Code -csharp -code @" using System; public class Foo { public Foo ( string message ) { Message = message; } public string Message { get; private set; } public void Bar() { Console.WriteLine( "Foo.Bar: {0}", Message ); } } "@ $foo = New-Object Foo "hello world" $foo.Bar()
Update: Added ability to compile C# or VB.NEt code and also to return the bytes for the compiled assembly for loading at a later time.