Reflection Module 4.1 by Joel Bennett 14 months ago (modification of post by Joel Bennett view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="/img/spacer.gif"> download | new post
Helpers for working with .Net classes: Get-Constructor, Get-Assembly, Add-Assembly, Get-Type
Now includes the New-ConstructorFunction (formerly in PowerBoots) which depends on the Autoload Module …
In this version I fixed a minor problem with PowerShell 3 CTP1
- #requires -version 2.0
- # ALSO REQUIRES Autoload for some functionality (Latest version: poshcode.org/3173)
- # You should create a Reflection.psd1 with the contents:
- # @{ ModuleToProcess="Reflection.psm1"; RequiredModules = @("Autoload"); GUID="64b5f609-970f-4e65-b02f-93ccf3e60cbb"; ModuleVersion="4.1.0.0" }
- #History:
- # 1.0 - First public release (March 19, 2010)
- # 2.0 - Private Build
- # - Included the Accelerator function inline
- # - Added a few default aliases
- # 3.0 - September 3, 2010
- # - Included the New-ConstructorFunction feature (ripped from PowerBoots to serve a more generic and powerful purpose!)
- # - New-ConstructorFunction and Import-ConstructorFunctions depend on the Autoload Module: poshcode.org/2312
- # 3.5 - January 28, 2011
- # - Fixed several bugs in Add-Assembly, Get-Assembly, Get-MemberSignature
- # - Fixed alias exporting so aliases will show up now
- # - Added New-ModuleManifestFromSnapin to create module manifests from snapin assemblies
- # 3.6 - January 28, 2011
- # - Added *basic* support for CustomPSSnapin to New-ModuleManifestFromSnapin
- # 3.7 - February 1, 2001 - NOT RELEASED
- # - Added [TransformAttribute] type
- # 3.8 - May 4, 2011 - NOT RELEASED
- # - Huge rewrite of Invoke-Generic (also published separately: poshcode.org/2649)
- # 3.9 - May 25, 2011 - NOT RELEASED
- # - Added "Interface" parameter to Get-Type
- # 4.0 - Sept 27, 2011
- # - Fix conflicts with PowerShell 3
- # 4.1 - Oct 27, 2011
- # - Fix PowerShell 3 changes so they don't break PowerShell 2 (huy!)
- Add-Type -TypeDefinition @"
- using System;
- using System.ComponentModel;
- using System.Management.Automation;
- using System.Collections.ObjectModel;
- [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
- public class TransformAttribute : ArgumentTransformationAttribute {
- private ScriptBlock _scriptblock;
- private string _noOutputMessage = "Transform Script had no output.";
- public override string ToString() {
- return string.Format("[Transform(Script='{{{0}}}')]", Script);
- }
- public override Object Transform( EngineIntrinsics engine, Object inputData) {
- try {
- Collection<PSObject> output =
- engine.InvokeCommand.InvokeScript( engine.SessionState, Script, inputData );
- if(output.Count > 1) {
- Object[] transformed = new Object[output.Count];
- for(int i =0; i < output.Count;i++) {
- transformed[i] = output[i].BaseObject;
- }
- return transformed;
- } else if(output.Count == 1) {
- return output[0].BaseObject;
- } else {
- throw new ArgumentTransformationMetadataException(NoOutputMessage);
- }
- } catch (ArgumentTransformationMetadataException) {
- throw;
- } catch (Exception e) {
- throw new ArgumentTransformationMetadataException(string.Format("Transform Script threw an exception ('{0}'). See `$Error[0].Exception.InnerException.InnerException for more details.",e.Message), e);
- }
- }
- public TransformAttribute() {
- this.Script = ScriptBlock.Create("{`$args}");
- }
- public TransformAttribute( ScriptBlock Script ) {
- this.Script = Script;
- }
- public ScriptBlock Script {
- get { return _scriptblock; }
- set { _scriptblock = value; }
- }
- public string NoOutputMessage {
- get { return _noOutputMessage; }
- set { _noOutputMessage = value; }
- }
- }
- "@
- function Get-Type {
- <#
- .Synopsis
- Gets the types that are currenty loaded in .NET, or gets information about a specific type
- .Description
- Gets information about one or more loaded types, or gets the possible values for an enumerated type or value.
- .Parameter Assembly
- The Assemblies to search for types.
- Can be an actual Assembly object or a regex to pass to Get-Assembly.
- .Parameter TypeName
- The type name(s) to search for (wildcard patterns allowed).
- .Parameter BaseType
- A Base type they should derive from (wildcard patterns allowed).
- .Parameter Interface
- An interface they should implement (wildcard patterns allowed).
- .Parameter Enum
- An enumeration to list all of enumeration values for
- .Parameter Namespace
- A namespace to restrict where we selsect types from (wildcard patterns allowed).
- .Parameter Force
- Causes Private types to be included
- .Example
- Get-Type
- Gets all loaded types (takes a VERY long time to print out)
- .Example
- Get-Type -Assembly ([PSObject].Assembly)
- Gets types from System.Management.Automation
- .Example
- [Threading.Thread]::CurrentThread.ApartmentState | Get-Type
- Gets all of the possible values for the ApartmentState property
- .Example
- [Threading.ApartmentState] | Get-Type
- Gets all of the possible values for an apartmentstate
- #>
- [CmdletBinding(DefaultParameterSetName="Assembly")]
- param(
- # The assembly to collect types from
- [Parameter(ValueFromPipeline=$true)]
- [PsObject[]]$Assembly
- ,
- # The type names to return from
- [Parameter(Mandatory=$false,Position=0)]
- [String[]]$TypeName
- ,
- # The type names to return from
- [Parameter(Mandatory=$false)]
- [String[]]$Namespace
- ,
- # A Base Type they should derive from
- [Parameter(Mandatory=$false)]
- [String[]]$BaseType
- ,
- # An Interface they should implement
- [Parameter(Mandatory=$false)]
- [String[]]$Interface
- ,
- # The enumerated value to get all of the possibilties of
- [Parameter(ParameterSetName="Enum")]
- [PSObject]$Enum
- ,
- [Parameter()][Alias("Private","ShowPrivate")]
- [Switch]$Force
- )
- process {
- if($psCmdlet.ParameterSetName -eq 'Enum') {
- if($Enum -is [Enum]) {
- [Enum]::GetValues($enum.GetType())
- } elseif($Enum -is [Type] -and $Enum.IsEnum) {
- [Enum]::GetValues($enum)
- } else {
- throw "Specified Enum is neither an enum value nor an enumerable type"
- }
- }
- else {
- if($Assembly -as [Reflection.Assembly[]]) {
- ## This is what we expected, move along
- } elseif($Assembly -as [String[]]) {
- $Assembly = Get-Assembly $Assembly
- } elseif(!$Assembly) {
- $Assembly = [AppDomain]::CurrentDomain.GetAssemblies()
- }
- :asm foreach ($asm in $assembly) {
- Write-Verbose "Testing Types from Assembly: $($asm.Location)"
- if ($asm) {
- trap {
- if( $_.Exception.LoaderExceptions[0] -is [System.IO.FileNotFoundException] ) {
- $PSCmdlet.WriteWarning( "Unable to load some types from $($asm.Location), required assemblies were not found. Use -Debug to see more detail")
- continue asm
- }
- Write-Error "Unable to load some types from $($asm.Location). Try with -Debug to see more detail"
- Write-Debug $( $_.Exception.LoaderExceptions | Out-String )
- continue asm
- }
- $asm.GetTypes() | Where {
- ( $Force -or $_.IsPublic ) -AND
- ( !$Namespace -or $( foreach($n in $Namespace) { $_.Namespace -like $n } ) ) -AND
- ( !$TypeName -or $( foreach($n in $TypeName) { $_.Name -like $n -or $_.FullName -like $n } ) -contains $True ) -AND
- ( !$BaseType -or $( foreach($n in $BaseType) { $_.BaseType -like $n } ) -contains $True ) -AND
- ( !$Interface -or @( foreach($n in $Interface) { $_.GetInterfaces() -like $n } ).Count -gt 0 )
- }
- }
- }
- }
- }
- }
- function Add-Assembly {
- #.Synopsis
- # Load assemblies
- #.Description
- # Load assemblies from a folder
- #.Parameter Path
- # Specifies a path to one or more locations. Wildcards are permitted. The default location is the current directory (.).
- #.Parameter Passthru
- # Returns System.Runtime objects that represent the types that were added. By default, this cmdlet does not generate any output.
- # Aliased to -Types
- #.Parameter Recurse
- # Gets the items in the specified locations and in all child items of the locations.
- #
- # Recurse works only when the path points to a container that has child items, such as C:\Windows or C:\Windows\*, and not when it points to items that do not have child items, such as C:\Windows\*.dll
- [CmdletBinding()]
- param(
- [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true, Position=0)]
- [Alias("PSPath")]
- [string[]]$Path = "."
- ,
- [Alias("Types")]
- [Switch]$Passthru
- ,
- [Switch]$Recurse
- )
- process {
- foreach($file in Get-ChildItem $Path -Filter *.dll -Recurse:$Recurse) {
- Add-Type -Path $file.FullName -Passthru:$Passthru | Where { $_.IsPublic }
- }
- }
- }
- function Get-Assembly {
- <#
- .Synopsis
- Get a list of assemblies available in the runspace
- .Description
- Returns AssemblyInfo for all the assemblies available in the current AppDomain, optionally filtered by partial name match
- .Parameter Name
- A regex to filter the returned assemblies. This is matched against the .FullName or Location (path) of the assembly.
- #>
- [CmdletBinding()]
- param(
- [Parameter(ValueFromPipeline=$true, Position=0)]
- [string[]]$Name = ''
- )
- process {
- [appdomain]::CurrentDomain.GetAssemblies() | Where {
- $Assembly = $_
- if($Name){
- $(
- foreach($n in $Name){
- if(Resolve-Path $n -ErrorAction 0) {
- $n = [Regex]::Escape( (Resolve-Path $n).Path )
- }
- $Assembly.FullName -match $n -or $Assembly.Location -match $n -or ($Assembly.Location -and (Split-Path $Assembly.Location) -match $n)
- }
- ) -contains $True
- } else { $true }
- }
- }
- }
- function Update-PSBoundParameters {