Using Drag and Drop in PowerShell GUIs

Drag and drop is a wonderful facility that most of us will use every day without even thinking about it. This article shows how it can be implemented in PowerShell GUI applications.

For this particular script, we’ll implement drag and drop functionality to allow us to drag a file from explorer to a textbox in we’ve created. When the drag and drop operation is complete, the textbox will then show the path to the file.

You can find a copy of the PowerShell Studio form and exported PowerShell code at the PowerShell.Amsterdam repository.

Here is what we our application will do once we have completed it:

To achieve our objective, we need to make use of two events, DragOver, and DragDrop.

DragOver occurs when the mouse is over the control on which we wish to ‘drop’ our object. We’ll typically just use this for changing our pointer to show a move or copy operation is in operation.

DragDrop occurs once the actual operation is finished. That is, the object has been dragged into the form and over the control, and the mouse button released.

To implement this in our application, carry out the following:

  • Create a form
  • Create a Textbox on the form
  • Set the following properties for the Textbox
    • Name : txtDragandDrop
    • Label : Contents dragged:
    • AllowDrop : true

1 - form design and properties

We now define the events that will be processed, and their handlers.

  • DragDrop : txtDragandDrop_DragDrop
  • DragOver : txtDragandDrop_DragOver

2 - form design and events

For the event handler code, use the following :

If you are developing this application in PowerShell Studio, you will need to first export the code, either to a standalone EXE, or .PS1 file.

  • Run the application from either of the above.
  • Drag a file of you choice from explorer to the textbox.

The textbox will be populated with the filepath of the file that has been dragged and dropped over it.

4 - running

Thanks for reading!


Creating a Shortcut for a Button in a PowerShell GUI

While most of us are all still friends with the mouse in GUIs, keyboard shortcuts once learned are very effective ways of manipulating form controls quicker.

Serveral controls, such as buttons can use keyboard accelerators. This is simply done by prefixing the Text property of the control by an ampersand. By doing this, you can perform the same as the Click event for that control simply by holding down the ALT key on the keyboard, and then the appropriate letter.

For example, a button control with its text property set to &OK will respond to the keyboard combination ALT + O as if the mouse had clicked on it. In keeping with normal Windows functionality, you can identify the keyboard shortcut by holding down the ALT key, and the letter for the accelerator will be listed with an underline.

Here’s how you’d do this in PowerShell Studio :

Keyboard Shortcut

And in PowerShell code itself, this is represented as :

Font Anti-Aliasing in PowerShell GUIs


The text on winform projects may seem blocky sometimes, particularly at larger font sizes. It never seems to look as polished as those we see with Microsoft products.

Here’s a standard form using Segio 24pt in white. It’s pretty blocky, especially around letters such as ‘S’ and ‘P’. Click on the image below to see it in normal size to get an idea how this looks.


Text without Anti-Aliasing

In order to make our text smoother and more, anti-aliasing will need to be used.

What’s Anti-Aliasing?

Anti-aliasing is the name given to actions which aim to minimise this type of blockiness. It works by shading the pixels along the borders of an image. In order to achieve this for ourselves, we need to dig into some .NET methods and events.

This post shows how we do just that for our fonts in PowerShell Studio, but can be applied in whatever way you develop your GUI apps.

Create a Project

Create a new forms project, making the form a good size. Now, drag a PictureBox control onto the form, and set the size of it close to the size of the form itself.

Set the properties for the PictureBox as follows :

Dock = ‘Top’
BackColour = 1;3;86

Create Positioning Functions

Because we’re going to be working with graphics, we need to define placement based on a horizontal and vertical basis. Whilst we could use absolute positioning, where we manually specify a fixed location, this style is rendered invalid if we make changes to size of the control or the graphic itself. Its relative positioning is changed.

Instead, if we use calculations for positioning, it gives us the flexibility to change control and graphic sizes after the code has been written without having to modify it later.

Thinking about this, there are several things we need to do :

  • Get the midpoint of the control (our picture box)
  • Get the midpoint of the graphic (our drawn string)
  • Get the position for placement of the graphic on the control

Picture Box Control

In this function, we simply pass in the PictureBox control, and work out its center point by adding the left most point with its width, and then divide by two. This gives us the horizontal (aka x) location. Similarly, we add the control’s top most point with it’s height and divide by two to get its vertical center point. These values are then returned as an object.

Drawn String

We’re working in a similar manner to the above function, but require to do a bit more calculation. We pass in a graphics object, previously instantiated, the string to be drawn, and the font itself. The MeasureString method of the grahpics control is then invoked, using the other two parameters we’ve just mentioned. Once that is completed, we obtain the horizontal and vertical midpoints.

Position from Drawn String

Now that we have our two sets of midpoints, we can calculate where the drawn string should be placed. This is done by subtracting the result of the latter function from the former for both x and y positions, and returning the results.

Create Event Code

Now that we’ve defined out functions, we can setup the event action and code.

The Paint event occurs when a control requires repainting. This can happen as a result of other actions on a form or control, such as scrolling to the bottom of a form at to the top again.
Go to the Paint event of the PictureBox in the properties panel, and double click on it. Insert the following :

Code explanation

What happens in this code is the following:

  • We obtain the Graphics properties from the event data and assigning it to a variable $g.
  • We define some of the properties of the picturebox control.
  • A Font type variable is created using Sergoe UI typeface in size 84 as the supplied parameters
  • A SoldBrush object is created. This is the drawing style we use, just like in the Paint application.
  • The functions mentioned previously are then used
  • With the above completed, we define a floating point coordinate object
  • We also set the type of anti-alias rendering to be carried out. Several options are available. See the links at the bottom of this page to get more information on these
  • We now run the DrawString method to create and position the anti aliased rendering of the font.

View the New Results

Now run the project to see a much smoother version.


Text with Anti-Aliasing

I’d recommend taking a look at the System.Drawing namespaces documentation on MSDN to get more information on the methods, properties, and enumerations used in this code, which will explain in more detail about each.

You can find the Project code and exported code (for those not using PSStudio) at my GitHub repository, and also a video of this in action on my YouTube channel.



Using .NET Event Handlers in a PowerShell GUI

GUI development tools, such as PowerShellStudio, make it very easy to manage events for controls on our winforms.

Once the control is on the form, and we select it, click on the Events button (the lightning symbol), the Properties panel gives us a list of the events available for us to manage. However, events are not just restricted to controls. There’s a world of other events out there that we can use to interact with our winforms projects.

In this article, we’ll create a forms project that downloads the latest 64 bit antimalware definitions from Microsoft and updates a progress control to show how far the download is to completion, using methods and events from a .NET class.

Updates to the latest antimalware definitions can be obtained through and a look through MSDN shows us that we can use the .NET WebClient class to carry out downloads programmatically.

To start this process, create a new forms project, and drag a progress bar, label, and button onto the form. Then set the properties of the controls as below. Note that properties with text controls will automatically be named for you if you set the text property first.

Text : Progress
Name : labelProgress

Text : Download
Name : buttonDownload

Progress Bar
Name : progressbarDownload

Here’s how my form looks.

Blog - Adding Events - Form Design

Once this is complete, we can begin writing the event code.

In our forms Load event, we create an instance of the System.Net.Webclient class. This is assigned to the script level variable, $webclient. This scope is required in order for the other parts of the solution to be able to process the object and its events.

The next two lines add event handlers for the DownloadProgressChanged and DownloadFileCompleted events. DownloadProgressChanged indicates a change in the state of the transfer with regards to the amount of content downloaded, whilst DownloadFileCompleted is fired on the completion of a download. The scriptblocks for these are $webclient_DownloadProgressChanged and $webclient_DownloadFileCompleted respectively.

The event handler for updating the progress of the download is written next:

To make it easier to read, $progressInfo is used for the rest of the code instead of $_. The variable contains the values given to us by the System.Net.DownloadProgressChangedEventArgs class instance that is passed into the handler.

The DownloadProgressChangedEventArgs class contains ProgressPercentage, BytesReceived, and TotalBytesToReceive properties. We use these for changing the progress meter value property, and also updating the text in the label below to show bytes received and the total size of the download.

The event handler for DownLoadFileCompleted is next:

When DownloadFileCompleted is fired, the label text is changed to indicate the download’s completion.

Lastly, the download button’s Click event is set to begin an asynchronous download of the antimalware definition.

Blog - Adding Events - Code

Our project code

And when we run the project and click on Download! We see this in action, with the progress bar being updated and the progress text below it also, using the code we wrote earlier.

Blog - Adding Events - Downloader Running

The downloader in action

This same methodology can be employed for using .NET events, creating an instance of the object, adding the event handler definition, and then the scriptblock code to be used.

You can find exported project code and the project files at my repository on GitHub, and a short video of the project in action on the YouTube channel.


Removing Items from Lists Using the Keyboard

In an earlier post, we created a form with two listgridview controls, and used both add and remove buttons, and double click functionality to allow an item to move an item from one control to another in an intuitive manner.

Todays post shows how we can use a remove items from a list by pressing a key. Specifically, we’ll be using the DELETE key for removing items. This will be carried out in Sapien’s PowerShell Studio 2015, but the same methodology applies to however you generate winforms in PowerShell.

For initial setup, carry out the following :

  • create a new form with a header and several items.
  • create a listview control called $lstControl
  • populate the control with a header
  • add some items to the listview control

Sample form and control layout


  • select the control
  • select Events in the properties pane
  • double click on KeyDown
  • Insert the following code :

The KeyDown event’s code


Go ahead and test it, adding an item to the control on the right hand side, selecting it, and then pressing the DELETE key.

Also, because the code loops through each selected item in the control, we can also use standard multiple selection functionality offered by the various use of the SHIFT and CTRL combinations.

Two items are selected using a click SHIFT combination

The DELETe key is pressed, and the previous selected items are removed from the list

You can find the files, if you are using PowerShell Studio 2015, or exported .ps1 file at my gitlab repository.

Additionally, there’s a (basic) video of this code in action at my channel on You Tube.

Thanks for reading, and feel free to provide feedback.



Using Double Click for Adding and Removing Items from Lists

Double click functionality for movement of items between listboxes is commonly used within Windows, and quite intuitive. This article shows how we can implement this in our own forms based projects. We’ll use this example with ListView, but it is also applicable to ListBoxes (ListView controls inherit from ListBoxes).

For initial setup of this project, follow the steps below, using your preferred GUI editor or code.

  • Create a new forms project
  • Change the form’s control name and text if desired (called AddServers and Double Click Demo in this article)
  • Add two ListView controls, with names of lstFrom, and lstTo
  • Add two Button controls, with names of btnAdd, and btnRemove
  • (optional) Set the Text property of the form


  • Add a column to the form
    • Name : columnComputernameFrom
    • Sorting : Ascending
    • Text : Computername
    • View : Details
    • Add the following items to lstFrom , with Text values of Computer1, Computer2, Computer3, and Computer4


  • Add a column to the form
    • Name : columnComputernameFrom
    • Text : Computername
    • View : Details
    • Sorting : Ascending

Set the name of the top button to btnAdd, and the Text property to >
Set the name of the bottom button to btnRemove, and the Text property to <

Arrange the controls to look something like the picture below :

Our form design

Our form design

Once this is complete, we’re going to start adding some features.

Add/Remove Buttons

This could be described as the ‘classic’ method of adding and removing items from lists, with arrows pointing in alternative directions to indicate the addition or removal of an item from one listbox to another.

In the Load event, we’ll set the arrow buttons Enabled property to $false, since no items are selected.

Let’s activate or deactive the add and remove buttons depending on whether the appropriate listboxes are populated, and additionally disable the appropriate button when an item is selected. There’s no point of the add button being enabled when we have selected an item from the To listgridview for example.

Now we add the code for the button events, adding to removing from the appropriate listgridview. We use the FindItemWithText method to verify that the item does not already exist there, preventing duplications.

Now go ahead and run it. Select double click on an item on the left hand column, and it will add it to the right one, and versa.

Double Click - Running 1

Double click on one of the items

Double Click - Running 2

…..and it is moved to the other side


The mechanisms that double click provides for list also be used on other controls. For example, double clicking on an item in a list which automatically populates a textbox with the value that has been selected in the list.

You can find a copy of the PowerShell Studio .psf form file, and also an exported .ps1 of the same for at my repository on GitHub.

A video of this is also available on the PowerShell.Amsterdam YouTube channel.

Thanks for reading, and please provide feedback if you have comments, questions, or have noticed any errors in this article.



Using the MouseEnter and MouseLeave Events in PowerShell Studio

Default Winforms on their own can sometimes look a bit bland, but there are some things we we can do, which do not require much coding, that can really enrich the GUI experience.

The MouseEnter and MouseLeave events can be easily overlooked when writing a forms application. A MouseEnter event is raised when the mouse pointer moves over an area, or to be more correct, a specific controls region. The MouseLeave event is the opposite. It is raised when the pointer is moved outside of the region of a control.

You can take advantage of these events in many ways. In this post, we’ll use them to highlight the control over which the pointer is, and display descriptive text associated with that control. The style is meant to be not unsimilar to some of the Microsoft installation dialogs. 🙂

NB If you wish, you can skip the steps below by downloading the source files from my GitHub repository.

Create the Forms Project

First of all, create a new forms project. Let’s call it MouseEnter. Now add the following controls, setting their properties as mentioned below.

Control Type Name Text BackColor Font
Form frmMouseEnterDemo MouseEnter demo White default
Panel panel1 na 1,36,86 default
Label labelDescription Description na Size 10, Bold
Label LabelOptions Options na Size 10, Bold
Label LabelOverview Overview na default
Label LabelMouseEnterApplication MouseEnter Application na default

Position labelDescription so that it occupies the left half of the form, underneath the blue panel.

Position these last three labels on the right hand side of the form, with the Options label at the top, followed by the other two directly under it.

Your form layout should now look something like this :

MouseOver - Initial Form Setup

With the labelDescription control positioned as we want it, clear its the text property, so that it is blank.

Now we need to add code for five events :

  • form loading
  • mouse enters overview label region
  • mouse leaves overview label region
  • mouse enters mouse enter application region
  • mouse leaves mouse leave application region

Writing the Event Code

We’ll register event handlers for the above actions by the process below, and then paste in the event code that is further down this page.

  • Select the properties panel, and the events (lightening) button
  • Double click on the form
  • Go back to the form view, select the overview label, double click on MouseEnter.
  • Do this also for the MouseLeave event
  • Repeat the above for the mouseenterapplication label.

Once you have completed, this your form should show a set of entries for the events we have selected. These will be empty. Select the text, and clear it.

Select the text below, copy it into the clipboard, and then paste it into the code window.

This sets the text that  to be shown when a control’s region is entered or left by the mouse pointer, and also other actions to be performed in these circumstances. When the pointer enters a control’s region, we set its text is set blue, and the label on the left hand of the screen displays some descriptive text. On startup, or when a pointer leaves a controls region, this description is reset back to the default welcome text.

mouseover - part 2 - form code

Rearrange your form as you wish.


Now let’s run our project to see the results.

Overview - MouseEnter

Overview Mouse Enter

Overview - MouseLeave/Not in any region

Overview MouseLeave

When the pointer is positioned over one of the options, the font changes to blue, and the descriptive text on the left hand side also changes. When the pointer moves outside the controls region, the default text is displayed, and the font set back to black.

And a video which highlights what’s happening a bit better. Apologies for the poor quality, I’m still wrestling with uploads to YouTube at the moment :

As always, comments and feedback welcome. Thanks for reading.



Using Local Functions on Remote Computers

30/12/2015 – UPDATE : Scriptblock code changed to better llustrate use of multiple local functions used in combination with other code on the remote system, after feedback from Aleksandar Nikolić &  Tommy Maynard. Thanks guys. 🙂

I came across a situation recently where I needed my remote computers to use some functions that were part of a project I was working on. I wanted to use them in various parts of a scriptblock passed from Invoke-Command. Options with Invoke-Command did not allow for this though. You have the mutial exclusive -file and -scriptblock  parameters.

I prefer to keep my functions as separate files as opposed to their inclusion in a module.Loaded functions are stored within the FUNCTION PowerShell provider, and because of this, cmdlets such as Get-ChildItem can be used with them.

I noticed the Name property of items in FUNCTION: always have the name of the function, and the Definition property the actual code.  To convert this to the exact text of the function as we normally see it, should just require some string concatentation  All we were missing was the word Function, and surrounding braces to create a string equivalent of the function. We’d also add new line characters as well for formatting purposes.

This could be done using the format:

Function {rn item.definition rn}rn

This is the function developed below:

It takes as a parameter an array, which is filtered against items provided by the Function PowerShell provider.  Then, the function text itself is comprised and concatenated to a string variable, $strFunctions.

At the beginning of our script, we define a string array containing the names of the functions that we wish to used for use remotely. In the below case, I had functions called Get-ServerList and Confirm-ValidSource.

Then, the function we created earlier is invoked to return a string of the text from these functions.

With this variable defined, I can create a new scriptblock of the string of functions above within the remote session, and then dot source it to make all these functions available.


For those of using PowerShell Studio, ensure the array of strings variable ($functions in this case) is defined in globals.ps1, and that for each function part of your project, the property CommandExtension is set to True.

Thanks for reading, and feel free to provide feedback.