Last month, in “Using PowerShell Object Methods,” I started exploring methods in PowerShell cmdlets. This month, I’ll go further with methods by showing you how to make PowerShell speak to you.
In that previous article, I started out with the simple Get-Date cmdlet, which returns the current date and time. Piping that cmdlet into Get-Member shows that the data returned from Get-Date isn’t a simple string of characters but rather an object of type datetime, as you see here:
PS C:\> get-date | get-member TypeName: System.DateTime
That’s just the first line of the Get-Member output, and note that Get-Member reports its type (TypeName) in two or more pieces—System and DateTime in this example. People usually refer to a TypeName by its rightmost part, so you would call it a DateTime object rather than a System.DateTime object.
Run that command on your computer, and you’ll see a bunch of methods under the initial TypeName: System.DateTime line, including the AddHours and AddDays methods that you saw last time. Remember that to call an object’s method, you add a period, then a method name, and a pair of parentheses to hold whatever value you’re passing the method, as in
which would show the current date with 4 minutes added to it. Some methods don’t need any values passed to them, but you have to type the parentheses anyway. For example, Get-Date will produce a shortened date if you invoke the ToShortTimeString method:
PS C:\> (get-date).ToShortTimestring() 11:08 AM
Let’s take this a little further with a different method example. If you have Windows 7 or later, your system contains a speech synthesizer, and the .NET runtime on your system has a set of classes that let you control the synthesizer. Type these two lines to create an object called $talker built from those classes:
Add-Type -AssemblyName System.speech $talker = New-Object System.Speech.Synthesis.SpeechSynthesizer
Those two lines are quite interesting because .NET—which so many PowerShell cmdlets are built upon—includes a class that lets your PC speak. Unfortunately, though, no one has ever created a built-in cmdlet with a name such as speak-text. Thankfully, the Add-Type and New-Object cmdlets will let you essentially create your own PowerShell access to your system’s speech synthesizer.
Now, I know you can’t wait to hear your system speak, so try this:
Clearly, an object of type System.Speech.Synthesis.SpeechSynthesizer—or SpeechSynthesizer to you and me—includes a method named speak that can be fed text that it will “speak.” But what more can it do? Here again, Get-Member is invaluable, particularly when using PowerShell to explore some .NET class that currently lacks cmdlets. Run
$talker | get-member
To display a couple dozen methods. GetInstalledVoices() sounds interesting. What does it contain? What can it do? Start exploring by typing
which returned (on my Windows 8.1 system) only three lines of System.Speech.Synthesis.VoiceInfo. That’s not very helpful, but try using Get-Member again to show not the members and properties of the SpeechSynthesizer object but instead the System.Speech.Synthesis.VoiceInfo object. Do it like this:
$talker.GetInstalledVoices() | Get-Member
That displays two properties: Enabled and VoiceInfo. So try Voiceinfo, which you can do by adding a period and voiceinfo to the rest of the previous query:
Notice that you get one member (a method) of $talker with .GetInstalledVoices() and then a member (a property) of that! The result of that query is a bit more interesting as it dumps out information for all of the voices in the system. My system has three voices, named David, Zira, and Hazel. Continuing your “dot” exploration of $talker’s structure by adding “.name,” if you type
you’ll see a nice, clean list of just the names. Again, look at how that works: Typing $talker retrieves the synthesizer object, .GetInstalledVoices(). Adding a method of GetInstalledVoices().voiceinfo retrieves the voiceinfo for the result from GetInstalledVoices(), and the .name extracts just the name from the voiceinfo results. Each step along the way, you use Get-Member to reveal what each layer offers, so you can choose what to examine on the next level. (Of course, once you get to name, that’s as far as you can go.)
Oh, and one more thing: How did I know that GetInstalledVoices() didn’t need anything in its parentheses? I just tried it! That kind of experimentation usually works. But, in fact, GetInstalledVoices can take a parameter, and I found that out by poking around the .NET documentation—which I’ll explore next time.