Sounds of the Holidays–Part 1


Summary: MVP, Thomas Rayner, inspires holiday spirit by using Windows PowerShell to trigger some multimedia.

Hello! I’m Thomas Rayner, a proud Cloud & Datacenter Management Microsoft MVP, filling in for the Scripting Guy for a couple days. You can find me on Twitter (@MrThomasRayner), or posting biweekly on my blog, WorkingSysadmin: Figuring stuff out at work. I’m enjoying some time off from work this holiday season by playing around with some of the multimedia resources that come with Windows.

Do you have a coworker who you wish was a little more festive? I do. His name is Matthew, and I’m going to inspire him with some nice holiday messages. All I need is a few lines of PowerShell. 

Windows has a text-to-speech utility built-in to it. The details of how exactly it works aren’t really important to me. What I want to do is add the assembly that lets me interact with it via PowerShell:

Add-Type -AssemblyName System.Speech 

So far, so good. I’ve added the System.Speech assembly. That by itself doesn’t do anything other than enable me to access that assembly. What I need to do now is create a new SpeechSynthesizer object:

$synth = New-Object -TypeName System.Speech.Synthesis.SpeechSynthesizer 

Now I’ve got a new SpeechSynthesizer named $synth. If you use the Get-Member cmdlet on $synth, you’ll see that it does all kinds of neat things, such as allow you to change the voice, output to different audio streams, and output to a .wav file. Most importantly, $synth has a method called Speak which takes a string, for example.

$synth.Speak(‘Hello world’) 

You might need to be a bit patient. It can take a little time for the SpeechSynthesizer to turn your string into audio output, but you should hear the Windows text-to-speech engine speak the words you specified. Pretty cool!

All I need to do is execute the code on Matthew’s computer instead of mine and replace the message with something more likely to inspire some holiday spirit. That’s as easy as using Invoke-Command. My script now looks like this:

$Computer = ‘Matthew-Computer’

Invoke-Command -ScriptBlock {

    Add-Type -AssemblyName System.Speech

    $synth = New-Object -TypeName System.Speech.Synthesis.SpeechSynthesizer

    $synth.Speak(‘Matthew, this is Ebenezer Script. I am calling to make sure you have been a good little boy this year.’)

} -ComputerName $Computer 

That’s it! I could, however, take this a bit further and send Matthew more messages:

$Computer = ‘Matthew-Computer’

$MessageCount = 0

$Messages = @(‘Matthew, this is Ebenezer Script. I am calling to make sure you have been a good little boy this year’, ‘Matthew, you are going to get coal in your stocking if you are not a good boy.’,’Ebenezer script to Matthew. Come in Matthew. Please advise your good-boy status. Only good boys get gifts from Ebenezer Script.’)

while ($MessageCount -lt 100)

{

    Invoke-Command -ScriptBlock {

        Add-Type -AssemblyName System.Speech

        $synth = New-Object -TypeName System.Speech.Synthesis.SpeechSynthesizer

        $synth.Speak($(Get-Random $Messages))

    } -ComputerName $Computer

    $MessageCount++

    Start-Sleep -Seconds $(Get-Random -Minimum 60 -Maximum 180)

Now Matthew will get one of three random holiday messages every 60 to 180 seconds until 100 messages have been sent. He’s definitely going to be in the holiday spirit after this!

~Thomas

Thanks, Thomas! Matthew is a lucky guy!

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Comments (2)

  1. Alexander says:

    Copying this line for line, the random speech vocalises the random number and not the string value in the array. I’m running WMF 5.0, was the processing made different? If I were to run "Get-Random $Messages" by itself the result is as expect and I receive
    a random string from the array. Only when it’s processed in the Speak method do I find issues.

    Any suggestions or help will be appreciated. I will try this on a lower version of PowerShell when I get to my office, and post the details if it’s different.

  2. Alexander says:

    RE: having the $Message array within the Invoke-Command scriptblock resolves this issue.

Skip to main content