Baby, It’s Cold Outside

I don’t know about your neck of the woods, but it is downright Arctic here. So I thought I’d polish up my PowerShell function to get weather data.

This function uses the Yahoo weather RSS feed for US locations. The function uses the Invoke-RestMethod to get an entry for a given zip code. I set my zip code as the default and suggest you do the same. You will need to modify the default value in the code above. Invoke-RestMethod gives me an XML document so it isn’t too difficult to pull out the values I want and construct a custom object. I even use some regular expression named captures to break out the location and time. So hopefully there are some good learning examples here.

Anyway, quite frigid here, and this is already 5 degrees warmer than when I got up.

weather

Hope you are staying warm.

Friday Fun: Read Me a Story

announcer A few days ago, someone on Twitter humorously lamented the fact that I expected them to actually read a blog post. After the laughter subsided I thought, well why does he have to? Perhaps I can make it easier for him. Plus I needed something fun for today. So I put together a PowerShell function I call Invoke-BlogReader which I think you’ll have fun playing with. It isn’t 100% perfect and as with most Friday Fun posts, serves more as an educational device than anything.

The function uses the .NET System.Speech class which seems to be a bit easier to use than legacy COM alternative. Here’s a snippet you can test.

So basically, all I have to do is get the contents of a blog article and pass the text to the voice object. That is a bit easier said than done which you’ll see as you look through this code.

The function uses the Invoke-WebRequest cmdlet to retrieve the content from the specified web page and I then parse the HTML looking for the content.

This is the trickiest part because different blogs and sites use different tags and classes. There is a getElementsbyClassName method, but that seems to be hit and miss for me, so I’ve opted for the slower but consistent process of using Where-Object.

Once I have the content, I could simply pass the text, but I realized I may not want to listen to the entire post. Especially for my own which often have script samples. Those aren’t very pleasant to listen to. So I realized I needed to parse the content into sentences. Regular expressions to the rescue.

Don’t ask me to explain the regex pattern. I “found” it and it works. That’s all that matters. $Sentences is an array of regex match objects. All I need to do is pass the value from each match to the voice object. The other benefit is that I can include a parameter to also display the text as it is being read.

That’s all there is to it! If you want to try out all of the options here’s a sample command:

Where this can get really fun is using another function, which I’m not sure I ever posted here, to get items from an RSS feed.

Putting it all together you can get the feed, pipe it to Out-Gridview, select one and have the blog read to you!

So now you can have your blog and listen to! There are probably a number of ways this could be enhanced. Or perhaps you want to take some of these concepts and techniques in another direction. If so, I hope you’ll let me know where you end up. Have a great weekend.

Pimp your Prompt

bling2If you are like me and live in PowerShell, then you spend a great deal of your day looking at your PowerShell prompt. That little indicator in the console and ISE that usually shows where you are. That little part of your PowerShell world is defined by a built-in function called Prompt. You can easily see the function like this:

This prompt is from PowerShell v4 but I’m pretty sure it is the same function that was used in v3. PowerShell v2 has a different function.

Did you notice that the newer function has a help link? Try it:

help prompt -online

You’ll get the online version of the about_prompts help topic. The great thing about the prompt function is that you can change it. I’ve posted a variety of prompts over the years. But here are 4 more for you to try out. These prompts should work in v3 and later. Most of the functions are simple additions to the standard prompt and should work for both the console and ISE. To try out the prompt you can paste the function into your PowerShell session. To make it “permanent”, insert it into your PowerShell profile script.

Include PowerShell Version

This prompt inserts the PowerShell major version into your prompt.
version-prompt

Include Admin

This prompt will test if you are running as Admin and if so, it inserts [ADMIN] in red text.
adminprompt

Include Computername

Do you like how a remoting session shows you the computer you are connected to? Why not have that all the time? All I’ve done is insert the local computername from the Computername environmental variable.

computername-prompt

Auto Export Command History

This last version serves up a twist on transcription. When you run a transcript you get the command and results. But maybe all you want is a record of all the commands you ran. Sure, you could export command history at the end of your session, but you have to remember to do so and if you exceed your maximum history count, you’ll miss commands. In this prompt, everytime you hit enter, it gets the last command you ran and appends it to a log file. The log file is created in your PowerShell directory and uses the naming format of the PowerShell host, without spaces, a time stamp (YearMonthDay) and the process ID of the current PowerShell session. This allows you to keep multiple PowerShell sessions with separate logs. The log file will only record the command if it is different than the last one you ran. This also allows you to hit Enter without doing anything and not fill up your log.

If you temporarily paste in one of these Prompt functions, but don’t like it, you can simply restart PowerShell to get your original prompt. Or you can use this function to restore it.

This is handy to put into your PowerShell profile if you are experimenting with prompts. The Restore-Prompt simply defines a new Prompt function in the global scope. I’m using the default PowerShell prompt but you change it to whatever you wanted.

If you are doing something cool with your prompt, I hope you’ll share.

Friday Fun: A Random PowerShell Console

crayonsThis week I thought we’d have a little fun with the PowerShell console and maybe pick up a few scripting techniques along the way. Today I have a function that changes the foreground and background colors of your PowerShell console to random values. But because you might want to go back to your original settings without completing restarting PowerShell the function allows you to reset to your original values. Oh, and it also supports -Whatif. Here’s what I came up with.

The function will not work properly in the PowerShell ISE so I’ve included some code at the beginning to see if it is running in the ISE. If so, the command displays a warning and bails out. This is a scenario where using Return is completely acceptable as I want to return out of the pipeline without doing anything. I could have used a command like this: Return “This command only works in the PowerShell console.” but that would have written a string object to the pipeline and I don’t want anything to go to the pipeline. Plus, I prefer to use Write-Warning for messages like this.

When you run the command, it tests for the existence of some variables, $savedfg and $savedbg, that are defined in the global scope. You’ll notice the use of the global: prefix. If they are not defined, then the assumption is that this is the first time the command has been run and the variables will be defined with the current values of the $host.ui.rawui.foregroundcolor and $host.ui.rawui.backgroundcolor values. Later, if you use -Reset, the command will use these values to restore your original settings.

Otherwise, the command gets a random color for the System.ConsoleColor enumeration for the background and then another random color for the foreground, that is different than the randomly selected background color.

When you look at the code, you will see that I am specifying in the cmdletbinding attribute that the function supports ShouldProcess. That could also be written [cmdletbinding(SupportsShouldProcess=$True)] but that seems redundant to me. Anyway, the command to make the change, $host.ui.rawui.backgroundcolor= $bg, by itself doesn’t know anything about ShouldProcess and -WhatIf. But I can add my own code using an If statement.

The value for the ShouldProcess() method is the text you see as part of the “…performing operation on target…” message. The text is the target.
set-randomconsol-whatif

All I’ve done is define a variable, $msg, to make the line of code easier to read. As you can see, it is not that difficult to add your own support for -WhatIf. And now, if you get a little bored, mix it up for a fresh perspective. I’ve even included an alias, src, in case you have to type in a console where you can’t see what you’re typing.

Have a terrific weekend.

More PowerShell Laziness

lightbulb-ideaA few days ago I posted an article on using Update-TypeData to provide shortcuts to object properties. These shortcuts might save a few keystrokes typing, especially if you use tab completion. They can also give you more meaningful output. But you can take this even further and save yourself even more typing. How many of you have struggled to type an expression like this:

If you read the last article, you already know that I can use my alias property shortcuts. But you can also define other types of properties. Let’s say I often want to get file sizes in KB, and it is pretty tedious having to use Select-Object all the time with a custom hashtable. Instead I can do this with Update-TypeData:

When defining a ScriptProperty, the $this variable is used instead of $_. Using my previously created aliases, my command is now much easier to write:

With the aliases I can use them anywhere in a PowerShell expression. Let me leave you with one more example:

I often need to get the total value of something, but often I need it in a different format such as MB or GB. Now I have it.

That definitely saves some typing. I should probably do something similar for Maximum and Minimum properties as well.

So, what are you constantly typing? Is it something you could be smarter about? I hope you’ll share so I can take advantage of your laziness, I mean, efficiency!