
This post is part of my grok-posh series describing why developers should learn PowerShell.
A PowerShell console is basically an doorway into the entire realm that is .NET, COM, and WMI. As I say in my talks – you can think of PowerShell as an interactive way to discover, obtain, and manipulate objects.
This makes it a great place to explore the things you can do and to learn about these objects by manipulating them.
Here’s a great example - the other day @shaylevy posted this little gem on twitter:
$error | % { (New-Object -ComObject SAPI.SPVoice).Speak($_.Message) }
Shay’s code is using the Microsoft Speech API to have the computer “read” the error message(s) raised by the last PowerShell command executed. Slick.
I’ve never played with the Speech API. Let’s see how I can use PowerShell to interactively learn what I can do with this object:
1 PS > $voice = New-Object -ComObject SAPI.SPVoice
2 PS > $voice | get-member
3
4
5 TypeName: System.__ComObject#{269316d8-57bd-11d2-9eee-00c04f797396}
6
7 Name MemberType Definition
8 ---- ---------- ----------
9 DisplayUI Method void DisplayUI (int, string, string, Variant)
10 GetAudioOutputs Method ISpeechObjectTokens GetAudioOutputs (string, string)
11 GetVoices Method ISpeechObjectTokens GetVoices (string, string)
12 IsUISupported Method bool IsUISupported (string, Variant)
13 Pause Method void Pause ()
14 Resume Method void Resume ()
15 Skip Method int Skip (string, int)
16 Speak Method int Speak (string, SpeechVoiceSpeakFlags)
17 SpeakCompleteEvent Method int SpeakCompleteEvent ()
18 SpeakStream Method int SpeakStream (ISpeechBaseStream, SpeechVoiceSpeakFlags)
19 WaitUntilDone Method bool WaitUntilDone (int)
20 AlertBoundary Property SpeechVoiceEvents AlertBoundary () {get} {set}
21 AllowAudioOutputFormatChangesOnNextSet Property bool AllowAudioOutputFormatChangesOnNextSet () {get} {set}
22 AudioOutput Property ISpeechObjectToken AudioOutput () {get} {set by ref}
23 AudioOutputStream Property ISpeechBaseStream AudioOutputStream () {get} {set by ref}
24 EventInterests Property SpeechVoiceEvents EventInterests () {get} {set}
25 Priority Property SpeechVoicePriority Priority () {get} {set}
26 Rate Property int Rate () {get} {set}
27 Status Property ISpeechVoiceStatus Status () {get}
28 SynchronousSpeakTimeout Property int SynchronousSpeakTimeout () {get} {set}
29 Voice Property ISpeechObjectToken Voice () {get} {set by ref}
30 Volume Property int Volume () {get} {set}
31
Line 1 creates a new instance of the SAPI.SPVoice object in the shell variable $voice. Line 2 passes the $voice variable to the get-member cmdlet, which outputs all the methods and properties that the COM object supports.
Lots of opaque methods there – some UI elements it looks like, some asynchronous hooks. Looks like we can change the rate at which the speech is spoken, the volume, oooohhh – looks like there are other voice options too! Let’s see what voices we have available:
PS > $voice.GetVoices()
Id DataKey Category
-- ------- --------
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Token... System.__ComObject System.__ComObject
Aw, sad trombone … we have only one voice available. Hey, what’s it sound like anyway?
PS > $voice.Speak( 'Hello Beef!' )
Hello yourself! Not bad. What does that Rate property do?
PS > $voice.Rate
0
PS > $voice.Rate = 5
PS > $voice.Speak( 'The build has failed!' )
1
PS > # oh dear, that has the potential to raise my stress level
PS > # let's try to get more of a southern drawl going...
PS > $voice.Rate = -5
PS > $voice.Speak( 'Oh no! The build, she has failed!' )
1
PS > # now that's more like it!
Neat. As much fun as I’m having, I’m learning a bit about the Speech API. PowerShell allows me to interact with the object, trying things out and testing theories. Will I eventually need to turn to MSDN if I want to do anything serious? Probably. But consider what I’ve learned so far using nothing but PowerShell for about 60 seconds:
- I know the methods and properties exposed by the Speech API voice object;
- I know that voices are somehow linked to my registry, and the API suggests that it’s possible to install and remove voices, or create my own;
- Based on the methods of the voice object, I can assume there is a way to have the API generate speech asynchronously;
- I can manipulate the properties of a voice to my liking. In fact, using PowerShell I can get immediate feedback on what the voice sounds like.
You can generalize this interaction to almost any object if you know a few key PowerShell cmdlets. Here I use these key cmdlets to discover how I can work with windows services in my PowerShell session:
1 PS >#what commands apply to services?
2 PS >get-command *service
3
4 CommandType Name Definition
5 ----------- ---- ----------
6 Cmdlet Get-Service Get-Service [[-Name] <String[]>] [-ComputerName <String[]>] [-DependentServices...
7 Cmdlet New-Service New-Service [-Name] <String> [-BinaryPathName] <String> [-DisplayName <String>]...
8 Cmdlet Restart-Service Restart-Service [-Name] <String[]> [-Force] [-PassThru] [-Include <String[]>] [...
9 Cmdlet Resume-Service Resume-Service [-Name] <String[]> [-PassThru] [-Include <String[]>] [-Exclude <...
10 Cmdlet Set-Service Set-Service [-Name] <String> [-ComputerName <String[]>] [-DisplayName <String>]...
11 Cmdlet Start-Service Start-Service [-Name] <String[]> [-PassThru] [-Include <String[]>] [-Exclude <S...
12 Cmdlet Stop-Service Stop-Service [-Name] <String[]> [-Force] [-PassThru] [-Include <String[]>] [-Ex...
13 Cmdlet Suspend-Service Suspend-Service [-Name] <String[]> [-PassThru] [-Include <String[]>] [-Exclude ...
14
15
16 PS >#looks promising. what does get-service do?
17 PS >get-help get-service
18
19 NAME
20 Get-Service
21
22 SYNOPSIS
23 Gets the services on a local or remote computer.
24
25
26 SYNTAX
27 Get-Service [[-Name] <string[]>] [-ComputerName <string[]>] [-DependentServices] [-Exclude <string[]>] [-Include <string[]>] [-RequiredServices] [<CommonParameters>]
28
29 Get-Service -DisplayName <string[]> [-ComputerName <string[]>] [-DependentServices] [-Exclude <string[]>] [-Include <string[]>] [-RequiredServices] [<CommonParameters>]
30
31 Get-Service [-InputObject <ServiceController[]>] [-ComputerName <string[]>] [-DependentServices] [-Exclude <string[]>] [-Include <string[]>] [-RequiredServices] [<CommonParamete
32 rs>]
33
34
35 DESCRIPTION
36 The Get-Service cmdlet gets objects that represent the services on a local computer or on a remote computer, including running and stopped services.
37
38 You can direct Get-Service to get only particular services by specifying the service name or display name of the services, or you can pipe service objects to Get-Service.
39
40
41 RELATED LINKS
42 Online version: http://go.microsoft.com/fwlink/?LinkID=113332
43 Start-Service
44 Stop-Service
45 Restart-Service
46 Resume-Service
47 Suspend-Service
48 Set-Service
49 New-Service
50
51 REMARKS
52 To see the examples, type: "get-help Get-Service -examples".
53 For more information, type: "get-help Get-Service -detailed".
54 For technical information, type: "get-help Get-Service -full".
55
56
57
58 PS >#ok, now let's see what we can do with a service...
59 PS >get-service | get-member
60
61
62 TypeName: System.ServiceProcess.ServiceController
63
64 Name MemberType Definition
65 ---- ---------- ----------
66 Name AliasProperty Name = ServiceName
67 RequiredServices AliasProperty RequiredServices = ServicesDependedOn
68 Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs)
69 Close Method System.Void Close()
70 Continue Method System.Void Continue()
71 CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
72 Dispose Method System.Void Dispose()
73 Equals Method bool Equals(System.Object obj)
74 ExecuteCommand Method System.Void ExecuteCommand(int command)
75 GetHashCode Method int GetHashCode()
76 GetLifetimeService Method System.Object GetLifetimeService()
77 GetType Method type GetType()
78 InitializeLifetimeService Method System.Object InitializeLifetimeService()
79 Pause Method System.Void Pause()
80 Refresh Method System.Void Refresh()
81 Start Method System.Void Start(), System.Void Start(string[] args)
82 Stop Method System.Void Stop()
83 ToString Method string ToString()
84 WaitForStatus Method System.Void WaitForStatus(System.ServiceProcess.ServiceControllerStatus desiredStatus), System.Void WaitForStatus(System.ServiceProcess.Se...
85 CanPauseAndContinue Property System.Boolean CanPauseAndContinue {get;}
86 CanShutdown Property System.Boolean CanShutdown {get;}
87 CanStop Property System.Boolean CanStop {get;}
88 Container Property System.ComponentModel.IContainer Container {get;}
89 DependentServices Property System.ServiceProcess.ServiceController[] DependentServices {get;}
90 DisplayName Property System.String DisplayName {get;set;}
91 MachineName Property System.String MachineName {get;set;}
92 ServiceHandle Property System.Runtime.InteropServices.SafeHandle ServiceHandle {get;}
93 ServiceName Property System.String ServiceName {get;set;}
94 ServicesDependedOn Property System.ServiceProcess.ServiceController[] ServicesDependedOn {get;}
95 ServiceType Property System.ServiceProcess.ServiceType ServiceType {get;}
96 Site Property System.ComponentModel.ISite Site {get;set;}
97 Status Property System.ServiceProcess.ServiceControllerStatus Status {get;}
98
99
100 PS >
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
The key PowerShell commands: get-command (line 2), get-help (line 17), and get-member (line 59) help you find the objects you’re looking for and tell you what it is they can do.