Export-Application.ps1
function Export-Application { <# .Synopsis Exports a WPK script into an executable .Description Exports a WPK script into an executable. Embeds all needed scripts within the executable, an .Example # Creates an .exe at the current path that runs digitalclock.ps1 $clock = Get-Command $env:UserProfile\Documents\WindowsPowerShell\Modules\WPK\Examples\DigitalClock.ps1 $clock | Export-Application .Parameter Command The Command to turn into an application. The command should either be a function or an external script .Parameter Name The name of the .EXE to produce. By default, the name will be the command name with an .EXE extension instead of a .PS1 extension .Parameter ReferencedAssemblies Additional Assemblies to Reference when compilign. .Parameter OutputPath If set, will output the executable into this path. By default, executables are outputted to the current directory. .Parameter TopModule The top level module to import. By default, this is the module that is exporting Export-Application #> param( [Parameter(ValueFromPipeline=$true)] [Management.Automation.CommandInfo] $Command, [string] $Name, [Reflection.Assembly[]] $ReferencedAssemblies = @(), [String]$OutputPath, [switch]$DoNotEmbed, [string]$TopModule = $myInvocation.MyCommand.ModuleName ) process { $optimize = $true Set-StrictMode -Off if (-not $name) { $name = $command.Name if ($name -like "*.ps1") { $name = $name.Substring(0, $name.LastIndexOf(".")) } } $referencedAssemblies+= [PSObject].Assembly $referencedAssemblies+= [Windows.Window].Assembly $referencedAssemblies+= [System.Windows.Threading.DispatcherFrame].Assembly $referencedAssemblies+= [System.Windows.Media.Brush].Assembly if (-not $outputPath) { $outputPath = "$name.exe" } $initializeChunk = "" foreach ($r in $referencedAssemblies) { if ($r -notlike "*System.Management.Automation*") { $initializeChunk += " # [Reflection.Assembly]::LoadFrom('$($r.Location)') " } } if ($optimize) { $iss = [Management.Automation.Runspaces.InitialSessionState]::CreateDefault() $builtInCommandNames = $iss.Commands | Where-Object { $_.ImplementingType } | Select-Object -ExpandProperty Name $aliases = @{} $outputChunk = "" $command | Get-ReferencedCommand | ForEach-Object { if ($_ -is [Management.Automation.AliasInfo]) { $aliases.($_.Name) = $_.ResolvedCommand $_.ResolvedCommand } $_ } | Foreach-Object { if ($_ -is [Management.Automation.CmdletInfo]) { if ($builtInCommandNames -notcontains $_.Name) { $outputChunk+= " Import-Module '$($_.ImplementingType.Assembly.Location)' " } } $_ } | ForEach-Object { if ($_ -is [Management.Automation.FunctionInfo]) { $outputChunk += "function $($_.Name) { $($_.Definition) } " } } $outputChunk += $aliases.GetEnumerator() | ForEach-Object { " Set-Alias $($_.Key) $($_.Value) " } $initializeChunk += $outputChunk } else { $initializeChunk += " Import-Module '$topModule' " } if (-not $DoNotEmbed) { if ($command.ScriptContents) { $base64 = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($command.ScriptContents)) } else { if ($command.Definition) { $base64 = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($command.Definition)) } } $argsSection = @" sb.Append(System.Text.Encoding.Unicode.GetString(Convert.FromBase64String("$base64"))); "@ } else { $argsSection = @' if (args.Length == 2) { if (String.Compare(args[0],"-encoded", true) == 0) { sb.Append(System.Text.Encoding.Unicode.GetString(Convert.FromBase64String(args[1]))); } } else { foreach (string a in args) { sb.Append(a); sb.Append(" "); } } '@ } $initBase64 = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($initializeChunk)) $applicationDefinition = @" using System; using System.Text; using System.Management.Automation; using System.Management.Automation.Runspaces; public static class $name { public static void Main(string[] args) { StringBuilder sb = new StringBuilder(); $argsSection PowerShell psCmd = PowerShell.Create(); Runspace rs = RunspaceFactory.CreateRunspace(); rs.ApartmentState = System.Threading.ApartmentState.STA; rs.ThreadOptions = PSThreadOptions.ReuseThread; rs.Open(); psCmd.Runspace =rs; psCmd.AddScript(Encoding.Unicode.GetString(Convert.FromBase64String("$initBase64")), false).Invoke(); psCmd.Invoke(); psCmd.Commands.Clear(); psCmd.AddScript(sb.ToString()); try { psCmd.Invoke(); } catch (Exception ex) { System.Windows.MessageBox.Show(ex.Message, ex.GetType().FullName); rs.Close(); rs.Dispose(); } foreach (ErrorRecord err in psCmd.Streams.Error) { System.Windows.MessageBox.Show(err.ToString()); } rs.Close(); rs.Dispose(); } } "@ Write-Verbose $applicationDefinition Add-Type $applicationDefinition -IgnoreWarnings -ReferencedAssemblies $referencedAssemblies ` -OutputAssembly $outputPath -OutputType WindowsApplication } } |