PowerShell 2.0 – PSCX Labs: Invoke-Reflector

by oising 5. May 2010 21:05

This is a lot of fun if you spend a lot of time tinkering around with APIs in PowerShell. This function (included in the upcoming PSCX 2.0, alias: refl) will let you open Lutz Roeder’s Reflector for any Type or Cmdlet. Reflector will automatically load the correct Assembly and will highlight the relevant Type, without you having to do diddley-squat. Examples and help will display with -?

function Invoke-Reflector {
<#
    .SYNOPSIS
        Quickly load Reflector, with the specified Type or Command selected.
    .DESCRIPTION
        Quickly load Reflector, with the specified Type or Command selected. The function will also
        ensure that Reflector has the Type or Command's containing Assembly loaded.
    .EXAMPLE
        # Opens System.String in Reflector. Will load its Assembly into Reflector if required.
        ps> [string] | invoke-reflector
    .EXAMPLE
        # Opens GetChildItemCommand in Reflector. Will load its Assembly into Reflector if required.
        ps> gcm ls | invoke-reflector
    .EXAMPLE
        # Opens GetChildItemCommand in Reflector. Will load its Assembly into Reflector if required.
        ps> invoke-reflector dir
    .PARAMETER CommandName
        Accepts name of command. Does not accept pipeline input.
    .PARAMETER CommandInfo
        Accepts output from Get-Command (gcm). Accepts pipeline input.
    .PARAMETER Type
        Accepts a System.Type (System.RuntimeType). Accepts pipeline input.
    .PARAMETER ReflectorPath
        Optional. Defaults to Reflector.exe's location if it is found in your $ENV:PATH. If not found, you must specify.
    .INPUTS
        [System.Type]
        [System.Management.Automation.CommandInfo]
    .OUTPUTS
        None
#>
     [cmdletbinding(defaultparametersetname="name")]
     param(
         [parameter(
            parametersetname="name",
            position=0,
            mandatory=$true
         )]
         [validatenotnullorempty()]
         [string]$CommandName,

         [parameter(
            parametersetname="command",
            position=0,
            valuefrompipeline=$true,
            mandatory=$true
         )]
         [validatenotnull()]
         [management.automation.commandinfo]$CommandInfo,

         [parameter(
            parametersetname="type",
            position=0,
            valuefrompipeline=$true,
            mandatory=$true
         )]
         [validatenotnull()]
         [type]$Type,

         [parameter(
            position=1
         )]
         [validatenotnullorempty()]
         [string]$ReflectorPath = $((gcm reflector.exe -ea 0).definition)
     )

        # no process block; i only want
        # a single reflector instance

        if ($ReflectorPath -and (test-path $reflectorpath)) {

            $typeName = $null
            $assemblyLocation = $null

            switch ($pscmdlet.parametersetname) {

                 { "name","command" -contains $_ } {

                    if ($CommandName) {
                        $CommandInfo = gcm $CommandName -ea 0
                    } else {
                        $CommandName = $CommandInfo.Name
                    }

                    if ($CommandInfo -is [management.automation.aliasinfo]) {

                        # expand aliases
                        while ($CommandInfo.CommandType -eq "Alias") {
                            $CommandInfo = gcm $CommandInfo.Definition
                        }
                    }

                    # can only reflect cmdlets, obviously.
                    if ($CommandInfo.CommandType -eq "Cmdlet") {

                        $typeName = $commandinfo.implementingtype.fullname
                        $assemblyLocation = $commandinfo.implementingtype.assembly.location

                    } elseif ($CommandInfo) {
                        write-warning "$CommandInfo is not a Cmdlet."
                    } else {
                        write-warning "Cmdlet $CommandName does not exist in current scope. Have you loaded its containing module or snap-in?"
                    }
                }

                "type" {
                    $typeName = $type.fullname
                    $assemblyLocation = $type.assembly.location
                }
            } # end switch


            if ($typeName -and $assemblyLocation) {
                & $reflectorPath /select:$typeName $assemblyLocation
            }

        } else {
            write-warning "Unable to find Reflector.exe. Please specify full path via -ReflectorPath."
        }
}

Have fun!

Tags:

.NET | Cmdlets | Developer | Functions | Monad | PowerShell | PowerShell 2.0 | PSCX

PowerShell 2.0 RC: Working with .NET Callbacks – Part 1 - Synchronous

by oising 18. July 2009 08:22

updated 2009/7/20: added link to PSEventing for v1.0 event handling
updated 2009/7/24: added link to Get-Delegate script for v1.0 callbacks

There have been some nice improvements made in the latest build of PowerShell with respect to interop with the "callback” pattern in .NET. What exactly are callbacks anyway? It’s exactly what it sounds like, pretty much. In .NET there are sometimes APIs you need to call that expect you to hand them delegates (pointers to methods) which that API will call some time in the future, usually based on certain conditions being fulfilled. If that sounds a bit like .NET events, you’d be right. An event is a much gussied-up callback - it’s just a way of permitting multiple methods to be invoked in response to some condition.

Synchronous Callbacks in PowerShell v1.0

In .NET there are two types of callbacks: Asynchronous (non-blocking) and synchronous (blocking). In PowerShell v1.0, the only callbacks that were catered for were for EventHandler Delegates. This is the method signature that most of the Windows Forms controls expect to call back to in response to button clicks etc. You may have seen code similar to:

$button = new-object system.windows.forms.button
$button.add_Click( { $form.Close() } )

This works because in PowerShell v1.0, there is specialized support for this kind of callback to methods with the EventHandler signature, that is to say, methods with parameters of (object sender, EventArgs e). PowerShell is able to run the ScriptBlock in response to the button being clicked and will even pass the two arguments to the scriptblock for you. When the form is shown from a PowerShell script, there is a single thread that is running the message loop for the application. It is this same thread that handles running the script. In the PowerShell engine, there is a pool of threads created at startup, and each of them has its own “Runspace” for running scripts. Because it is one of the PowerShell threads that is running the application, that same thread is able to run the ScriptBlocks in its Runspace when called upon to do so. Although it is in a slightly roundabout way, this is an example of a synchronous callback. This single application thread is effectively waiting (blocked) for the callback to occur in response to a button click (in reality, it’s doing other things while waiting, but it’s still waiting.)

Some rather creative folks, namely one of the primary developers of PowerShell, wrote a delegate/scriptblock binder in pure script some years ago which you can use to pass script to a .NET api to be called back to in a synchronous manner.  See: Creating arbitrary delegates to ScriptBlocks.

If you want to work with .NET events in version 1.0 of PowerShell, you’ll need an add-on, like my PSEventing Snap-In.

Synchronous Callbacks in PowerShell v2.0

In the latest and greatest version of PowerShell, v2.0 RC (which comes with the public Windows 7 RC), synchronous callbacks got a whole lot easier. PowerShell is now able to deal with pretty much ANY delegate signature, automatically. Lets test this by using the .NET 3.5 System.Func<T, TResult> delegate. This is a generic delegate which lets us pass a method to an API expecting a callback to a method which has one parameters of type T1, and will return type T2. Because it’s generic, we get to pick which parameters. Lets demo creating a ScriptBlock that will be passed a DateTime and returns a String:

add-type –assembly system.core # load .net 3.5
$callback = [system.func[datetime, string]] { param($date); "the date is $date" }
$callback.Invoke( [datetime]::now )
# returns
”the date is 2009/07/14 21:50:35”

We can even take advantage of PowerShell’s super-versatile parameter binder by passing it in a string and having it get coerced to DateTime with ne’er a Parse in sight!

$callback.Invoke(“1/1/2009”)
”the date is 2009/01/01 00:00:00”

So, what’s the point of all this? Why go to all that trouble? Why not just write a function? The point is that functions cannot be called by .NET directly. So when would you need a callback like this in a PowerShell script?

Calling Web Services with Invalid, Untrusted or Expired SSL Certificates

The title says it all – sometimes you need to do this. Usually it’s because you’re working with self-signed, expired or otherwise invalid certificates on a QA or Development system. The New-WebServiceProxy Cmdlet in v2.0 is great for calling Web Services, but it doesn’t have a switch to ignore invalid certificates. If you were writing .NET code in C# or VB.NET, the way go about this is to pass a callback method to an API that expects a RemoteCertificateValidationCallback Delegate. This delegate is designed to point to a method that is passed a handful of arguments describing the attempted connection, and is expected to return a boolean; that is to say, true or false. True means “sure, the connection looks fine – go for it.” A value of False being returned tells .NET to stop the connection before it happens.

The amount of .NET code needed to do this is not a ton, but it’s still a fair handful of lines. Check out this example here: http://blog.jameshiggs.com/2008/05/01/c-how-to-accept-an-invalid-ssl-certificate-programmatically/

Now let’s see how much PowerShell script is needed for this same task:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

Bwahahahah! Eat that, Mr. C# coder! Again, PowerShell’s binder comes into play here and automatically casts our ScriptBlock to a RemoteCertificateValidateCallback delegate (it’s not really a cast – there is no conversion – it’s a sizeable chunk of code.) From this point on, any attempts to use the New-WebServiceProxy Cmdlet with dodgy SSL certificates will succeed without so much as a warning. In fact, pretty much any other classes, like WebRequest will behave the same way. It’s important to note that this only affects the current AppDomain, that is to say, the current PowerShell process. Other processes on the system will continue to stick their nose up at dodgy SSL certs. Quit PowerShell and restart it -- or set that ServerCertificateValidationCallback property to $null -- and all is right in the world again. This works as long as you use one of PowerShell’s threads to do the work of connecting; i.e. don’t use an asynchronous request. This ensures there is a Runspace available to execute this ScriptBlock.

Converting Synchronous Callbacks into Events

This is really quite straightforward. Taking the previous example, we would generate an event inside the scriptblock using New-Event, and then bind one or more event handlers using the Register-EngineEvent Cmdlet:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {
		new-event -SourceIdentifier SslCheck -MessageData $args > $null
		$true
	}
# dump out arguments to cert validate callback
Register-EngineEvent -SourceIdentifier SslCheck -Action { write-output $args }
Next time, we'll get into some meatier stuff. Have fun!

In Part Two: Asynchronous Callbacks in PowerShell v1.0 and v2.0

Tags:

.NET | CTP3 | Eventing | Monad | PowerShell | PowerShell 2.0 | PSCX | RC | Windows 7

Pscx 1.2 Beta Released

by oising 15. May 2009 00:28

Hey, so we did the unthinkable. We released another version of the PowerShell Community Extensions. We’re calling it a beta, because we’ve be so swamped with Real Life stuff that we’re not 100% confident that it is defect-free. It’s not going to murder your servers or anything, but there might be some documentation missing and other minor stuff. We’d really appreciate it if you can give it a test-drive. If you’re running PowerShell v1.0 or v2.0 CTP3, please use the MSI installer. It will upgrade your Pscx 1.1.1 install if you have one. If, on the other hand, you are running Windows 7 RC and/or have a later version of PowerShell than v2 CTP3, you can download the zipped module and unzip to your user profile module directory at ~\documents\windowspowershell\modules\ and load it using “import-module pscx.”

Thanks for your infinite patience (yes, it’s been a while and we’re sorry) and please leave comments and issues on the tracker at http://pscx.codeplex.com/

View the 1.2 Beta release page.

Tags:

Cmdlets | CTP3 | Modules | Monad | PowerShell | PowerShell 2.0 | PSCX | SnapIns | Windows 7

Time For A Change

by oising 12. August 2008 14:03

It’s getting harder to post useful scripting tips for PowerShell these days as there are so many talented hardcore scripting bloggers around. My day to day is job is not system/network/server administrator; I’m a .NET developer, having started the C# habit about eight or nine years ago with the early CLR 1.0 beta. So, from here on in, I’ve decided that a better direction for me to take from now on is that of a PowerShell developer,  as opposed to a scripter. There are very few (if any?) dedicated PowerShell developer blogs around, and so I figured I should try to fill that gap as best I can. I have a not insignificant amount of experience writing providers, cmdlets and other widgety bits, so it’s a good time to share my experiences. Of course, my way is not “the” way, so please reply with your own experiences/advice/mocking/whatever. ;-)

That said, I am not eschewing scripting altogether – I have some stuff in the pipeline (har-har) concerning areas I’m interested in, like eventing and jobs/remoting.

Tags:

.NET | Cmdlets | Monad | PowerShell | Providers | PSCX | PSEventing | SharePoint | SnapIns

Pscx 1.2 progress &ndash; archive read and extract support coming

by oising 28. July 2008 09:28

In the latest PowerShellCX changeset, archive read and extract support is finally available. Sorry there are no binary builds yet. Use the Extract-Archive cmdlet as a stand-alone to extract all files. Use Read-Archive to generate ArchiveEntry objects which can be piped through Where-Object for filtering and eventual consumption by Extract-Archive (which can accept ArchiveEntry as well as FileInfo pipeline input). I’ve got progress reporting working too for extract. I’ve added support for reading/extracting SevenZip, Arj, BZip2, Cab, Chm, Cpio, Deb, GZip, Iso, Lzh, Lzma, Nsis, Rar, Rpm, Tar, Wim, Z & Zip.  Yes, you did see ISO support in that list ;-) Write support is only zip, bzip2, tar and gzip still.

There are more features coming, including encrypted archive support.

Tags:

.NET | CodePlex | Monad | PowerShell | PSCX

About the author

Oisin Grehan lives in Montreal, Canada and builds all sorts of crap for all sorts of people.

Month List

Page List