Guest Spot on Hey, Scripting Guy Talking PowerShell and USN Change Journal

Starting today and ending Wednesday, I will be guest blogging on the Hey, Scripting Guy! blog talking about working with the USN Change Journal using PowerShell. Be sure to check it out and leave your comments with any questions!

Connect to USN Change Journal

View Entries in USN Change Journal

Use PoshUSNJournal Module to Work with Change Journal

Posted in powershell | Tagged , , , , | Leave a comment

Invoking Private Static Methods Using PowerShell

Usually if I want to accomplish a task in PowerShell, I can count on either a cmdlet or a publicly available .Net method to come to my rescue. Sometimes though, a method that I would like to use is just seemingly not available. Fortunately on occasion I can find a method that does what I need (or at least sets me up to accomplish my goal a little easier) using a private (or hidden) static method.

An example of needing such a method was when I decided to incorporate the $Using: variable scope in my PoshRSJob module. I had to open up and dive into PowerShell using DotPeek to see the internal workings of Start-Job to see that there were some calls to a method which I could not see just by piping the object into Get-Member and viewing the methods. Instead, we have to take the object and dive into the guts of it to view some methods and also enlist the help of some reflection binding flags to actually uncover the method that we need.

I won’t actually go into this approach as it won’t really provide a good ‘real world’ use. Instead I will take a look at the [Array] type and we will uncover some private methods and use one to see what happens.

Lets take a look at the static methods on [Array] and see what we have:

[Array] | Get-Member –Type Method –Static

image

You might be wondering why I used the –Static switch instead of looking at just the Methods. This is because I only wanted to display the methods that would actually be associated with working with the Array in this case. Had I not done that, then we would be seeing methods associated with the System.RuntimeType object.

What isn’t shown here is a method within Array called GetMedian, which as you can tell, should help to tell you the middle item in an array. Also note that it isn’t even mentioned on the MSDN site for Array. Why would you need this? Well, there is always someone somewhere that might need this type of thing.

With that, we need to figure out how we can find this method. Looking at the methods for the System.RunTimeType object of Array, we can find two methods that stick out: GetMethod() and GetMethods(). Calling GetMethods() will spit out all of the methods of Array while GetMethod() is geared towards a particular method.

image

Taking a deeper look at the method overloads, we can see that there are more than a few overloads that we could use for each of these methods.

image

In this example, I just want to see all methods (just the names) for Array.

[Array].GetMethods().Name | Group | Select Count, Name

image

You can see the same static methods that we observed earlier, plus multiple methods with the same name. Let’s say that we wanted to look at a single method. We would just list the name of the method in GetMethod and then we can view more information about it.

[Array].GetMethod(‘Clear’)

image

Calling GetParameters() from this method will show us all of the parameters required for this method, if applicable. In the case of Clear, there are no parameters so we do not have to worry about adding a parameter to the private method if we were to call it. Don’t worry, we will see some parameters for GetMedian Winking smile.

Before we hit up on GetMedian, let’s examine what happens when we try to view a method that has multiple overloads.

[array].GetMethod('Reverse')

image

This error is talking about results for ‘Reverse’ were found which means that we need to find a way to only use a single instance. What we need to do is figure out the parameter types that exist for each method overload and we can then use those with our GetMethod() call.

[array].GetMethods() | Where {$_.Name -eq 'reverse'} | ForEach {
    Write-Verbose $($_.Name) -Verbose
    $_.GetParameters() | Select Name, ParameterType, Position
}

image

I’ll got for the second method which is looking for an Array and two Int32 types and plug those into the method and see what happens.

[array].getmethod('Reverse',[type[]]@('array','int32','int32')).GetParameters()

image

And now we have our method. Definitely something to keep in mind if you happen to run into this error message.

The problem here is that the GetMedian method is not here! This is now where we have to make use of the Reflection.BindingFlags to locate our private method.

Let’s take a look at all of the possible values here for System.Reflection.BindingFlags

[System.Reflection.BindingFlags].GetEnumNames()

image

Each of these provides specific filters for when you do a search for the methods using GetMethod() or GetMethods(). Rather than regurgitate all of the possible meanings for these, I will instead direct you to this link that does a fine job of explaining everything.

The binding flags that I need to locate the private methods are: Static, Nonpublic and Instance. The three of these will open up a whole new world of methods that were previously hidden from us.

$BindingFlags = 'static','nonpublic','instance'
[array].GetMethods($BindingFlags).Name

SNAGHTML2be7092d

Definitely a lot of private methods here! But in this case, I am only concerned with GetMedian. Let’s now view the method itself.

$BindingFlags = 'static','nonpublic','instance'
[array].GetMethod(‘GetMedian’,$BindingFlags)

image

Now we can view the parameters of this method and see what is required.

$Method = [array].getmethod('GetMedian',@('nonpublic','instance','static'))
$Method.GetParameters() | 
Select Name, ParameterType, Position | Format-Table –AutoSize

image

Here we can see that both of the parameters require an Int32. The low is the starting index of the array (usually 0) and the hi parameter requires the highest index of the array. Also note the positions of each parameter. Just like in PowerShell, if we don’t specify the correct value for the right parameter in the proper position, bad things can happen.

We have the method and we have the parameters, but how in the world do we actually use this method? It’s not publically available so what is the magical process to use it? Well, we have to call the Invoke() method on the method and supply the object that owns the method followed by the collection of values required by the parameters (in the proper order) for it to work properly.

I want to first create an array of letters:

$list = 'a','b','c','d','e'

image

We obviously know that ‘c’ is the middle item in the array, but imagine if this was a huge array. Might not be that obvious.

Next up is to set ourselves up to use the private method.

$GetMedian = [array].getmethod('GetMedian',@('nonpublic','instance','static'))

And now we get to call the method by supplying the array itself and the low and hi parameters.

$Index = $GetMedian.Invoke($list,@(0,$list.Count))
$Index

image

What we actually get back is the index of the array (remember the return type of the method) so we can use that to slice into the array and verify that the median is indeed ‘c’.

$list[$Index]

image

Sure enough, it is the letter ‘c’ that is the median of this array.

Given, this was a rather simple demonstration of how you can use private methods in PowerShell, but this was the same approach that I took when working with my module to implement $Using: support.

Just for the sake of having a reference, if I ran into a issue with multiple method overloads, I would use the following in order to get the one that I needed (after knowing the parameter types).

[array].getmethod('GetMedian',@('nonpublic','instance','static'),$Null,[type[]]@([int32],[int32]),$null)

It just took a little work to locate the method and then to supply the proper parameter types to the method and it worked like a champ!

Posted in powershell | Tagged , , , , | 6 Comments

PowerShell and WPF: Ink Canvas

Today’s PowerShell and WPF topic is all about the Ink Canvas, which is a WPF control that gives you the opportunity to draw on it, just like MS Paint! There really isn’t a lot to this control and we can quickly provision it in a short amount of time. Of course, adding some fun features like changing the color of the pen and using the eraser and highlighter will require a little more work in order for it to work properly.

With that out of the way, let’s get started on building the ink canvas to use! If you have Visual Studio available, then you can quickly put together a UI and then copy the XAML code and merge it into a PowerShell script. In my case, I am building the XAML manually because there really isn’t a lot of add for this example.

[xml]$xaml = @"
<Window 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" WindowStyle = 'ToolWindow'
ShowInTaskbar = "True" >    
<InkCanvas x:Name="InkCanvas">
</InkCanvas>
</Window>
"@

As I mentioned, this is a basic control with pretty much no options set. I’ve cast the here-string as XML and will now take this and open it up using XMLNodeReader and then connect to the Window control.

$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load( $reader )

I only have to connect to a single control here, which happens to be the InkCanvas itself.

#region Connect to Controls
$InkCanvas = $Window.FindName('InkCanvas')
#endregion Connect to Controls

Now if I just show the window, we can instantly start drawing in it.

[void]$Window.ShowDialog()

image

Changing the Ink Color and Size

By default, the ink color is black. This can be changed through the $inkcanvas.DefaultDrawingAttributes.Color property. This can be a wide range of colors depending on your style. In this case, I will add a line to change it to red and then we can see the results.

$inkcanvas.DefaultDrawingAttributes.Color = ‘red’

image

We can even increase or decrease the size of the ink stylus to have a wider or narrower drawing stroke size. This is handled under the $InkCanvas.DefaultDrawingAttributes.Width and $InkCanvas.DefaultDrawingAttributes.Height properties. Adjusting these values will have a nice effect on the size as shown below:

Larger

image

Smaller

image

Setting up a Highlighter

Another nice thing that you can take advantage of with the InkCanvas is that it has a highlighter that you can use…after you select it that is.

$InkCanvas.DefaultDrawingAttributes.IsHighlighter = $True
$InkCanvas.DefaultDrawingAttributes.Color = 'Yellow'
$InkCanvas.DefaultDrawingAttributes.StylusTip = 'Rectangle'

Note here that I changed the shape of the stylus from a ellipses to a rectangle to make it more ‘highlighter like’ and also set the color to yellow. The result is a more transparent stroke that shows up when being used.

image

Let’s merge both a drawing and the highlighter into one thing and see what we can do.

image

As you can see, we can both use the ink and highlighter to accomplish a mix of things.

Erasing out Work

Of course, with drawing various things here, we certainly could use a way to erase our work or the entire canvas if we need to. First we can clear the board by calling the following method under the Strokes property object;

$InkCanvas.Strokes.Clear()

No real need for a screenshot here as a cleared canvas is pretty easy to envision.

The eraser part is the next thing to look at. We can set this under the $InkCanvas.EditingMode property by specifying one of the two options for the eraser:

  • EraseByPoint
    • Standard eraser where you drag the mouse around to erase parts of the stroke. Cursor is in a square shape.

EraseByPoint

  • EraseByStroke
    • This will actually erase the entire stroke vs. just a part of it. Cursor looks like an eraser.

EraseByStroke

With a couple of ways to erase our work, it shouldn’t be hard to clean up some accidental mistakes!

Selecting our Drawings

We can also select our drawings as well and copy, cut, resize and move them around! We first have to tell the InkCanvas that we want to select something by using the Select() method on the InkCanvas. We also need to specify an object of System.Windows.Ink.StrokeCollection.

$InkCanvas.Select((new-object System.Windows.Ink.StrokeCollection))

You will see the cursor change into a large plus (+) sign and we are now free to drag an outline of the drawing to then take action against using one of the following methods;

$InkCanvas.CopySelection()
$InkCanvas.CutSelection()
$InkCanvas.Paste()

As you can see, we are able to copy, cut or paste our ink image on the canvas. Moving and resizing occurs once we have selected an item.

SelectMethod

Saving and Loading Ink Drawings

The last thing to really cover here is saving and loading our ink drawings.

Saving involves setting up a FileStream that we can then apply to the Save() method of the $InkCanvas.Strokes property collection. We can make this process easier by creating a SaveDialog and giving it a default extension of .isf for our ink drawings.

$SaveDialog = New-Object  Microsoft.Win32.SaveFileDialog
$SaveDialog.Filter = "isf files (*.isf)|*.isf"
$Result = $SaveDialog.ShowDialog()
If ($Result){
    $FileStream = New-Object System.IO.FileStream -ArgumentList $SaveDialog.FileName, 'Create'
    $InkCanvas.Strokes.Save($FileStream)
    $FileStream.Dispose()
}

A similar approach can be done when we want to re-open an existing ink drawing by using the OpenDialog instead.

$OpenDialog = New-Object Microsoft.Win32.OpenFileDialog
$OpenDialog.Filter = "isf files (*.isf)|*.isf"
$Result = $OpenDialog.ShowDialog()
If ($Result) {
    $FileStream = New-Object System.IO.FileStream -ArgumentList $OpenDialog.FileName, 'Open'
    $StrokeCollection = New-Object System.Windows.Ink.StrokeCollection -ArgumentList $FileStream
    $InkCanvas.Strokes.Add($StrokeCollection)
    $FileStream.Dispose()
}

Our end result is something that looks like the following image:

Save_Open

I have the source code below so you can take this and have some fun with it. One last thing is that I added some keyboard shortcuts to make things such as changing the ink color, eraser, etc… more easy to do. Look for the event for Add_KeyDown.

Source Code

$Window.Add_KeyDown({ 
    $Key = $_.Key  
    If ([System.Windows.Input.Keyboard]::IsKeyDown("RightCtrl") -OR [System.Windows.Input.Keyboard]::IsKeyDown("LeftCtrl")) {
        Switch ($Key) {
            "C" {$InkCanvas.CopySelection()}
            "X" {$InkCanvas.CutSelection()}
            "P" {$InkCanvas.Paste()}
            "S" {
                $SaveDialog = New-Object  Microsoft.Win32.SaveFileDialog
                $SaveDialog.Filter = "isf files (*.isf)|*.isf"
                $Result = $SaveDialog.ShowDialog()
                If ($Result){
                    $FileStream = New-Object System.IO.FileStream -ArgumentList $SaveDialog.FileName, 'Create'
                    $InkCanvas.Strokes.Save($FileStream)
                    $FileStream.Dispose()
                }                
            }
            "O" {
                $OpenDialog = New-Object Microsoft.Win32.OpenFileDialog
                $OpenDialog.Filter = "isf files (*.isf)|*.isf"
                $Result = $OpenDialog.ShowDialog()
                If ($Result) {
                    $FileStream = New-Object System.IO.FileStream -ArgumentList $OpenDialog.FileName, 'Open'
                    $StrokeCollection = New-Object System.Windows.Ink.StrokeCollection -ArgumentList $FileStream
                    $InkCanvas.Strokes.Add($StrokeCollection)
                    $FileStream.Dispose()
                }                
            }
        }
    } Else {
        Switch ($Key) {
            "C" {
                $InkCanvas.Strokes.Clear()
            }
            "S" {
                $InkCanvas.Select((new-object System.Windows.Ink.StrokeCollection))
                #$InkCanvas.Select($InkCanvas.Strokes)
            }
            "N" {
                $Color = $Script:ColorQueue.Dequeue()
                $Script:ColorQueue.Enqueue($Color)
                $InkCanvas.DefaultDrawingAttributes.Color = $Color
            }
            "Q" {
                $This.Close()
            }
            "E" {
                Switch ($InkCanvas.EditingMode) {
                    "EraseByStroke" {
                        $InkCanvas.EditingMode = 'EraseByPoint'
                    } 
                    "EraseByPoint" {
                        $InkCanvas.EditingMode = 'EraseByStroke'
                    }
                    "Ink" {
                        $InkCanvas.EditingMode = 'EraseByPoint'
                    }
                }            
            }
            "D" {
                If ($InkCanvas.DefaultDrawingAttributes.IsHighlighter) {
                    $InkCanvas.DefaultDrawingAttributes.StylusTip = 'Ellipse'
                    $InkCanvas.DefaultDrawingAttributes.Color = 'Black'
                    $InkCanvas.DefaultDrawingAttributes.IsHighlighter = $False
                    $InkCanvas.DefaultDrawingAttributes.Height = $Script:OriginalInkSize.Height
                    $InkCanvas.DefaultDrawingAttributes.Width = $Script:OriginalInkSize.Width
                    $Script:OriginalHighLightSize.Width = $InkCanvas.DefaultDrawingAttributes.Width
                    $Script:OriginalHighLightSize.Height = $InkCanvas.DefaultDrawingAttributes.Height
                }
                $InkCanvas.EditingMode = 'Ink'            
            }
            "H" {
                If (-NOT $InkCanvas.DefaultDrawingAttributes.IsHighlighter) {
                    $Script:OriginalInkSize.Width = $InkCanvas.DefaultDrawingAttributes.Width
                    $Script:OriginalInkSize.Height = $InkCanvas.DefaultDrawingAttributes.Height
                }
                $InkCanvas.EditingMode = 'Ink'
                $InkCanvas.DefaultDrawingAttributes.IsHighlighter = $True
                $InkCanvas.DefaultDrawingAttributes.Color = 'Yellow'
                $InkCanvas.DefaultDrawingAttributes.StylusTip = 'Rectangle'
                $InkCanvas.DefaultDrawingAttributes.Width = $Script:OriginalHighLightSize.Width            
                $InkCanvas.DefaultDrawingAttributes.Height = $Script:OriginalHighLightSize.Height 
            }
            "OemPlus" {
                Switch ($InkCanvas.EditingMode) {
                    "EraseByPoint" {
                        If ($InkCanvas.EraserShape.Width -lt 20) {
                            $NewSize = $InkCanvas.EraserShape.Width + 2
                            $Rectangle = New-Object System.Windows.Ink.RectangleStylusShape -ArgumentList $NewSize,$NewSize
                            $InkCanvas.EraserShape = $Rectangle
                            $InkCanvas.EditingMode = 'None'
                            $InkCanvas.EditingMode = 'EraseByPoint'
                        }                
                    }
                    "Ink" {
                        If ($InkCanvas.DefaultDrawingAttributes.Height -lt 20) {
                            $InkCanvas.DefaultDrawingAttributes.Height = $InkCanvas.DefaultDrawingAttributes.Height + 2
                            $InkCanvas.DefaultDrawingAttributes.Width = $InkCanvas.DefaultDrawingAttributes.Width + 2
                            $InkCanvas.EditingMode = 'None'
                            $InkCanvas.EditingMode = 'Ink'
                        }
                    }
                }
                    
            }
            "OemMinus" {
                Switch ($InkCanvas.EditingMode) {
                    "EraseByPoint" {
                        If ($InkCanvas.EraserShape.Width -gt 2) {
                            $NewSize = $InkCanvas.EraserShape.Width - 2
                            $Rectangle = New-Object System.Windows.Ink.RectangleStylusShape -ArgumentList $NewSize,$NewSize
                            $InkCanvas.EraserShape = $Rectangle
                            $InkCanvas.EditingMode = 'None'
                            $InkCanvas.EditingMode = 'EraseByPoint'
                        }
                    }
                    "Ink" {
                        If ($InkCanvas.DefaultDrawingAttributes.Height -gt 2) {
                            $InkCanvas.DefaultDrawingAttributes.Height = $InkCanvas.DefaultDrawingAttributes.Height - 2
                            $InkCanvas.DefaultDrawingAttributes.Width = $InkCanvas.DefaultDrawingAttributes.Width - 2
                            $InkCanvas.EditingMode = 'None'
                            $InkCanvas.EditingMode = 'Ink'
                        }
                    }
                }            
            }
        }
    }
        
})
Posted in powershell | Tagged , , , | Leave a comment

The 2015 Scripting Games and the First Puzzle

In case you haven’t heard, the 2015 Scripting Games have taken a different approach than what has been done in the previous years. Instead of a throwing down all of the events within a 2-4 weeks span as has been done in the past, this year is more focused on an event per month style to allow folks more of an opportunity to complete the events. Also changed is the use of judges and coaches (used with the team approach last year) to review the code submitted.

Having competed, judged, coached, etc… on the Scripting Games since 2010, I am interested to see how this plays out. I will be the first to admit that judging the submissions during the games is practically a full time job to ensure that you review as many as possible by testing to see if they ran right, then running through the code to see how it was written to assign a proper score. This made for some long nights as well as auto-pilot syndrome sometimes when we were coming down to the deadline of trying to get everything judged by at least 2 judges to ensure a fair look at entries.

I could more into this but you can find all of this information out on PowerShell.org: http://powershell.org/wp/2015/06/29/the-scripting-games-heres-whats-happening/

Needless to say, this should be a fun approach and also provides a great way to get the User Groups involved as well for an added piece of fun. As the blog post says, the idea of a more familiar event could still happen in the future but the current timeline is still unsure at this point.

All that being said, the first puzzle has been published out on PowerShell.org: http://powershell.org/wp/2015/07/04/2015-july-scripting-games-puzzle/

My part in this event is that I am going to offer a celebrity submission, meaning that I will offer my solution as well as how I came to the finished piece. That won’t be published until sometime next month, but I will be sure to let everyone know when it goes live.

 

Good Luck!

Posted in powershell | Tagged , , | Leave a comment

Looking at Local Groups Using PowerShell on MCPMag

My latest series on MCPMag talks about local groups and using PowerShell (of course Winking smile) to not only report on the groups, but also to manage them. Check them out and let me know what you think!

Managing Local Groups in PowerShell

Reporting on Local Groups in PowerShell

Posted in powershell | Tagged , , , | Leave a comment