Let’s face it.  Sometimes scripts take a while to run.   Often I have a lower end client sitting in the back of my office specifically for executing schedule scripts or scripts that will run for a long period of time.  Normally I have the scripts email me once they have completed and I simply run Receive-job to collect the data. 
I developed this cmdlet as a fun way of demonstrating passing input via the pipeline into a cmdlet. It gives you the opportunity to have PowerShell talk to you. Maybe to alert you that a threshold has been exceeded or to let you know that a workflow has completed. In any case, have some fun with. Remember its intent was to act as a demonstration of parameter passing. Look carefully and you will see examples of passing parameters ByValue and ByPropertyName.
 
Lines 6-7 allow the parameter $VoiceMessage to pass information ByValue and ByProperty name. This string is what Windows will read back to you. By having ByPropertyName, this allows you to add a “VoiceMessage” property to your objects should you need a verbal message given.
Lines 9-11 allow you to choose the voice that you want to use. There are three built in voices. Advanced parameterization using the ValidateSet attribute allows you to provide TAB completion of this parameter.
The PassThru and InputObject parameters allows the original object piped to this cmdlet to continue in the pipeline.
Lines 16-21 executes when the pipeline first starts. The Begin block will create an object of Windows Text-To-speech capabilities into PowerShell and allow you to use it.
Lines 23-26 runs for each object passed to this cmdlet. Should multiple lines of messages be passed to the cmdlet, a ForEach loop will handle them.
Line 30 test to make sure that this code is running on Windows 8. The code was only tested on Windows 8. To test on other platforms, change *Windows 8* to *.
Lines 32-39 collect the different voice objects.
Lines 43-48 set the voice based on the VoiceType parameter. US_Male is the default.
Line 51 executes the Speak method and reads the text to the user.
Lines 55-61 is the END block. it will only execute once after all elements in the upstream pipeline have been exhausted. If the PassThru parameter has been specified, then the original object is passed through the pipeline.
I developed this cmdlet as a fun way of demonstrating passing input via the pipeline into a cmdlet. It gives you the opportunity to have PowerShell talk to you. Maybe to alert you that a threshold has been exceeded or to let you know that a workflow has completed. In any case, have some fun with. Remember its intent was to act as a demonstration of parameter passing. Look carefully and you will see examples of passing parameters ByValue and ByPropertyName.
| 
1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 | 
Function Out-Voice 
{ 
[cmdletBinding()] 
Param  
( 
    [parameter(ValueFromPipeline=$True, 
               ValueFromPipelineByPropertyName=$True)] 
               [String]$VoiceMessage, 
    [parameter(ValueFromPipelineByPropertyName=$True)] 
    [ValidateSet("US_Male","UK_Female","US_Female")]            
               [String]$VoiceType, 
               [Switch]$PassThru, 
    [parameter(ValueFromPipeline=$True)] 
               [PSObject]$InputObject           
) 
    BEGIN  
    { 
        # When the cmdlet starts, create a new 
        # SAPI voice object. 
        $voice = New-Object -com SAPI.SpVoice 
    } 
    PROCESS 
    { 
        # If an array of messages is passed, this will allow 
        # for each message to be read. 
        ForEach ($M in $VoiceMessage) 
        { 
            # If the client is Windows 8, then allow for different voices. 
            If ((Get-CimInstance -ClassName Win32_Operatingsystem).Name -Like "*Windows 8*") 
            {               
                # Get a list of all voices. 
                $Voice.GetVoices() | Out-Null 
                $voices = $Voice.GetVoices(); 
                $V = @() 
                ForEach ($Item in $Voices) 
                { 
                    $V += $Item 
                }                    
                # Set the voice to use using the $VoiceType parameter. 
                # The defualt voice will be used otherwise. 
                Switch ($VoiceType) 
                { 
                    "US_Male" {$Voice.Voice = $V[0]} 
                    "UK_Female" {$Voice.Voice = $V[1]} 
                    "US_Female" {$Voice.Voice = $V[2]} 
                } 
            } # End: IF Statment. 
            # Speak the message. 
            $voice.Speak($M) | Out-Null 
        } 
    } # End: ForEach ($M in $VoiceMessage) 
    END 
    { 
        If ($PassThru) 
        { 
            Write-Output $InputObject 
        } 
    } #End: PROCESS 
<# 
.SYNOPSIS 
Reads a message to the user. 
.DESCRIPTION 
Uses the default voice of the client to read a message 
to the user. 
.PARAMETER Message 
The string of text to read. 
.PARAMETER VoiceType 
Allows for the default choice to be changed using the  
default voices installed on Windows 8. Acceptable values are: 
US_Male 
UK_Female 
US_Female 
.PARAMETER PassThru 
Passes the piped in object to the pipeline. 
.EXAMPLE 
Out-Voice "Script Complete" 
Reads back to the user "Script Complete" 
.EXAMPLE 
$CustomObject | Out-Voice -PassThru 
If the object has a property called "VoiceMessage" and is of 
data type [STRING], then the string is read.  If the object 
contains a "VoiceType" parameter that is valid, that 
voice will be used. The original object is then passed  
into the pipeline. 
.EXAMPLE 
Get-WmiObject Win32_Product |  
ForEach -process {Write-Output $_} -end{Out-Voice -VoiceMessage "Script Completed"} 
Recovers the product information from WMI and the notifies the 
user with the voice message "Script Completed" while also 
passing the results to the pipeline. 
.EXAMPLE 
Start-Job -ScriptBlock {Get-WmiObject WIn32_Product} -Name GetProducts 
While ((Get-job -Name GetProducts).State -ne "Completed") 
{ 
    Start-sleep -Milliseconds 500 
} 
Out-Voice -VoiceMessage "Done" 
Notifies the user when a background job has completed. 
.NOTES 
Tested on Windows 8 
+-------------------------------------------------------------+ 
| Copyright 2013 MCTExpert, Inc. All Rights Reserved          | 
| User takes full responsibility for the execution of this    | 
| and all other code.                                         | 
+-------------------------------------------------------------+  
#> 
} # End: Out-Voice  | 
Lines 6-7 allow the parameter $VoiceMessage to pass information ByValue and ByProperty name. This string is what Windows will read back to you. By having ByPropertyName, this allows you to add a “VoiceMessage” property to your objects should you need a verbal message given.
Lines 9-11 allow you to choose the voice that you want to use. There are three built in voices. Advanced parameterization using the ValidateSet attribute allows you to provide TAB completion of this parameter.
The PassThru and InputObject parameters allows the original object piped to this cmdlet to continue in the pipeline.
Lines 16-21 executes when the pipeline first starts. The Begin block will create an object of Windows Text-To-speech capabilities into PowerShell and allow you to use it.
Lines 23-26 runs for each object passed to this cmdlet. Should multiple lines of messages be passed to the cmdlet, a ForEach loop will handle them.
Line 30 test to make sure that this code is running on Windows 8. The code was only tested on Windows 8. To test on other platforms, change *Windows 8* to *.
Lines 32-39 collect the different voice objects.
Lines 43-48 set the voice based on the VoiceType parameter. US_Male is the default.
Line 51 executes the Speak method and reads the text to the user.
Lines 55-61 is the END block. it will only execute once after all elements in the upstream pipeline have been exhausted. If the PassThru parameter has been specified, then the original object is passed through the pipeline.
Comments