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!


Asynchronously Save Images in the Clipboard to File

PowerShell v5.0 introduces us with two cmdlets, Get-Clipboard and Set-Clipboard which, just as their names suggest, allow us to obtain and set the contents of the clipboard. What’s not immediately apparent though is that these cmdlets can process more than just text in the clipboard.

In this blog, we’ll focus on using Get-Clipboard, and create a script which is used in combination with Register-EvengineEvent to save an image to file any time that one is detected in the clipboard during the current session. A repo containing the script is available at GitHub

Get-Clipboard supports the processing of several types of data that is in the clipboard, one of which is that of an image type. Examples of these would be print screens or copying an image created in Paint into the clipboard.

When an image is in the clipboard, and we use Get-Clipboard -Format Image, an object of Bitmap type (inherited from System.Drawing.Image) is returned. One of the methods this class provides is Save. Save has several overloads, one of which writes to a file and a variety of formats of your choice.

The script below requires use of the ISE, and uses Register-EngineEvent to register a scriptblock, which runs when a PowerShell.OnIdle event is raised. In the scriptblock, we check to see if there is any content in the clipboard of image type. If there is, we take the details of the current file open in ISE the editor, and use it to generate a unique filename. Then, the content of the clipboard is saved to this filename using the method mentioned above. Finally, we clear the clipboard to ensure that there we don’t end up in a continuous looping operation.

Thanks for reading!


Automatic Parameter Splatting ISE Add-On

Here’s some code I put together which converts parameters in a command to a splatted variant of them. There’s definately room for improvement with the code (it can struggles with some sequences of parameters), so any contributions or ideas would be great for this. It’s posted in my GitHub area.

The function below parses the selected text and attempts to split them into separate chunks of parameters, which are processed and then concatenated into a single string. Once complete, the existing parameters are removed from the command and replaced with the splat, and the hash table placed on the line above.

Run the function to store it memory. Now, in order for us to be able to call the function either from a menu or keyboard option in the ISE, run the following code. :

With this done, all that’s required is to :

  • Select the parameters you wish splatted in the command
  •  Either
    • Click Add-ons in the menu bar
    • Click Get Splat
  •  Or
    • Press ALT + T
Select the parameters

Selection of the parameters and splatting option

  • View the results
The result of the autosplat

The results of the autosplat

Here’s a video of it in action:

PowerShell and GitLab CI – Part 5


During the last article in this series on the use of PowerShell with GitLab, we noticed some displays on the build console, and some results from our build that was a bit unusual.

Today, I’m going to look a bit further into how the build engine works, which will also explain some of these results we are seeing.

How GitLab CI Runner Works

It would be logical to think that the PowerShell code is run in the same location or a subdirectory of the folder where the service file is, similar to Jenkins, but after a bit of investigation, I found out this is not the case.

To look further into what was happening, let’s add a line to the script section of the YAML file, and put a Start-Sleep command in.Make it ten minutes, to give enough time to remote onto the GitLab CI Runner, and do a search for our .ps1 file stored in a subdirectory of the repository.

Use the content below for our build file.

  • Save the changes
  • Add the updated file
  • Commit the changes
  • Push the changes
  • Navigate to the build section
  • Click on the commit

The job is running, and because of the Start-Sleep command, will continue to do so for the next ten minutes.

Part 5 - GitLab Job Running


  • Remote onto your build server (if it is not already the same system you are accessing GitLab from.
  • Go to the C:\Windows\Temp

There will be a folder name of the format Build_xxxxPart 5 - Temp Dir

  • Double click on the folder

Part 5 - Build Script Contents Dir

  • Within this folder is a script.ps1 file.
  • Open the file

Part 5 - The Script Code

The PowerShell code contained within the script: section of the YAML file is adjusted to make it suitable for returning the output we can see on the console window within a Gitlab job.

Looking at the code now, we can see that it has been changed significantly :

  • ErrorActionPreference has been set to ‘Stop‘.
  • Commands are in place to check to see if an error has occured, and if so to exit the script.  This will also result in the job being flagged as having failed.
  • Probably the most interesting of the changes is the frequent use of Echo command which mimics the command that follows it.

This explains several things to us :

  • How the console output is seen on the job screen
  • Some lines output appeared strange because variables were undefined at the stage when the Echo command ran

Because PowerShell returns all output from a function, it explains why were receive an array when the HappyHelloWorld function is called. It consists of the intented output, but also the Echo commands.

The use of a function in our build code now becomes a challenge or possibly could be perceived as something to be avoided, since we cannot guarantee the element in the array that will contain our desired output.  One way i’ve been able to get round this is to make the function return a PScustomobject, and make use of the -is operator outside of the function to obtain the value.

e.g. $functionOutput = $arrayReturned | Where {$PSItem -is [pscustomobject]}

However, I’ve found a better approach is to minimize the actual PowerShell commands that you use in the script, and instead create a Build folder within your repository which contains files with the actual commands that you wish to use for the build. These can be dotsourced to make them available from within the script, without the need for adding custom code to handle this.

There are many other aspects and configuration settings possible within GitLab, which lets you have powerful control over your build steps. Examples of this are defining the order of execution, ignoring errors, and setting the steps to be taken after each one.

It’s also worthwhile noting that these articles do not include the use of testing, which should be part of your chain of operations. If you are not already familiar with the use of Pester, I’d recommend taking a look at the documentation and examples on GitLab. Amongst others, Jakub Jareš has also written an excellent series of articles on its use, which you can find on

That’s it for this series of articles on the use of PowerShell and GitLab. Thanks for reading, and feel free to provide feedback.



PowerShell and GitLab CI – Part 1

GitLab 8 adds built in CI as an option, making a single instance of GitLab not only for use as a version control system, but also a continuous integration solution. GitLab is available for both use over the internet, and also locally hosted. These posts will cover the use of the internet service.

The next few posts will detail how I set this up for use with PowerShell, tested it, and some of the gotchas I came across. Todays one will cover the pre-requisites I needed to setup, and initial configuration for a new project.

Git Client

Naturally, in order to perform our GIT operations we’ll need some type of client installed. Some options available are :

NB At the point of writing this articule Posh-Git is included in the Github Desktop client, which may give you the best of both worlds.

My choice of client at the moment is Git for Windows and using the Bash CLI. I’ve still to take a proper look at Posh-Git, but it’s in the pipeline….

SSH Keys

Using the Bash console, you can create a set of SSH keys, which are going to be used later. Starting a Bash session with Git for Windows can be done by right clicking within any Explorer window, and selecting Git Bash Here

Opening a Bash session

Opening a Bash session

With the session open, type the following :

Creating the SSH keys

Creating the SSH keys

This creates a public and private key. If you accept the defaults, a folder called .ssh will be created in the root of your user profile. Within this, you will find two files, and id_rsa. The first of these will be used later when we are creating a test repository.

Register with GitLab

  • Browse to
  • Follow the on-screen instructions to register
  • Open the .pub public key file created earlier, and copy it into the clipboard
  • Login to Gitlab

Step 3 - Initial Login After Registering

  • Click Profile Settings
  • Click SSH Keys.
  • Click ADD SSH KEY
  • Paste your public key into the Key box
  • In the Name box enter a descriptive name of your choice
  • Click ADD KEY.

Step 4 - Adding SSH Keys

  • Click Back to dashboard

Creating the Project

On this screen, we can import existing projects from other sources, such as GitHub, but for now, we’ll create a new one.

  • Click + NEW PROJECT
  • Enter HelloWorld into the Project path box
  • If you wish, enter text describing the project in the Description box

Step 5 - Create New Project

This will then take us to the project page of HelloWorld. If you further scroll down the page, commands for us to setup our repository locally are detailed.

Step 6 - Project Page

Now startup a BASH session, and change to a directory where you want to create this sample repository. Use the commands provided in the above, from  Create a new repository.

The first time that you perform the GIT CLONE command, you will be prompted if you trust the authenticity of the host, Enter Yes. This information will then be recorded in a known_hosts file, which is placed within the .ssh folder referred to previously.

Once complete, close your BASH session.

Step 7 - Creating the repository

With the project created, and the repository locally cloned, we’ll go into the projects settings and enable the CI options.

  • Click Settings
  • Click Services

Step 8 - Configure Gitlab CI

  • Click Gitlab CI
  • Check Active
  • Click SAVE

When you do this, a green circle will appear next to GitLab CI on the right. New options will also appear on the left side, including Runners, CI Web Hooks, CI Settings, CI Services, and CI Events.

Step 9 - Enable Gitlab CI

  • Click CI Services
  • Click Mail

The Mail option is used to send an email when a build process has completed. Mail is enabled by default, but only for builds that do not succeed. I find it handy to have this enabled for all builds. If you wish to do this.

  • Select the Notify check box
  • Click to clear the Notify check box.
  • Click SAVE.

Step 10 - Enable Mail

That’s it for day 1. In the next article in this series we’ll deploy and configure a Windows Runner, and take a look at the options available.

Regain sysadmin rights to a SQL instance without stopping its service

I came across a situation a few weeks ago where there was a set of SQL servers, some with single and others with multiple instances, which were missing the required domain groups for management.

Worse, I had no permissions to the server, and without these, I was unable to login to the SQL instance. Another issue was that under no circumstances could any of the instances be stopped.

After a bit of head bashing I remembered that by default installation, the local system admin account is a system administrator in SQL Server, and it’s not one I remove after installation.

If I could write a script to add the required groups in, and run a script in a local system context then maybe i could restore the required permissions.

I came up with the script below. The only caveat is that Local System must be resident within the instance level users, and have sysadmin rights.

It’s a bit of a hack, but it served its purpose. 🙂

In the script, two text blocks are created.

The first one, assigned to the $task variable, is the XML for the scheduled task we are going to create.

The second one, assigned to $code, is the actual powershell code that the scheduled task would run. This code contains a function for executing the required sql commands, and additionally there is code which iterates through each instance on the server and runs the function with the required SQL commands to add the required permissions to each instance. The script writes these text blocks out to new files (in my case on the D drive).

Then, schtasks.exe is used to create the scheduled task, using the new XML file we’ve just created as the input source. Amongst other settings, the XML specifies that the tasks runs in local system context, and also the command and arguments to be executed. The arguments point to the second file just created, the .ps1 file. schtasks.exe is then used again to trigger the job and we wait until the status of the job changes from running to anything else. Once the task has completed, or failed, it is removed from Task Scheduler. Finally, the script removes the files it has just created so no footprint is left on the system at all. Sounds a bit ‘naughtyish’, but it’s really just to keep things tidy!

The code can be run remotely by specifying it as a scriptblock in an Invoke-Command against a remote system, if so desired.

NB You should also be able to use this for also adding single domain accounts, as the formatting of the sql command will be exactly the same. Just replace or add the required details.

You can find the source code for this at my repo