Scary PowerShell

In honor of today’s festivities, at least in the United States, I thought we’d look at some scary PowerShell. I have seen a lot of scary things in blog posts, tweets and forum discussions. Often these scary things are from people just getting started with PowerShell who simply haven’t learned enough yet to know better. Although I have seen some of these things from people who appear to be a bit more experienced. I find these things scary because I think they are “bad” examples of how to use PowerShell. Often these examples will work and provide the desired result, but the journey is through a terrifying forest. Please note that PowerShell style is subjective but I think many of the core concepts I want to show you are sound.

First, here is a chunk of scary PowerShell code. This is something I wrote based on a number of “bad” techniques I’ve encountered.

This code will create a CSV file with files in C:\Work that are over a certain size and modified after January 1, 2014. When I see code like this I am pretty confident the author is coming from a VBScript background. To me, I see a lot of energy working with text. I’ll come back to that point in a moment.

First, filtering is a bit ugly. Unless you have a specific byte value in mind, use shortcuts like 1MB which is easier to understand than 104876. You can also combine filters into one.

I cringe when I see people trying to concatenate values in PowerShell. In this case it simply isn’t needed. But for the sake of learning, if you really needed to build a string, take advantage of variable expansion. Here I will need to use a sub-expression.

But in the example of bad code ,instead of manually creating a CSV file, PowerShell can do that for you with Export-CSV.  In the code sample, the header is different than the property names, but that’s OK. We can use a hashtable with Select-Object and create something new.

The original code used text parsing to get the file extension. But if you pipe a file object to Get-Member, you would discover there is a property called Extension. When building scripts, pipe objects to Get-Member or Select-Object with all properties to discover what you have to work with. The original code is written with the assumption that the CSV file will be used outside of PowerShell. If that is the case, then export it without type information. But if you think you will import the data back into PowerShell, include the type information because it will help PowerShell reconstruct the objects. You would learn all of this by looking at help and examples for Export-CSV.

The example above is technically a one-line command. But it doesn’t have to be. It might make more sense to break things up into discrete steps.

This code is sort of a compromise and isn’t too difficult to follow, even if you are new to PowerShell. This would give you the same result.

Sometimes using the ForEach enumerator is faster than using ForEach-Object in a pipeline. You have to test with Measure-Command. If you are running PowerShell v4, you can take advantage of the new Where() method which can dramatically improve performance.

By now I hope you can see how this code is taking advantage of cmdlets and the pipeline. For example, Export-CSV has a –NoClobber parameter which prevents you from overwriting an existing file. You can’t do that with legacy redirection operators like > and >> without additional commands.

The final step with my scary code, which now isn’t quite so scary I hope, is to turn this into something re-usable. If you put the above into a script as-is, you would have to edit the file every time you wanted to check a different folder or export to a different file. This is where we can turn it from a pumpkin into a fantastic carriage, that won’t revert at midnight.

This function gives me a flexible tool. All I need to do is specify a path, although it defaults to the current directory, and some sort of filtering script block. The default is to display everything. Now I can run a command \ like this:

You’ll notice that my function doesn’t export anything to a CSV file. Of course not. The function’s only purpose is to get files and display a subset of properties. Because the function writes to the pipeline I can do whatever I need. Perhaps today I need to export to a CSV file but tomorrow I want to create formatted table saved to a text file.

I hope PowerShell in general doesn’t frighten you. As the saying goes, we fear that which we don’t understand. But once you understand some basic PowerShell principals and concepts I think you’ll find it not quite as terrifying.

What scary PowerShell have you come across

Friday Fun – Take a Chance with PowerShell

Last week I showed you my PowerShell Bingo game. While the game itself might be a fun way to pass the time, the real goal was to teach you some PowerShell techniques and concepts without you realizing it. This week, I thought I’d keep with the gaming theme and take up chance. Specifically let’s roll some dice and flip some coins. These aren’t especially complicated tasks in PowerShell, and it is hard to say what problem they might solve, but let’s have some fun anyway.

First up, flipping coins.

Flipping a coin is essentially a True/False game. Or another way to look at is Even/Odd. My favorite way is to use the modulo operator.

Those values can be represented as Booleans.

So all I need is a random number and perform a modulo operation. Here’s the function I created.

I used a valid verb but will also define a more user-friendly alias.

Because you may want several different types of output, not necessarily the best idea for a function but this might be an exception. And remember this is supposed to be educational not necessarily practical. My function uses parameter sets and depending on the set, decides what type of result to write to the pipeline.

And it seems to work pretty well.

Next, let’s roll some dice. Again I’ll use Get-Random . A single dice roll is as simple as this:

To roll multiple dice, you could do this:

Naturally I wrote a function with a few more bells and whistles because I like shiny toys.

This function lets you choose the number of dice to roll. Notice I use a ValidateRange attribute to limit the number of dice. And in case you are rolling for a game of Dungeons and Dragons which has some extra-sided dice, I gave you that option as well.

In some games, you need the total so I added that as well. One thing that I changed was my rolling technique. In this version I am pre-generating an array of all possible values and then get the specified number of random values.

Not that it is super critical, but this technique is faster.

Here’s the result

If you are debating between different techniques in a script or function, use Measure-Command to see how they perform.

Now you have some tools to build your own PowerShell games and maybe learn something new in the process. If you do, I hope you’ll share. Enjoy!

PowerShell Dates, Times and Formats

astroclock_thumbIf you are like me you use date time values constantly in PowerShell. From simply displaying the current date and time in progress message to using different values to create file or folder names. The Get-Date cmdlet has a -Format parameter which you can use. The tricky part is remembering what values to specify. Especially because they are case-sensitive. The values are documented at http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo%28VS.85%29.aspx.

So to make my life (and maybe yours) easier, I wrote a little PowerShell script to remind me of the possible values.

The variable $patterns is an array of commonly used datetime format values. Many of them were pulled from that MSDN page but I added some of my own at the end. Here’s the output from this script.
test-datetimepattern01

This looks nice, and is definitely a nice cheat sheet. But then I realized since I’m writing a script I should take this to the next level and write a useful object to the pipeline.

This version creates a custom object for each pattern, including the syntax.
test-datetimepattern02

An alternative to -Format is to use the ToStringMethod() specifying the format pattern.

Because this is an object I can pipe it to other cmdlets.

test-datetimepattern03

I included the syntax so all you need to do is copy and paste. Or, how about this?

Define this function in the PowerShell ISE, perhaps even adding it to your Add-Ons menu with a keyboard shortcut. When executed, you’ll get a graphical display using Out-Gridview.

test-datetimepattern04

Select a pattern and the syntax gets pasted into your PowerShell script. I love making PowerShell do my work for me! Enjoy.

Advice, solutions, tips and more for the lonely Windows administrator with too much to do and not enough time.

%d bloggers like this: