Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Friday Fun: Improved PowerShell Napping

Posted on January 29, 2016

So I had some fun with my post last week on taking a nap with PowerShell. I got some great feedback on Twitter and a new comments on the blog. My initial effort was a relatively simple PowerShell script which certainly got the job done. But I there were a number of areas where I could expand and improve the script and they would be terrific teaching aids. So I did.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

The function is defined in a script you can find in Github.

Let's look at some of the changes I made. First off, I turned this into a function complete with comment based help. You'll need to dot source the script file into your PowerShell session or profile script to make the command available.

I made just about every option a parameter and added a few parameter aliases as well. So even though I made the Minutes parameter positional so that you don't need to use the parameter name, you could use –Nap or –Time. You'll notice I also made the wakeup message a parameter.  Feel free to set your own default value. Otherwise, you can set a different message at different times.

I also realized that if you are napping, someone might still drop by your desk. So I included an option to display a progress bar using Write-Progress. This is a cmdlet that doesn't get the love it should.

I defined an array of messages:

#an array of status messages if using a progress bar
$ops = "I'm solving a PowerShell problem","I'm chasing cmdlets",
"Brilliance at work","Re-initializing my pipeline",
"Go away","I'm checking eyelid integrity","It can wait...",
"Don't you dare!","Spawning a new runspace","I'm multitasking",
"Nothing is that important","Unless you have beer for me, go away",
"I'm testing the new PSNap provider","I need this",
"I'm downloading my new matrix","Resource recyling in progress",
"Synaptic synch in progress","Neural network rebooting",
"If you can read this you shouldn't be here",
"$($env:username) has left the building"

The messages will be used as the Status property for Write-Progress. I like using a hashtable of parameters to splat when using Write-Progress.

$progHash = @{
 Activity = "Ssssshhh..."
 Status = $ops[0]
 SecondsRemaining = $remainingSeconds
}

If I use the Progress bar, it is displayed using the seconds remaining.

if ($ProgressBar ) {
    Write-Progress @proghash
    #tick down $remainingseconds
    $proghash.SecondsRemaining = $remainingSeconds--
    #pick a new random status if remaining seconds is divisible by 10
    if ($remainingSeconds/10 -is [int]) {
        $proghash.status = $ops | Get-Random
    }
} #if

And every 10 seconds I set the status to another randomly selected message. The result is something like this:

image

The last major change I made per a suggestion was to use the text to speech feature to have a Windows voice "say" the wake up message. I added a parameter for you to specify a voice name which in the US will most likely be David or Zira.  If you don't know the names, you can specify a bogus value like 'foo' and the function will display the available names. This works because I added a validation script to the Voice parameter.

[ValidateScript({
 #get voices
 Add-Type -AssemblyName System.speech
 $installed = [System.Speech.Synthesis.SpeechSynthesizer]::new().GetInstalledVoices().voiceinfo.Name
 if ($installed -match $_ ) {
    $True
 }
 else {
    [regex]$rx= "Microsoft\s+(?\w+)\s+"
    #build a list of voices assuming the voice name is something like Microsoft David Desktop
    $choices = (($rx.Matches($installed)).foreach({$_.groups["name"].value})) -join ","
    Throw "Can't find an installed voice for $_. Possible values are: $choices"
 }

})]
[Parameter(ParameterSetName = "voice")]
[string]$Voice,

This is probably a bit more involved than most validation scripts.  The main takeaway is that if you use a validation script it has to return either True or False, or throw an exception as I'm doing here. But it works.

image

By adding a voice option I decided the function could either display the message using Write-Host or speak it. The chime happens in either event.

If ($Voice) {
    Add-Type -AssemblyName System.speech
    $speech = New-Object System.Speech.Synthesis.SpeechSynthesizer
    #find the matching voice object
    $selected = [System.Speech.Synthesis.SpeechSynthesizer]::new().GetInstalledVoices().voiceinfo.Name | where {$_ -match $voice}
    $speech.SelectVoice($selected)
    $speech.Rate = $Rate
    $speech.SpeakAsync($message) | Out-Null
    #write a blank line to get a new prompt
    Write-Host "`n"
}
else {
    Write-Host "`n$Message" -ForegroundColor Yellow
}

What this meant was that I had to differentiate the parameters which I did with parameter sets.  I specified the default in the cmdletbinding attribute.

[cmdletbinding(DefaultParameterSetName = "host")]

Then I needed to specify a parameter set name for each parameter.  If you don't specify parameter set name, then the parameter will belong to all sets.  Or you can do as I did and be explicit. If you do it properly it should be reflected in the help.

image

You can see that there are 2 ways to use this command. I'll let you grab a copy and try out the new additions.

Certainly this isn't a production oriented script but I hope it serves up some interesting examples of different scripting techniques and cmdlets.

As always, comments sincerely welcomed.

Enjoy!


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

2 thoughts on “Friday Fun: Improved PowerShell Napping”

  1. Marco Janse says:
    January 30, 2016 at 3:24 pm

    Hilarious script, but also very clever and lots of new things for me to discover. Thanks for sharing

    1. Jeffery Hicks says:
      January 31, 2016 at 10:59 am

      Thanks. These types of articles are intended to be fun and entertaining and even teach a few things without you realizing it!

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d