Friday Fun: Tweaking the PowerShell ISE

Today’s fun is still PowerShell related, but instead of something in the console, we’ll have some fun with the PowerShell ISE. One of the things I love about the PowerShell ISE is that you can customize it and extend it.  My ISE Scripting Geek project is an example.  But today I have a simple example that you can try.

When I’m training or creating courses for Pluralsight, I am often in the PowerShell ISE and it would be helpful to highlight the line of code I am going to run. But I don’t want to muck around with a mouse. So I have created an ISE shortcut to select the current line.

The ISE has an object model that has a root of $psise which is automatically created when you launch the ISE. I won’t go into the entire structure now. For our purposes we want to take advantage of this method:

$psise.CurrentPowerShellTab.AddOnsMenu.Submenus.Add()

This method takes 3 parameters, the text to display, an action scriptblock and optionally a keyboard shortcut. If you don’t want to use a parameter, use $Null in its place. Sometimes I create menu items that don’t have keyboard shortcuts so I’ll use $Null. But in this case a keyboard shortcut is the primary purpose.

You can use any combination using Ctrl, Alt, or Shift along with function keys (F2) and alphanumeric characters. I’m going to use Ctrl+L because it is unused. If they keyboard shortcut is already used, you’ll get an error when you run the command.

I’ve posted a short script on GitHub to do the job.

Once I run this script, I have a new menu shortcut.

image

If you make a mistake anywhere or want to re-run the command you’ll need to open a new PowerShell tab or restart the PowerShell ISE and try again.

I expect at some point I’ll incorporate this into the ISE Scripting Geek module, but for now it is separate.  For now, I’ll insert the commands into my PowerShell ISE profile script. In the ISE run this command to edit it:

If you’ve never created it you’ll get an error message. The ISE profile script will be something like  C:\Users\Jeff\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1.

Enjoy your weekend.

Friday Fun: A SysInternals PowerShell Workflow

Over the years I’ve come up with a number of PowerShell tools to download the SysInternals tools to my desktop. And yes, I know that with PowerShell 5 and PowerShellGet I could download and install a SysInternals package. But that assumes the package is current.  But that’s not really the point. Instead I want to use today’s Friday Fun to offer you an example of using a workflow as a scripting tool. In this case, the goal is to download the SysInternals files from the Internet.

First, you’ll need to get a copy of the workflow from GitHub.

A workflow command is like a function, in that you need to load it into your PowerShell session such as dot sourcing the file.

. c:\scripts\Update-SysinternalsWorkflow.ps1

This will give you a new command.

image

The workflow can now be executed like any other command.

image

The workflow’s main advantage is that it can process items in parallel and you can throttle the activity. In my workflow, I am processing 8 files at once.

One thing to be careful of in a workflow is scope.  You shouldn’t assume that variables can be accessed across the entire workflow. That’s why I am specifically scoping some variables so that they will persist across sequences.

I really hope that one day the parallel processing will make its way into the language because frankly, that is the only reason I am using a workflow. And it’s quick. I downloaded the entire directory in little over a minute on my FiOS connection. The workflow will also only download files that are either newer online or not in the specified directory.

If you are looking to learn more about workflows, there is material in PowerShell in Depth.

I hope you find this useful. Consider it my Valentine to you.

NOTE: Because the script is on GitHub, it will always be the latest version, including what you see embedded in this post. Since this article was posted I have made a few changes which may not always be reflected in this article.

Friday Fun: Improved PowerShell Napping

So I had some fun with my post last week on taking a nap with PowerShell. I got some great feedback on Twitter and a new comments on the blog. My initial effort was a relatively simple PowerShell script which certainly got the job done. But I there were a number of areas where I could expand and improve the script and they would be terrific teaching aids. So I did.

The function is defined in a script you can find in Github.

Let’s look at some of the changes I made. First off, I turned this into a function complete with comment based help. You’ll need to dot source the script file into your PowerShell session or profile script to make the command available.

I made just about every option a parameter and added a few parameter aliases as well. So even though I made the Minutes parameter positional so that you don’t need to use the parameter name, you could use –Nap or –Time. You’ll notice I also made the wakeup message a parameter.  Feel free to set your own default value. Otherwise, you can set a different message at different times.

I also realized that if you are napping, someone might still drop by your desk. So I included an option to display a progress bar using Write-Progress. This is a cmdlet that doesn’t get the love it should.

I defined an array of messages:

The messages will be used as the Status property for Write-Progress. I like using a hashtable of parameters to splat when using Write-Progress.

If I use the Progress bar, it is displayed using the seconds remaining.

And every 10 seconds I set the status to another randomly selected message. The result is something like this:

image

The last major change I made per a suggestion was to use the text to speech feature to have a Windows voice “say” the wake up message. I added a parameter for you to specify a voice name which in the US will most likely be David or Zira.  If you don’t know the names, you can specify a bogus value like ‘foo’ and the function will display the available names. This works because I added a validation script to the Voice parameter.

This is probably a bit more involved than most validation scripts.  The main takeaway is that if you use a validation script it has to return either True or False, or throw an exception as I’m doing here. But it works.

image

By adding a voice option I decided the function could either display the message using Write-Host or speak it. The chime happens in either event.

What this meant was that I had to differentiate the parameters which I did with parameter sets.  I specified the default in the cmdletbinding attribute.

Then I needed to specify a parameter set name for each parameter.  If you don’t specify parameter set name, then the parameter will belong to all sets.  Or you can do as I did and be explicit. If you do it properly it should be reflected in the help.

image

You can see that there are 2 ways to use this command. I’ll let you grab a copy and try out the new additions.

Certainly this isn’t a production oriented script but I hope it serves up some interesting examples of different scripting techniques and cmdlets.

As always, comments sincerely welcomed.

Enjoy!

Friday Fun: A PowerShell Nap

antique-watch-150x225I’m hoping that I’m not the only one who feels their butt dragging by mid to late afternoon. Let’s say that’s because we’ve been thundering through the day and by 3:00 we’re a bit out of gas. Yeah, I’ll go with that.

I find myself wanting to close my eyes for only a few minutes to recharge and or at least take the tired edge off.  In other words, I just want a quick nap like we had in kindergarten.  But I need to make sure I wake up! Since I always have a PowerShell console, I can use it as a quick and dirty alarm clock.

For starters I can use the Start-Sleep cmdlet to wait for X number of seconds. So if I want say a 10 minute timer I can run:

But if my eyes are closed how will know when time is up? A quick solution is to make my computer beep using the [console] .NET class.

So to run this all at once I can enter a command like this:

The semi-colon is the end of command marker so what I’m really doing here is executing 2 commands. PowerShell will sleep for 600 seconds and when that command completes, then the Beep() method will run.

But of course it is Friday so let’s have a bit more fun with this.

The Beep() method can also take 2 parameters. The first is a tone frequency, and the second is a duration in milliseconds.

With this in mind I put together a PowerShell napping script.

The script takes a parameter for the number of minutes you need to nap. It then writes a message to anyone who might be walking by your desk to keep quiet.  The script then does a countdown of sorts by calculating a timespan between the target end time and the current time. I’m writing the value as a string so that I can strip off the milliseconds.

nap in progress
nap in progress

At the end of the countdown I’ve recreated a well known chime, at least for those of you in the United States and of a certain age. I’ll let you try it out for yourself.

nap complete
nap complete

So get a bit more work done today,  and when you’re ready, take a quick PowerShell Power nap.

Enjoy and sweet dreams.

Friday Fun: Number Crunching

Earlier this week I was looking at the GoFundMe website in the midst of debating a new project. One of the considerations I have for sites like this is the expense involved. Certainly I don’t expect this type of service to be free. But I started wondering about what net donations might look like. According to GoFundMe, assuming I am interpreting this correctly, the site takes 5% of the donation right off the top. In addition to that there is a processing fee of 2.9% of the donation plus 30 cents. At least for the US. So for a $10 donation the net donation would be $8.91.

10 – (10*.05) – (10*.029 +.30)

Alright then.  This should be simple enough to turn into a PowerShell function.

This also should make for a fun learning opportunity.

The function takes a parameter for the donation amount. I cast it as a [double] in the event someone might donate $10.25. If used [int] PowerShell would turn it into $10.  I’ll come back to the other parameter in a bit.

I define the rates from GoFundMe as variables.  This makes it easier to calculate some values.

You’ll note that I’m using the Round() method of the .NET Math class. This is so that the result is formatted to 2 decimal points.  This is what I want to see, not necessarily how the site operates. With these values I can create a custom object.

Here’s a simple demonstration, and yes I know I’m not using a standard function name but this is for fun.

image

I also wrote the function as an advanced function so that I can pipe values into it. If you look at the parameter definition for $Donation you’ll see that I have a setting for ValueFromPipeline.

image

This makes it pretty clear about what happens with each donation.  But what did I end up with?  My function writes objects to the pipeline so that I can use other cmdlets, like Measure-Object.

image

Here’s the fun part: I can measure multiple properties.

image

I thought that was pretty handy.

I know that the values are in dollars.  But let’s say I was creating a report and I wanted to make it pretty and include the $ sign, or whatever my currency symbol might be.

If you recall, I included a switch parameter called UseCurrency along with a parameter alias of currency.

If I run the function with –UseCurrency, then this parameter will have a value of $True. That is how a Switch parameter works. In my function I can test the parameter value and it it is true, then I’ll create the same custom object, except that I will use the –F operator to format the value as a string using the currency symbol.

This operator is used to format strings in the .NET Framework. You can read more about this online at http://go.microsoft.com/fwlink/?LinkID=166450. But in short, the {0} on the left side of the operator is a numbered place holder. The c is the modifier which in this case indicates to use a currency format string and I’m limiting it to 2 places.  I probably don’t need that since I’m already rounding but I left it in for the sake of education.  On the right side of the –f operator is a comma separated list of values that will “plug in” to the place holders. The net result is this:

image

That looks pretty, but be aware that these values are strings.

image

This means my previous method of getting a sum will fail.  Instead I need to use numbers and then format the result.

image

Now I have the best of everything. Although if I truly want to make a pretty report, I can use Format-Table so that I can specify an alignment on the custom property.

image

I hope you found this fun and informative.  If you have any questions about what I did or why, please drop them in the comments.