Signing unsigned assemblies in NuGet packages

I wrote a set of PowerShell cmdlets for signing unsigned assemblies with the SNK of your choice. Certain platforms (I'm looking at you, SharePoint) just work better with SN assemblies, but this constrains dependencies to NuGet packages that contain only signed assemblies.

Many people believe using strong names is more of a hindrance than a help (myself included,) but corporate policies often dictate their usage. My strong naming package makes it simple to sign assemblies, even without the source code. No more begging package authors to release signed packages, or fiddling with github repos.

If you sign 3rd party NuGet package assemblies, I suggest signing them in-situ, in their original locations, so you can continue to reference the package and so not risk missing out on updates. When you update a package, simply resign the assemblies and compile away.

To get started, open the NuGet PM console and type:

Install-Package Nivot.StrongNaming

You must have a solution open at this time. This package is not tied to any project; it just adds new commands to the PM console (documented below.)

Nivot.StrongNaming

  • v1.0.0 [2013/04/29]
    • Initial release.
  • v1.0.1 [2013/04/29]
    • Updated metadata.
  • v1.0.2 [2013/04/30]
    • Added license and project URL.
    • Added readme.MD

About

A set of PowerShell Cmdlets to facilitate signing of unsigned 3rd party assemblies with a key of your choice, to allow them to be referenced by strongly named projects.

A NuGet package is available at: https://nuget.org/packages/Nivot.StrongNaming

Syntax

All cmdlets accept pipeline input. The AssemblyFile parameter is aliased to PSPath, so it will bind to piped files.

  • Test-StrongName [-AssemblyFile] <string[]> [<CommonParameters>]

    Returns true if an assembly has a strong name.

  • Import-StrongNameKeyPair [-KeyFile] <string> [<CommonParameters>]

  • Import-StrongNameKeyPair [-KeyFile] <string> -Password <securestring> [<CommonParameters>]

    Imports a simple unprotected SNK or a password-protected PFX, returning a StrongNameKeyPair instance for consumption by Set-StrongName. If your PFX file has a blank password, you must provide a SecureString of the empty string "". SecureString instances are returned from the Read-Host cmdlet with the -AsSecureString parameter.

  • Set-StrongName [-AssemblyFile] <string[]> -KeyPair <StrongNameKeyPair> [-NoBackup] [-Passthru] [-Force] [-DelaySign] [-WhatIf] [-Confirm] [<CommonParameters>]

    Assigns a strong name identity to an assembly.

    The -KeyPair parameter accepts a System.Reflection.StrongNameKeyPair output from the Import-StrongNameKeyPair cmdlet., which accepts either simple unprotected SNK files or password-protected PFX files.

    The -NoBackup switch directs the cmdlet to skip creating a .bak file alongside the newly signed assembly.

    The -Passthru switch will output a FileInfo representing the newly signed assembly to the pipeline.

    The -DelaySign switch will create a delay-signed assembly from a public key only SNK (it can also create one if the SNK contains both private and public keys.) This is useful if you can't get access to the full private key at your company. This will allow you to compile against previously unsigned nuget packages at least.

    The -Force switch will allow you to overwrite an existing strong name on an assembly.

    NOTE: You may supply -WhatIf to see what would be done, without actually doing it.

  • Get-AssemblyName [-AssemblyFile] <string[]> [<CommonParameters>]

    Returns a System.Reflection.AssemblyName instance from any assembly file.

FAQ: How Do I?

Get the default package root folder

PM> $root = join-path (split-path $dte.solution.filename) packages

Load an unprotected snk

PM> $key = Import-StrongNameKeyPair -KeyFile .\folder\key.snk
PM> dir *.dll | Set-StrongName -KeyPair $key -Verbose

Load a password-protected PFX

PM> $key = Import-StrongNameKeyPair -KeyFile .\folder\key.pfx -Password (Read-Host -AsSecureString)
******

Sign some unsigned assemblies

PM> cd (join-path $root unsignedPackage)
PM> dir -rec *.dll | set-strongname -keypair $key -verbose

(Re)sign some assemblies forcefully

PM> dir -rec *.dll | set-strongname -keypair $key -force

Sign only unsigned assemblies

PM> dir -rec *.dll | where { -not (test-strongname $_) } | set-strongname -keypair $key -verbose

PowerShell– A Peek at the Poke Module

I wrote this a good long time ago now, but somehow I never bothered to blog it. I guess I thought it was a bit too specific to be of general interest to people, but my good friend and long time MVP Karl Prosser tells me otherwise. This is the Wiki page from bitbucket repository, the link for which you'll find at the foot of the page. Basically, it's a module that lets you "peek" at objects to view and manipulate their internals. That is to say, you can access non-public methods, fields and properties just like they were public. You can also create instances of non-public types easily. I originally wrote this to help me when debugging things and to explore PowerShell itself from the inside out, interactively. It turns out to be a pretty powerful tool. I hope you enjoy it.


Here you'll find examples of how to peek and poke objects using the Poke module.

Version History

  • 1.0.1 - Compatibility fixes for v3 beta / .net 4.5
  • 1.0 - Initial release
Examples
# peek at a Job instance using pipeline syntax
$job = start-job { 42 } | peek
$job | get-member

which results in the new extended output format for get-member:

   TypeName:
Pokeable.System.Management.Automation.PSRemotingJob#676f9716-c167-47c6-ab0d-4d8cedbbe44d

Name                            Modifier  MemberType Definition
----                            --------  ---------- ----------
Equals                          public    Method     bool Equals(System.Object obj)
GetHashCode                     public    Method     int GetHashCode()
GetType                         public    Method     type GetType()
CheckDisconnectedAndUpdateState private   Method*    void CheckDisconnectedAndUpdateState(System....
CommonInit                      private   Method*    void CommonInit(int throttleLimit, System.Co...
ConnectJob                      internal  Method*    void ConnectJob(guid runspaceInstanceId)
ConnectJobs                     internal  Method*    void ConnectJobs()
ConstructLocation               private   Method*    string ConstructLocation()
Dispose                         protected Method*    void Dispose(bool disposing)
FindDisconnectedChildJob        private   Method*    System.Management.Automation.PSRemotingChild...
GetAssociatedPowerShellObject   internal  Method*    powershell GetAssociatedPowerShellObject(gui...
GetJobsForComputer              internal  Method*    System.Collections.Generic.List[System.Manag...
GetJobsForOperation             internal  Method*    System.Collections.Generic.List[System.Manag...
GetJobsForRunspace              internal  Method*    System.Collections.Generic.List[System.Manag...
GetRunspaces                    internal  Method*    System.Collections.Generic.IEnumerable`1[[Sy...
HandleChildJobStateChanged      private   Method*    void HandleChildJobStateChanged(System.Objec...
HandleJobUnblocked              private   Method*    void HandleJobUnblocked(System.Object sender...
InternalStopJob                 internal  Method*    void InternalStopJob()
SetStatusMessage                private   Method*    void SetStatusMessage()
StopJob                         public    Method*    void StopJob()
SubmitAndWaitForConnect         private   Method*    void SubmitAndWaitForConnect(System.Collecti...
ToString                        public    Method*    string ToString()
__GetBaseObject                 -         Method*    System.Management.Automation.PSRemotingJob, ...
__GetModuleInfo                 -         Method*    psmoduleinfo __GetModuleInfo()
atleastOneChildJobFailed        private   Field*     bool atleastOneChildJobFailed
blockedChildJobsCount           private   Field*     int blockedChildJobsCount
CanDisconnect                   internal  Property*  bool CanDisconnect { get; set; }
disconnectedChildJobsCount      private   Field*     int disconnectedChildJobsCount
finishedChildJobsCount          private   Field*     int finishedChildJobsCount
HasMoreData                     public    Property*  bool HasMoreData { get; set; }
HideComputerName                internal  Property*  bool HideComputerName { get; set; }
isDisposed                      private   Field*     bool isDisposed
Location                        public    Property*  string Location { get; set; }
moreData                        private   Field*     bool moreData
StatusMessage                   public    Property*  string StatusMessage { get; set; }
throttleManager                 private   Field*     System.Management.Automation.Remoting.Thrott...
_stopIsCalled                   private   Field*     bool _stopIsCalled
_syncObject                     private   Field*     System.Object _syncObject

You can call methods, set fields and properties (if they have setters - it doesn't matter if they're private, protected or internal.)

You can proxy/peek Types as well as instances:

# proxy a public type by piping it
$type = [text.stringbuilder] | peek
   TypeName: Pokeable.System.RuntimeType#System.Text.StringBuilder

Name             Modifier MemberType Definition
----             -------- ---------- ----------
Equals           public   Method     bool Equals(System.Object obj)
GetHashCode      public   Method     int GetHashCode()
GetType          public   Method     type GetType()
FormatError      private  Method*    static void FormatError()
ThreadSafeCopy   private  Method*    static void ThreadSafeCopy(System.Char*, mscorlib, Version=4...
ToString         public   Method*    string ToString()
__CreateInstance -        Method*    .ctor (), .ctor (int capacity), .ctor (string value), .ctor ...
__GetBaseObject  -        Method*    type __GetBaseObject()
__GetModuleInfo  -        Method*    psmoduleinfo __GetModuleInfo()
CapacityField    private  Field*     string CapacityField
DefaultCapacity  internal Field*     int DefaultCapacity
MaxCapacityField private  Field*     string MaxCapacityField
MaxChunkSize     internal Field*     int MaxChunkSize
StringValueField private  Field*     string StringValueField
ThreadIDField    private  Field*     string ThreadIDField

Peeking at non-public types:

# nonpublic types can't be specified using type literal
# syntax, so in this case you should use the -name parameter
$type = peek -name MS.Internal.Xml.XPath.XPathParser

# nonpublic objects returned from methods, properties or fields
# are not "peeked" themselves, so you may need to peek the return value:
$manager = peek (start-job { 42 } | peek).throttlemanager
$manager.throttlelimit = 64 # bump throttle limit ;)

Of course, you can peek instances too:

$sb = new-object system.text.stringbuilder
$proxy = peek $sb
$proxy | gm
   TypeName: Pokeable.System.Text.StringBuilder#45f12364-1906-45b3-b48b-a77acd81e3f0

Name                                                     Modifier MemberType Definition
----                                                     -------- ---------- ----------
GetHashCode                                              public   Method     int GetHashCode()
GetType                                                  public   Method     type GetType()
Append                                                   public   Method*    System.Text.StringBu...
AppendFormat                                             public   Method*    System.Text.StringBu...
AppendHelper                                             private  Method*    void AppendHelper(st...
AppendLine                                               public   Method*    System.Text.StringBu...
Clear                                                    public   Method*    System.Text.StringBu...
CopyTo                                                   public   Method*    void CopyTo(int sour...
EnsureCapacity                                           public   Method*    int EnsureCapacity(i...
Equals                                                   public   Method*    bool Equals(System.T...
ExpandByABlock                                           private  Method*    void ExpandByABlock(...
FindChunkForByte                                         private  Method*    System.Text.StringBu...
FindChunkForIndex                                        private  Method*    System.Text.StringBu...
Insert                                                   public   Method*    System.Text.StringBu...
InternalCopy                                             internal Method*    void InternalCopy(Sy...
MakeRoom                                                 private  Method*    void MakeRoom(int in...
Next                                                     private  Method*    System.Text.StringBu...
Remove                                                   private  Method*    System.Text.StringBu...
Replace                                                  public   Method*    System.Text.StringBu...
ReplaceAllInChunk                                        private  Method*    void ReplaceAllInChu...
ReplaceBufferAnsiInternal                                internal Method*    void ReplaceBufferAn...
ReplaceBufferInternal                                    internal Method*    void ReplaceBufferIn...
ReplaceInPlaceAtChunk                                    private  Method*    void ReplaceInPlaceA...
StartsWith                                               private  Method*    bool StartsWith(Syst...
System.Runtime.Serialization.ISerializable.GetObjectData private  Method*    void System.Runtime....
ToString                                                 public   Method*    string ToString()
VerifyClassInvariant                                     private  Method*    void VerifyClassInva...
__GetBaseObject                                          -        Method*    System.Text.StringBu...
__GetModuleInfo                                          -        Method*    psmoduleinfo __GetMo...
Capacity                                                 public   Property*  int Capacity { get; ...
Chars                                                    public   Property*  char Chars { get; se...
Length                                                   public   Property*  int Length { get; se...
MaxCapacity                                              public   Property*  int MaxCapacity { ge...
m_ChunkChars                                             internal Field*     char[] m_ChunkChars
m_ChunkLength                                            internal Field*     int m_ChunkLength
m_ChunkOffset                                            internal Field*     int m_ChunkOffset
m_ChunkPrevious                                          internal Field*     System.Text.StringBu...
m_MaxCapacity                                            internal Field*     int m_MaxCapacity

Have fun!

View or download the Poke module from bitbucket.

The Bourne Again PowerShell (BAPS) AWKWARD Module

Update 2013/4/3: This is an April Fools post. I think I got a bit too subtle here despite best efforts to make this kind of ridiculous. Apparently being tagged “OMGPONIES” is not enough to give it away. Yes, the script actually works, but it’s more of a roundabout way to compare the “awkward” AWK syntax with the more readable, idiomatic PowerShell. Thanks for reading.

Sometimes PowerShell’s object pipeline just gets in the way. Often I find myself needing to pipe a few commands together and while I lay it out in my head, I am already unconsciously preparing the regular expressions I’ll need to convert the text to a structure required by the receiving command. Other times I am idly flicking through a well-thumbed and worn binder of common commands and their output on sheets of grid paper so I can figure out what columns I need to munge. Muscle memory is a hard beast to tame, so with that in mind, I started out designing a module that would let me scratch that regex itch, and also keep things kind of “PowerShelly.” It then dawned on me that I could probably extend this further into a full POSIX* compatibility layer, with the codename for this being WARD (Windows Adaptable Reusable Development). My first implementation for AWK/WARD looked a little like this:

function awk {
    $input
}

While that implementation works well for a surprising number of cases, there are others which are a little trickier, so I figured I'd add a little intelligence to the commands for some of the more common use cases for AWK. Some examples:

# count lines in a file
cat text.txt | awk 'END{print NR}'

# Add all fields in ALL lines and print the sum
#
# sheet is:
#
#    a, b, c, d
#    1, 2, 3, 4
#    1, 2, 3, 4
#    1, 2, 3, 4
cat sheet.txt | awk '{s=0; for (i=1; i<=NF; i++) s=s+$i; print s}'

# Print 25 "A" characters
awk 'BEGIN{while (a++<25) s=s "A"; print s}'

Here's the current source of the AWKWARD BAPS module:

function awk ($expression) {
    
    switch ($expression) {
        
        # count lines
        'END{print NR}' {
            $input | measure
        }

        # print the total number of fields ("words") in all lines
        '{ total = total + NF }; END {print total}' {
            $input | measure -word
        }

        # print the sums of the fields of every line
        '{s=0; for (i=1; i<=NF; i++) s=s+$i; print s}' {
            $input | convertfrom-csv | measure -sum * | select property, sum
        }

         # add all fields in ALL lines and print the sum
        '{for (i=1; i<=NF; i++) s=s+$i}; END{print s}' {
            $input | convertfrom-csv | measure -sum * | measure -sum sum
        }

         # create a string of a specific length (e.g., generate N spaces)
        ([regex]'BEGIN{while \(a\+\+<(\d+)\) s=s "(.+?)"; print s}') {
            $matches[2] * $matches[1]
        }
        
        # print first N lines of file (emulates behavior of "head")
        ([regex]'NR < (\d+)') {
            $input | select -first $matches[1]
        }

        # print the last 2 lines of a file
        '{y=x "\n" $0; x=$0};END{print y}' {
            $input | select -last 2    
        }

         # print the last line of a file
        'END{print}' {
            $input | select -last 1
        }

        # print the last N lines of a file (circular buffer)
        ([regex]'{a\[NR%(\d+)\]=\$0}END{for(i=NR+1;i<=NR+(?:\d+);i++)print a\[i%(?:\d+)\]}') {
            $input | select -last $matches[1]
        }

        # emit matching lines for regex
        { $_ -as [regex] } {
            $input | where { ($expression -as [regex]).ismatch($_) }
        }
        
        default {
            write-warning "unsupported expression"
            $input
        }
    }
}
}

If you want to play around with the module, you can autoinstall it by running the following one-liner:

iex (New-Object Net.WebClient).DownloadString(“http://bit.ly/e0Mw9w”)

Have fun!

Ensuring a PowerShell script will always run in a 64 bit shell

Someone on Jabbr earlier today was struggling a bit with a NuGet init.ps1 script while trying to work with the IIS module. They thought the NuGet Package Manager shell was 64 bit, but in fact it’s a 32 bit shell as Visual Studio is itself 32 bit and will remain that way for the foreseeable future. So, if I have a dependency on some 64 bit binary module, how can I ensure that the script will get run in the right environment? Well, here’s some “stub” script that you can put at the top of your ps1 file that will detect its environment and relaunch itself in a 64 bit shell, passing along any arguments that were given.

I’d suggest keeping your 64 bit scripts in a separate ps1 and calling them from init.ps1 to do the work. Because the script will be relaunched in a 64 bit shell, you won’t have access to the package manager console intrinsics like $DTE, nor can you pass any “live” objects to the essentially external script. Stick to strings and other primitives like [int] and [bool] etc.

# am I running in 32 bit shell?
if ($pshome -like "*syswow64*") {
    write-warning "Restarting script under 64 bit powershell"

    # relaunch this script under 64 bit shell
    # if you want powershell 2.0, add -version 2 *before* -file parameter
    & (join-path ($pshome -replace "syswow64", "sysnative") powershell.exe) -file `
        (join-path $psscriptroot $myinvocation.mycommand) @args

    # exit 32 bit script
    exit
}

# start of script for 64 bit powershell

write-warning "hello from $pshome"
write-warning "My original arguments $args"

Also available on poshcode: http://poshcode.com/3827

Disclaimer: I’ve tested this with PowerShell 3.0 only.

PowerShell - Convert a .NET Type’s static methods into a Module

Updated 2012/9/24: $type.Name -> $type.FullName (otherwise only types directly in System namespace are found... oops!)

Here’s something I just knocked up recently to have a nice and simple way to import groups of functions temporarily from a .NET Type as a module. When you’re done with them, you can unload at any time using Remove-Module. As the inline help mentions, you must pipe the output of this function into Import-Module to make the functions available. You have to be somewhat familiar with the methods you’re converting in order to know what order to pass parameters. Some are obvious in that they only take one argument (like Sin, Cos or Tan) but others you’ll have to double check yourself. It would have been nice to convert .NET parameters and overloads into parameter sets, but the differences between how PowerShell and the .NET compilers resolve ambiguities can be very different and would only work for mostly simple cases. Here’s how I like to quickly check method syntax:

PS C:\projects> [math]::Log

OverloadDefinitions
-------------------
static double Log(double d)
static double Log(double a, double newBase)

Here's the function itself ( also available on poshcode (updated) )

function ConvertTo-Module {
<#
    .SYNOPSIS
    Quickly convert a .NET type's static methods into functions

    .DESCRIPTION
    Quickly convert a .NET type's static methods into functions.
    
    This function returns a PSModuleInfo, so you should pipe its
    output to Import-Module to use the exported functions.

    .PARAMETER Type
    The type from which to import static methods. 

    .INPUTS
    System.String, System.Type

    .OUTPUTS
    PSModuleInfo

    .EXAMPLE
    ConvertTo-Module System.Math | Import-Module -Verbose

    .EXAMPLE
    [math] | ConvertTo-Module | Import-Module -Verbose

#>
    [outputtype([psmoduleinfo])]
    param(
        [parameter(
            position=0,
            valuefrompipeline=$true,
            mandatory=$true)]
        [validatenotnull()]
        [type]$Type
    )

    new-module {
        param($type)
         
        ($exports = $type.getmethods("static,public").Name | sort -uniq) | `
            % {
                $func = $_
                new-item "function:script:$($_)" `
                    -Value {
                        # look mom! no [scriptblock]::create!
                        ($type.FullName -as [type])::$func.invoke($args)

                    }.GetNewClosure() # capture the value of $func
            }
        export-modulemember -function $exports
    } -name $type.Name -ArgumentList $type
}

Have fun!

Emulating Bash / GNU Readline with PowerShell 3.0

Introducing PSReadline 1.0 (Beta)

This is a module that takes advantage of a new hook added to PowerShell 3.0 that allows you to completely take over the readline API. To do so, you must define a function like:

function PSConsoleHostReadline {
    [Console]::Readline()
}

The is an example of a very simple implementation. You may think it's enough, until you realise that there is absolutely zero line editing: The cursor keys don't work, no home/end, no tab completion, nothing! There's a lot more to do than just grabbing a line of text.

This module tries to emulate the Unix Bash/GNU Readline experience. Tab completion works by dumping out a long line of space-separated matches, and will only complete the current line up to the maximum amount of shared leading letters for all matches based on the current token.

Thankfully, you will also get Bash style tab completion for types, cmdlets, parameters and their values as the PSReadline module uses PowerShell 3.0's powerful and fast tab completion APIs.

This is a beta release, so expect a glitch or two. Currently all of the bindings are based on EMACS. The next release will let you define your own bindings. The EMACS bindings are documented below.

Have fun!
readline
Installation
=============

- Download ZIP file, unblock with unblock-file cmdlet.
- Extract to ~\documents\windowspowershell\modules\
  -- This should result in a PSReadline folder 

PS> Import-Module PSReadline

Known issues:
=============

- <esc> does not clear the current line
- does not use powershell history (so get-history returns nothing)
- doesn't support fancy prompt functions with newlines and/or those
  that use write-host; single line prompt function only

Credits
==============
- Miguel de Icaza (getline.cs)
  
  Thanks to his unending masochism & for donating 
  the guts of the Readline emulation, which was torn kicking &
  screaming from an old Mono REPL C# shell. Much massaging and 
  poking was needed for NT & PowerShell, but it works.

Common Bindings
=========================================
Home          Cursor Home
LeftArrow     Cursor Left
RightArrow    Cursor Right
UpArrow       History - Previous
DownArrow     History - Next
Enter         Done
Backspace     Backspace
Delete        Delete Character
Tab           Tab / Tab Complete

EMACS Bindings
=========================================
Ctrl+A        Home
Ctrl+E        End
Ctrl+B        Left
Ctrl+F        Right
Ctrl+P        History - Previous
Ctrl+N        History - Next
Ctrl+K        Kill to EOL
Ctrl+Y        Yank
Ctrl+D        Delete Character
Ctrl+L        Refresh
Ctrl+R        Reverse Search History

Alt+B         Word - Backwards
Alt+F         Word - Forwards
Alt+D         Word - Delete
Alt+BkSpc     Word - Delete Backwards

=========================================
Ctrl+Q        Quote
=========================================

PowerShell 3.0 - Scripting callbacks and Delegates in Managed APIs

A question came up on an MVP mailing list about passing delegates of .NET methods to managed APIs in PowerShell. I covered callbacks to script blocks in a previous post, but I've never covered anything on passing regular .NET methods to APIs so here's a function I wrote to easily create Action, Action<> or Func<> delegates for any given static or instance method. The syntax is pipeline friendly and very flexible. As methods may be overloaded, you must provide a means to select an overload for the delegate. This is done by either providing a specific delegate type you wish to create, or by passing an array of types that should be used to find a compatible overload. The latter technique is more flexible because you only need to provide compatible parameters; the explicit delegate technique needs an exact match for the overload. Here are some examples of the syntax:

# Gets a delegate for a matching overload with string,string parameters.
# It will actually return func<string,object,string> which is the correct 
# signature for invoking string.format with string,string.
$delegate = [string]::format | Get-Delegate string,string

# Gets a delegate for a matching overload with no parameters.
$delegate = [console]::beep | Get-Delegate @()

# Gets a delegate for a matching overload with @(int,int) parameters.
$delegate = [console]::beep | get-delegate int,int

# Gets a delegate for an explicit func[].
$delegate = [string]::format | Get-Delegate -Delegate 'func[string,object,string]'

# Gets a delegate for an explicit action[].
$delegate = [console]::writeline | Get-Delegate -Delegate 'action[int]'

# For a method with no overloads, we will choose the default method and 
# create a corresponding action, action[] or func[].
$delegate = [string]::isnullorempty | get-delegate 

# Gets a delegate to an instance method of a stringbuilder: Append(string)
$sb = new-object text.stringbuilder
$delegate = $sb.append | get-delegate string

Here is the function definition itself. It requires PowerShell 3.0 (in public beta right now) due to some new language features but in theory it could be modified to support PowerShell 2.0. It's also available on PoshCode.

#requires -version 3

function Get-Delegate {
<#
.SYNOPSIS
Create an action[] or func[] delegate for a psmethod reference.
.DESCRIPTION
Create an action[] or func[] delegate for a psmethod reference.
.PARAMETER Method
A PSMethod reference to create a delegate for. This parameter accepts pipeline input.
.PARAMETER ParameterType
An array of types to use for method overload resolution. If there are no overloaded methods
then this array will be ignored but a warning will be omitted if the desired parameters were
not compatible.
.PARAMETER DelegateType
The delegate to create for the corresponding method. Example: [string]::format | get-delegate -delegatetype func[int,string]
.INPUTS System.Management.Automation.PSMethod, System.Type[]
.EXAMPLE
$delegate = [string]::format | Get-Delegate string,string

Gets a delegate for a matching overload with string,string parameters.
It will actually return func which is the correct 
signature for invoking string.format with string,string.
.EXAMPLE
$delegate = [console]::beep | Get-Delegate @()

Gets a delegate for a matching overload with no parameters.
.EXAMPLE
$delegate = [console]::beep | get-delegate int,int

Gets a delegate for a matching overload with @(int,int) parameters.
.EXAMPLE
$delegate = [string]::format | Get-Delegate -Delegate 'func[string,object,string]'

Gets a delegate for an explicit func[].
.EXAMPLE
$delegate = [console]::writeline | Get-Delegate -Delegate 'action[int]'

Gets a delegate for an explicit action[].
.EXAMPLE
$delegate = [string]::isnullorempty | get-delegate 

For a method with no overloads, we will choose the default method and create a corresponding action/action[] or func[].
#>
    [CmdletBinding(DefaultParameterSetName="FromParameterType")]
    [outputtype('System.Action','System.Action[]','System.Func[]')]
    param(
        [parameter(mandatory=$true, valuefrompipeline=$true)]
        [system.management.automation.psmethod]$Method,

        [parameter(position=0, valuefromremainingarguments=$true, parametersetname="FromParameterType")]
        [validatenotnull()]
        [allowemptycollection()]
        [Alias("types")]
        [type[]]$ParameterType = @(),

        [parameter(mandatory=$true, parametersetname="FromDelegate")]
        [validatenotnull()]
        [validatescript({ ([delegate].isassignablefrom($_)) })]
        [type]$DelegateType
    )

    $base = $method.GetType().GetField("baseObject","nonpublic,instance").GetValue($method)    
    
    if ($base -is [type]) {
        [type]$baseType = $base
        [reflection.bindingflags]$flags = "Public,Static"
    } else {
        [type]$baseType = $base.GetType()
        [reflection.bindingflags]$flags = "Public,Instance"
    }

    if ($pscmdlet.ParameterSetName -eq "FromDelegate") {
        write-verbose "Inferring from delegate."

        if ($DelegateType -eq [action]) {
            # void action        
            $ParameterType = [type[]]@()
        
        } elseif ($DelegateType.IsGenericType) {
            # get type name
            $name = $DelegateType.Name

            # is it [action[]] ?
            if ($name.StartsWith("Action``")) {
    
                $ParameterType = @($DelegateType.GetGenericArguments())    
            
            } elseif ($name.StartsWith("Func``")) {
    
                # it's a [func[]]
                $ParameterType = @($DelegateType.GetGenericArguments())
                $ParameterType = $ParameterType[0..$($ParameterType.length - 2)] # trim last element (TReturn)
            } else {
                throw "Unsupported delegate type: Use Action<> or Func<>."
            }
        }
    }

    [reflection.methodinfo]$methodInfo = $null

    if ($Method.OverloadDefinitions.Count -gt 1) {
        # find best match overload
        write-verbose "$($method.name) has multiple overloads; finding best match."

        $finder = [type].getmethod("GetMethodImpl", [reflection.bindingflags]"NonPublic,Instance")

        write-verbose "base is $($base.gettype())"

        $methodInfo = $finder.invoke(
            $baseType,
             @(
                  $method.Name,
                  $flags,
                  $null,
                  $null,
                  [type[]]$ParameterType,
                  $null
             )
        ) # end invoke
    } else {
        # method not overloaded
        Write-Verbose "$($method.name) is not overloaded."
        if ($base -is [type]) {
            $methodInfo = $base.getmethod($method.name, $flags)
        } else {
            $methodInfo = $base.gettype().GetMethod($method.name, $flags)
        }

        # if parametertype is $null, fill it out; if it's not $null,
        # override it to correct it if needed, and warn user.
        if ($pscmdlet.ParameterSetName -eq "FromParameterType") {           
            if ($ParameterType -and ((compare-object $parametertype $methodinfo.GetParameters().parametertype))) {
                write-warning "Method not overloaded: Ignoring provided parameter type(s)."
            }
            $ParameterType = $methodInfo.GetParameters().parametertype
            write-verbose ("Set default parameters to: {0}" -f ($ParameterType -join ","))
        }
    }

    if (-not $methodInfo) {
        write-warning "Could not find matching signature for $($method.Name) with $($parametertype.count) parameter(s)."
    } else {
        
        write-verbose "MethodInfo: $methodInfo"

        # it's important here to use the actual MethodInfo's parameter types,
        # not the desired types ($parametertype) because they may not match,
        # e.g. asked for method(int) but match is method(object).

        if ($pscmdlet.ParameterSetName -eq "FromParameterType") {            
            
            if ($methodInfo.GetParameters().count -gt 0) {
                $ParameterType = $methodInfo.GetParameters().ParameterType
            }
            
            # need to create corresponding [action[]] or [func[]]
            if ($methodInfo.ReturnType -eq [void]) {
                if ($ParameterType.Length -eq 0) {
                    $DelegateType = [action]
                } else {
                    # action<...>
                    
                    # replace desired with matching overload parameter types
                    #$ParameterType = $methodInfo.GetParameters().ParameterType
                    $DelegateType = ("action[{0}]" -f ($ParameterType -join ",")) -as [type]
                }
            } else {
                # func<...>

                # replace desired with matching overload parameter types
                #$ParameterType = $methodInfo.GetParameters().ParameterType
                $DelegateType = ("func[{0}]" -f (($ParameterType + $methodInfo.ReturnType) -join ",")) -as [type]
            }                        
        }
        Write-Verbose $DelegateType

        if ($flags -band [reflection.bindingflags]::Instance) {
            $methodInfo.createdelegate($DelegateType, $base)
        } else {
            $methodInfo.createdelegate($DelegateType)
        }
    }
}

Here are some tests to demonstrate the various cases covered. They were pretty much essential while I was tweaking the script.

# general test function
function Assert-True {
    param(
        [parameter(position=0, mandatory=$true)]
        [validatenotnull()]
        [scriptblock]$Script,

        [parameter(position=1)]
        [validatenotnullorempty()]
        [string]$Name = "Assert-True"
    )    
    $eap = $ErrorActionPreference
    Write-Host -NoNewline "Assert-True [ $Name ] "
    try {
        $erroractionpreference = "stop"
        if ((& $script) -eq $true) {
            write-host -ForegroundColor Green "[PASS]"
            return
        }
        $reason = "Assert failed."
    }
    catch {
        $reason = "Error: $_"
    }
    finally {
        $ErrorActionPreference = $eap
    }
    write-host -ForegroundColor Red "[FAIL] " -NoNewline
    write-host "Reason: '$reason'"
}

#
# static methods
#

assert-true {
    $delegate = [string]::format | Get-Delegate -Delegate 'func[string,object,string]'
    $delegate.invoke("hello, {0}", "world") -eq "hello, world"
} -name "[string]::format | get-delegate -delegate 'func[string,object,string]'"

assert-true {
    $delegate = [console]::writeline | Get-Delegate -Delegate 'action[int]'
    $delegate -is [action[int]]
} -name "[console]::writeline | get-delegate -delegate 'action[int]'"

assert-true {
    $delegate = [string]::format | Get-Delegate string,string
    $delegate.invoke("hello, {0}", "world") -eq "hello, world"
} -name "[string]::format | get-delegate string,string"

assert-true {
    $delegate = [console]::beep | Get-Delegate @()
    $delegate -is [action]
} -name "[console]::beep | get-delegate @()"

assert-true {
    $delegate = [console]::beep | Get-Delegate -DelegateType action
    $delegate -is [action]
} -name "[console]::beep | Get-Delegate -DelegateType action"

assert-true {
    $delegate = [string]::IsNullOrEmpty | get-delegate
    $delegate -is [func[string,bool]]
} -name "[string]::IsNullOrEmpty | get-delegate # single overload"

assert-true {
    $delegate = [string]::IsNullOrEmpty | get-delegate string
    $delegate -is [func[string,bool]]
} -name "[string]::IsNullOrEmpty | get-delegate string # single overload"

#
# instance methods
#

assert-true {
    $sb = new-object text.stringbuilder
    $delegate = $sb.Append | get-delegate string
    $delegate -is [System.Func[string,System.Text.StringBuilder]]
} -name "`$sb.Append | get-delegate string"

assert-true {
    $sb = new-object text.stringbuilder
    $delegate = $sb.AppendFormat | get-delegate string, int, int
    $delegate -is [System.Func[string,object,object,System.Text.StringBuilder]]
} -name "`$sb.AppendFormat | get-delegate string, int, int"

PowerShell 3.0–Now with Property Unrolling!

There are many new improvements to the language and parser in v3 (some of which I hope to cover over the next few posts) but one of my favourites is what Microsoft are calling singleton/array enumeration (or something equally obtuse.) I am hereby christening it “Property Unrolling” as it works similarly to how PowerShell does automatic collection unrolling when piping an enumerable (list, collection, array.)

This powershell 3.0 technique is where you can take a variable that contains an array (or collection, list or anything else that is enumerable) like $myarray and if you want to access a property on each element in that array, you no longer need to use foreach-object with $_.propertyName to access it. Instead, you can simply type $myarray.propertyName and powershell will return that property from each element in the array, but only if the array itself does not have that property. For example if you had an array of strings, asking for $arr.length would return the length of the array, and not the length of each string. The best way to show this is with some examples:

Array of files

# the older way (still works)
dir | foreach-object { $_.lastwritetime } | sort

# now, here's the shortcut way for v3
(dir).lastwritetime | sort

XML

Here's an example on how working with XML just got ten times easier. Here's some XML:

    
                     
             42
        
                     
             43
        
                     
             44
        
    

Here's a script that dumps the prop value in each element:

# the older way
$xml = [xml]" ... "
$xml.root.element | foreach-object { $_.prop }

# the v3 way ;)
$xml.root.element.prop

This is such a time saver. Thank you Microsoft!

Bypassing Restricted Execution Policy in Code or in Script

Many businesses are averse to moving away from a restricted execution policy because they don't really understand it. As Microsoft will tell you, It's not a security boundary - it's just an extra hoop to jump through so you don't shoot yourself in the foot by running something you shouldn’t. If you want to run ps1 scripts in your own application, simply host your own Runspace and use the base authorization manager which pays no heed to system execution policy, even if it’s controlled by group policy and immune to powershell –bypass and set-executiopolicy:

Bypassing in Code

InitialSessionState initial = InitialSessionState.CreateDefault(); 
 
// Replace PSAuthorizationManager with a null manager
// which ignores execution policy 
initial.AuthorizationManager = new 
      System.Management.Automation.AuthorizationManager("MyShellId"); 
 
// Extract psm1 from resource, save locally 
// ... 
 
// load my extracted module with my commands 
initial.ImportPSModule(new[] { <path_to_psm1> }); 
 
// open runspace 
Runspace runspace = RunspaceFactory.CreateRunspace(initial); 
runspace.Open(); 
 
RunspaceInvoke invoker = new RunspaceInvoke(runspace); 
 
// execute a command from my module 
Collection<PSObject> results = invoker.Invoke("my-command"); 
 
// or run a ps1 script     
Collection<PSObject> results = invoker.Invoke(@"c:\program files\myapp\my.ps1");

By using this null authorization manager, execution policy is completed ignored. Remember - this is not some "hack" because execution policy is something for protecting users against themselves. It's not for protecting against malicious third parties, like some kind of script firewall. Whatever could be put in a script, could be run by hand in a dozen different ways using invoke-expression, and even file based scripts can be executed this way: invoke-expression (get-content .\foo.ps1).

Bypassing in Script

Now this is a little more hackish because it involves manipulating powershell.exe internals at runtime. This is a useful one-liner (if you can memorise it) when you find yourself in one of those clients who has GPO controlled execution policy. It’s pushing it for a one-liner, I know, but hey:

function Disable-ExecutionPolicy {
    ($ctx = $executioncontext.gettype().getfield(
        "_context","nonpublic,instance").getvalue(
            $executioncontext)).gettype().getfield(
                "_authorizationManager","nonpublic,instance").setvalue(
        $ctx, (new-object System.Management.Automation.AuthorizationManager
                  "Microsoft.PowerShell"))
}

This function will swap out the powershell host’s AuthorizationManager implementation (PSAuthorizationManager) with the null, policy-ignoring version. Execution policy will be effectively unrestricted, regardless of enterprise, machine or user level attempts to set it to restricted. This is an in-memory bypass only – when powershell.exe is closed and restarted, it’s back to business (or lack thereof.)

Have fun!

PowerShell – Module Installation Best Practices

I’m seeing a few errant companies have their installers throw their modules into ${env:systemroot}\WindowsPowerShell\1.0\Modules but this is not the right place. The only things that should go there are core operating system modules from Microsoft. So, where should you install them?

How to: Install a module for all users

  1. Create the folder ${env:programfiles}\YourProduct\PowerShell\Modules\
  2. Place your module (or modules) under this folder
  3. Add the folder from step 1 to the system scoped environment variable PSModulePath; consider embedding %ProgramFiles% to keep the environment string as short as possible
  4. Profit.

How to: Install a module for the current user

  1. Test for, and create if necessary the folder which is the result of this call (or equivalent in managed code): join-path ([environment]::GetFolderPath("MyDocuments")) WindowsPowerShell\Modules
  2. Copy your module or (modules) to folder at above
  3. Profit.

It’s as easy as that.

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List