Write-Interface.ps1
function Write-Interface { <# .Synopsis Creates an interface implementation that is backed by a PSObject .Description Creates an interface implementation backed by a PSObject. All operations on the interface go straight to the PSObject, which lets you do two powerful things: - Implement interfaces in PowerShell - Test interfaces with a bad implementation, that does not implement certain overrides .Example Write-Interface -interface ([IDisposable]) .Link Add-Type #> param( # The type of an existing interface, for example, IDisposable [Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ParameterSetName="FromInterface")] [Type]$interface, # If set, compiles the interface [switch]$Compile) process { # If the FromObject parameter set is used, then quickly create a cache for the loaded types so that # we will not search through them each time. # Although all interfaces can be found with # [AppDomain]::CurrentDomain().GetAssemblies() | % { $_.GetTypes() } | ? { $_.IsInterface } # this operation will store them as a list. # As each interface is encountered, we will check a hashtable of the properties & methods of # each input object. When matches are encountered, the match will be added to a list of matching interfaces. # After all matches are cached, each type of switch ($psCmdlet.ParameterSetName) { FromObject { $loadedTypes = @{} } FromInterface { if (! $interface.IsInterface) { throw "Must provide an interface" } $requiredAssemblies = $interface.Assembly.Location, [object].Assembly.Location, [PSObject].Assembly.Location $ofs = "," $methodCode = "" foreach ($method in ($interface.GetMethods()) ) { $parameterList = $method.GetParameters() | % { "$_.Name" } $methodCode += @" public $method { return psObj.Methods.Item("$($method.Name)").Invoke($("$parameterList".Trim())); } "@ } $propertyCode = "" foreach ($property in $interface.GetProperties()) { $propertyCode+=@" public $property { $(if ($property.CanRead) { " get { return psObj.Properties.Item(`"$($property.Name)`").Value; }" }) $(if ($property.CanWrite) { " set { psObj.Properties.Item(`"$($property.Name)`").Value = value; }" }) } "@ } $implementationCode = @" using System; using $($interface.Namespace); using System.Management.Automation; public class PsObject$($interface.Name) : $($interface.Name){ public PsObject$($interface.Name) (PSObject object) { psObj = object} $methodCode $propertyCode $eventCode } "@ if ($Compile) { Write-Verbose "Compiling $implementationCode" Add-Type -TypeDefinition $implementationCode } else { $implementationCode } } } } } |