Skip to content

Instantly share code, notes, and snippets.

@sean-m
Last active May 31, 2018 20:05
Show Gist options
  • Save sean-m/21c1260f2c5c4add9df73c46fdf7bb8c to your computer and use it in GitHub Desktop.
Save sean-m/21c1260f2c5c4add9df73c46fdf7bb8c to your computer and use it in GitHub Desktop.
Helper function for wrapping DLL assembly in PowerShell so it can more easily be placed in version control and loaded within a script.
function GenAsmLoader {
<#
.Synopsis
Helper function for wrapping DLL assembly in PowerShell so it
can more easily be placed in version control and loaded within a script.
.DESCRIPTION
The ability to ship binary modules inside of a script file can be nice
if working in an environment that does not allow external dependencies.
This is a way around that by allowing you to bundle .Net DLL libraries inside
PowerShell code and providing a function that may be called to load the
library as an Assembly object with .Net's Reflection facilities.
.EXAMPLE
GenAsmLoader -AssemblyPath ".\NetNativeHelper.dll" -FunctionName "LoadNativeNetHelper" -Comment "Loads NetNativeHelper namespace." | Out-File LoadNativeHelper.ps1
#>
param (
[OutputType([string])]
[Parameter(Mandatory=$true, Position=0)]
$AssemblyPath,
[Parameter(Mandatory=$true, Position=1)]
$FunctionName,
[Parameter(Mandatory=$true, Position=2)]
$Comment,
[Parameter(Mandatory=$false, Position=3)]
[string]$MinDotNetVersion='4',
[Parameter(Mandatory=$false, Position=4)]
[string]$OutFile
)
process {
if (-not (Test-Path $AssemblyPath)) {
throw New-Object System.IO.FileNotFoundException "Cannot find: $AssemblyPath"
}
$base_code = @"
<#
{1}
#>
function {0} {{
begin {{
## Helper function for converting byte[] to Assembly object
if (-not ([System.Management.Automation.PSTypeName]'AsmHelper').Type) {{
Add-Type -Language CSharp -TypeDefinition @"
using System;
using System.Reflection;
public static class AsmHelper {{
public static Assembly LoadAsm(byte[] AsmBytes) {{
return Assembly.Load(AsmBytes);
}}
public static Assembly LoadAsm(string AsmString) {{
if (String.IsNullOrEmpty(AsmString)) {{ throw new System.Exception("Must pass assembly as Base64 encoded string."); }}
return LoadAsm(Convert.FromBase64String(AsmString));
}}
}}
`"@
}}
}}
process {{
if (-not (`$PSVersionTable.CLRVersion.Major -ge {4})) {{
throw "Need .Net {4} or greater"
}}
`$local:asm = "{2}"
`$local:asm_sha256 = "{3}"
if ([System.BitConverter]::ToString([System.Security.Cryptography.SHA256]::Create().ComputeHash([Convert]::FromBase64String(`$local:asm))) -replace "-","" -eq `$local:asm_sha256) {{
Import-Module -Assembly `$([AsmHelper]::LoadAsm(`$local:asm))
}}
else {{
throw "Could not load assembly! Checksum failed, byte string corrupt."
}}
}}
}}
"@
$asm_string = [Convert]::ToBase64String([System.IO.File]::ReadAllBytes($AssemblyPath))
$asm_hash = [System.BitConverter]::ToString([System.Security.Cryptography.SHA256]::Create().ComputeHash([Convert]::FromBase64String($asm_string))) -replace "-",""
$code = [String]::Format($base_code, $FunctionName, $Comment, $asm_string, $asm_hash, $MinDotNetVersion)
if (-not [String]::IsNullOrEmpty($OutFile)) {
try {
New-Item -Force -Type File -Path $OutFile
$code | Out-File -Encoding ascii -FilePath $OutFile
"Export-ModuleMember -Function $FunctionName" | Out-File -Append -Encoding ascii -FilePath $OutFile
}
catch {
throw $_ # this is just so if an exception is encountered, it abandons writing to the file all together
}
}
else {
return $code
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment