Tag Archives: PowerShell

Friday Fun: A PowerShell Tickler

elmoI spend a lot of my day in the PowerShell console. As you might imagine, I often have a lot going on and sometimes it is a challenge to keep on top of everything. So I thought I could use PowerShell to help out. I created a PowerShell tickler system. Way back in the day a tickler system was something that would give you a reminder about an impending event or activity. What I decided I wanted was a tickler that would display whenever I started PowerShell.

This doesn’t replace my calendar and task list, but it let’s me see events I don’t want to miss right from PowerShell. As I worked through this idea I ended up with a PowerShell module, MyTickle.psm1, that has a number of functions to managing the tickle events, as I call them. From PowerShell I can get events, add, set and remove. I thought the module would make a good Friday Fun post because it certainly isn’t a high impact project but it offers some ideas on building a module and functions that I hope you’ll find useful.

The module for right now is a single file. Here’s the file and below I’ll talk about.

You should be able to copy the code from the WordPress plugin and paste it into a script file locally. You can call it whatever you want just remember to use a .psm1 file extension. The module uses some PowerShell 3.0 features like ordered hashtables but you could revise to have it run in PowerShell 2.0. Fundamentally it should work in both versions.

The events are stored in a CSV file that I reference with a module variable, $TicklePath. The default is a file called mytickler.csv which will be in your WindowsPowerShell folder under Documents. The module also defines a variable called $TickleDefaultDays, with a default value of 7. This displayed events to those that fall within that range. To use, I added these lines to my PowerShell profile.

The result, is that when I launch a new PowerShell session I see something like this (the message about help updates is from something else so disregard):
show-tickle

Here’s how it works.

The Show-TickleEvent function imports events from the CSV file that will happen within the next 7 days. Each object also gets an additional property that is a timespan object for how much time remains. The function then parses event information and constructs a “box” around the events.

I set a foreground color depending on how imminent the event is and then write each event to the console, wrapped in my border.

I purposely used Write-Host so that I could color code events and because I didn’t want the profile to write anything to the pipeline. Because the module is loaded at the start of my PowerShell session, I can always run Show-TickleEvent and event specify a different number of days. If I want objects, then I can use the Get-TickleEvent function which will import the csv events based on a criteria like ID or name. The function uses parameter sets and I create a filter scriptblock depending on the parameter set.

When I import the CSV file, I add types to the properties because otherwise everything would be a string, and then pipe each object to my filter.

These objects come in handy because they can be piped to Set-TickleEvent to modify values like event name, date or comment. Or I can pipe to Remove-TickleEvent to delete entries. The deletion process in essence finds all lines in the CSV file that don’t start with the correct id and creates a new file using the same name.

Finally, after accidentally wiping out event files, I added a simple backup function copies the CSV file to the same directory but with a .BAK file extension. You could specify an alternate path, but it defaults to the WindowsPowerShell folder.

Hopefully I won’t miss important events again, of course assuming I add them to my tickler file. I’ll let you play with Add-TickleEvent to see how that works or you could always modify the CSV file with Notepad.

If you actually use this, I hope you’ll let me know.

[Note: due to a limitation in the syntax plugin I use, I removed the comment characters around the help in each function. You will need to add them back.]

Test 64-Bit Operating System

One of the great features of PowerShell is how much you can get from a relatively simple one line command. For example. you might want to test if a computer is running a 64-bit operating system. You can find out with a command as simple as this.

If you are running PowerShell 3 you could substitute Get-CimInstance. One thing to be aware of with this particular class is that the OSArchitecture property isn’t valid on older operating systems like Windows Server 2003. You’ll get an exception.

osarchitecture-fail

In this case I modified the WMI query to only return the OSArchitecture property, which doesn’t exist. Otherwise I would just get false which might not be entirely true. Of course, I always get carried away so before I knew it I had turned this one line command into a function.

The function takes a computername and optionally a PSCredential. You can use a saved PSCredential object or specify the name and you will be prompted.

Test-Is64Bit-01
The other design element is that if there is an exception caught I have a Switch statement to checks the message and writes a custom warning.
Test-Is64Bit-02

There’s no reason you can’t use the one-liner. But if you want to add a bit more robustness and create a re-usable tool, it doesn’t take much to turn it into a simple function.

PowerShell Version Profiles

talkbubble One of the best things about PowerShell 3.0, for me anyway, is the ability to run PowerShell 2.0 side by side. I often need to test commands and scripts in both versions not only for my writing projects but also when helping people out. Like many of you I have a PowerShell profile script that configures my console. And because I primarily use PowerShell 3.0 I tend to have a number of version specific commands in my profile. The problem is that when I launch a PowerShell 2.0 session it uses the same profile, resulting in error messages for things it can’t do. So this is how I handle having a single profile that can be used by two different versions of PowerShell.

Basically, my profile script checks the version first, before doing anything. You can use the $psversiontable variable.

The PSVersion property is what I’m looking for. With this information, I can wrap my PowerShell profile script in simple IF statement.

I think the comments in the code sample are pretty clear and there’s really not much else to add. The Write-Host lines are merely for testing. You don’t really need them.

Now I can get properly configured PowerShell sessions regardless of version and without errors.

Scrub Up PowerShell Content

scrubbrush It is probably a safe bet to say that IT Pros store a lot of information in simple text files. There’s nothing with this. Notepad is ubiquitous and text files obviously easy to use. I bet you have text files of computer names, user names, service names, directories and probably a few that are unique to your company. Getting data out of these text files is very easy in PowerShell using Get-Content.

The potential problem is that the text file may not be perfectly formatted. Your text file might have blank lines. Or your computername may have a trailing white space. These things can complicate using the text file in a PowerShell pipelined expression. One approach is to filter the content using Where-Object and simply look for the existing of something.

This works fine in filtering out blank lines. But won’t fail if you have a line where someone inserted a tab or hit the space bar a few times. So let’s take this a bit further and use a regular expression to filter out anything that doesn’t have a non-whitespace character.

This should get rid of any lines that are nothing but tabs or spaces. Of course, there is still the issue of leading or trailing spaces. But we can handle that by using the string object’s Trim() method.

This is starting to get complicated. So I wrote a filtering function to scrub up content presumably from text files.

We don’t use the Filter keyword much anymore but it seemed appropriate because that is the only thing Scrub is doing. In fact, I intentionally did not use a traditional verb-noun name. Technically this an advanced function this is just a Process script block. I wrote it with the assumption that you would pipe strings from Get-Content.

Each processed string is filtered to get rid of blanks and spaces. Then each string is trimmed of leading and trailing spaces and finally written to the pipeline. Now I can run a command line this:

scrubexample1

In my initial versions this solved all of my potential problems with text files. But then I realize I had an opportunity to add one more scrubbing feature. Many cmdlets have parameters that take pipeline input by property name. But strings from text files lack a property name. So I added a parameter to my Scrub filter to add a property name.

Now I’m writing an object to the pipeline and can take advantage of pipeline binding.

scrubexample2

I don’t know about you, but this will come in very handy. I hope you’ll let me know what you think.

PowerShell Scripting Games 2013 Impressions

Now that the PowerShell Scripting Games for 2013 are well underway, I thought I’d share my thoughts and impressions on what I’ve seen. I’m very impressed with the number of entries and generally the quality is pretty good. But as a judge I see repeated items that bear comment. These comments are in no particular order of importance and in some cases are really a matter of personal preference.

If you are going to use Write-Host (and want to save puppies) to display informational or progress messages, please use one of the color parameters so that your message can be differentiated from your object output. Ideally for advanced events you should be using Write-Progress. Not sure we’ve had events that call for Write-Progress but keep it in mind.

I generally dislike entries that are clearly overwrought and over-thought. Sometimes the problem can be solved simply. Don’t feel you have to use every trick in the PowerShell play book in order to score points. I’m a big proponent of the right tool for the job. On a related note, if you can solve the challenge with a PowerShell one-liner, don’t feel you need to write it as a long single line command. Take advantage of PowerShell parsing. This is very hard to read:

I’d much rather see a one-liner formatted like this:

In full scripts, I’d like to see more use of #Requires -version X so that I can tell what features you might be using. Related to that, in advanced scripts if you are using a parameter attribute like Mandatory or ValueFromPipeline, v3 scripts should use them like this:

You don’t have to explicitly state that Mandatory is equal to True. Although in v2 you would need to do this:

Which brings me to another minor irk, an object that has a boolean value doesn’t need a comparison operator. The whole point of something like an IF statement is to evaluate if the expression in the parentheses is true or not. If the object is already a boolean, there’s no need.

I’m also not a big fan of creating custom objects with lots of Add-Member commands. I think this makes the code harder to read and doesn’t really buy you much. I think using a hashtable with New-Object is much easier to read and just as effective. Plus in v3 we can now have ordered hashtables and even use [pscustomobject].

Finally, be very careful of including formatting commands in your entries, unless the event specifically calls for it. This is especially true if you are writing a function. When you include formatting directives at the end of the function, it can’t be used anywhere else in a PowerShell expression.

Don’t get me wrong, there is a lot of good PowerShell which I’m happy to see:

  • Using Join-Path to build paths
  • Using Test-Path to validate
  • Plenty of internal comments
  • Using Test-Connection to verify computers are online
  • Meaningful variable names

So keep up the good work and on to the next event!

Getting Top Level Folder Report in PowerShell

One of the sessions I presented recently at TechDays San Francisco was on file share management with PowerShell. One of the scripts I demonstrated was for a function to get information for top level folders. This is the type of thing that could be handy to run say against the root of your shared users folder. Or the root of a group share where each subfolder is a share that belongs to a different group. My function takes advantage of a new feature for Get-ChildItem that makes it much easier to retrieve only file or directories. Here’s my Get-FolderSize function.

The function defaults to the local path and gets a collection of all of the top level folders, that is, those found directly in the root. The function then takes the collection of folders and pipes them to ForEach-Object. Most of the time we only use the Process scriptblock with ForEach-Object, but I want to take advantage of the Begin and End blocks as well. In the Begin scriptblock I measure all of the files in the root of the parent path and create a custom object that shows the number of files and total size in bytes. I’m going to get this same information for each child folder as well.

The process scriptblock does just that for each top level folder. This version of my function uses Write-Progress to display progress and in the End script block I have code to complete the progress bar, although It works just fine without it.

Other techniques I’d like to point out are the use of splatting and error handling. You’ll notice that I’m using the common -ErrorVariable parameter. After exploring the different types of exceptions I decided I could easily display any errors and the paths In the Catch block. I’m using Write-Warning, but this could just as easily be written to a text file.

The function writes an object like this for every folder.

Here’s an example of complete output:

foldersizeBecause I’ve written objects to the pipeline, I could pipe this to Out-Gridview, export to a CSV file or create an HTML report.

This is just a taste of what you can accomplish with some basic PowerShell commands.

 

PowerShell Messagebox

messageboxRecently I posted an article explaining how to create a popup box in PowerShell using the Wscript.Shell COM object from our VBScript days. That was something I presented at the PowerShell Summit. Another option is a MessageBox, again like we used to use in VBScript. This works very much like the popup except the user has to click a button to dismiss the box. I can’t think of a compelling reason why you would choose one technique over the other if you need the user to click something. But I’ll let you make that call. Here’s the function, New-Messagebox.

Most of the function is a wrapper around this line:

Like the popup function, I wanted to make it easier to create a messagebox without having to remember the names for buttons and icons so I use validation sets with my parameters. This makes it much easier to create a command like this in your script:

In the version I presented at the PowerShell Summit, the function did not write anything to the pipeline unless you used -Passthru. After thinking about it more, I realized the whole reason you are likely to use a MessageBox is to capture an interaction so I flipped the parameter and now it is -NoPassthru. Now, when the user clicks a button, the text value of that button is automatically written to the pipeline. If you include -NoPassthru you’ll get nothing. Here’s an example:

messagebox2

Because the messagebox writes text to the pipeline, it is a little easier to use than the Popup technique where you have to decode an integer value. In any event, you now have some options.

If you find this useful, I hope you’ll let me know.