Thursday, September 6, 2007

Playing sounds in PowerShell

 

You can play sounds in PowerShell in different ways and integrate them in your scripts to provide some kind of indication. One way is with write-host. You can pass the escape sequence `a  to write host. `a is the Alert corresponding special character:

# play a screech sound (through the internal speaker, not useful on laptops)

write-host "`a";

 

Another way is with a .NET class (.wav format).

# play the file once
$sound = new-Object System.Media.SoundPlayer;
$sound.SoundLocation="c:\WINDOWS\Media\notify.wav";
$sound.Play();

Note that the following process is asynchronously, meaning that the script wont hang until sound has finished playing. This example plays the file repeatedly until a condition met

$sound = new-Object System.Media.SoundPlayer;
$sound.SoundLocation="c:\WINDOWS\Media\notify.wav";
$sound.PlayLooping();
$flag=$false;

1..10 | foreach {
    if($_ -gt 5){$flag=$true} else{sleep -s 1}
    if($flag) { $sound.Stop() }
}

write-host "Done";

There is another class called System.Media.SystemSounds. Pipe the class to get-member to reflect its static members:

 

PS C:\Scripts> [System.Media.SystemSounds] | gm -static

   TypeName: System.Media.SystemSounds

Name            MemberType  Definition
----               ----------         ----------
(...)
Asterisk        Property         static System.Media.SystemSound Asterisk {get;}
Beep             Property         static System.Media.SystemSound Beep {get;}
Exclamation  Property         static System.Media.SystemSound Exclamation {get;}
Hand            Property         static System.Media.SystemSound Hand {get;}
Question       Property         static System.Media.SystemSound Question {get;}

 

Each property emitted represents a system sound type. Now, Pipe each property to get-member

 

PS C:\Scripts> [System.Media.SystemSounds]::Asterisk | gm

   TypeName: System.Media.SystemSound

Name         MemberType   Definition
----            ----------         ----------
(...)
Play           Method           System.Void Play()
ToString    Method           System.String ToString()

 

Great, we can use the Play method,test each line in your console:

[System.Media.SystemSounds]::Asterisk.Play();
[System.Media.SystemSounds]::Beep.Play();
[System.Media.SystemSounds]::Exclamation.Play();
[System.Media.SystemSounds]::Hand.Play();
[System.Media.SystemSounds]::Question.Play();

 

Finally, here is a one-liner for the job. It Utilizes the SoundPlayer(String) Constructor. It Initializes a new instance of the SoundPlayer class, and attaches the specified .wav file.

(new-object Media.SoundPlayer "C:\WINDOWS\Media\notify.wav").play();

6 comments:

Anonymous said...

Or, you could have PowerShell talk to you ...

James Pool said...

in the line where you have
1..10 | foreach
what does the 1..10 do?
I have never seen that before.

Shay Levy said...

Hi James

.. Is the Range operator. It represents the sequential integers in an integer array,given an upper and lower boundary, or simply create and initialize an array of integers.

For example, instead of writing:

for ($i=0; $i -lt 10; $i++) {write-host $i}

You can write:

1..10

Which gives the same result.


Ranges can also be used to get array indices, For example:

$a = 1..10
$a[2..4] # returns 3,4,5

Ankit Kashyap said...

few hours back, I was building something like that and posted here http://www.ankitk.com/techpatch/?p=103
(Musical script)
Found your post a bit late otherwise I have followed this approach. anyway, Now playing with it :)

Anonymous said...

great for frying pancakes :)

Anonymous said...

"Finally, here is a one-liner for the job."
(new-object Media.SoundPlayer "C:\WINDOWS\Media\notify.wav").play();

No, thats wrong. It goes like this.
-c (New-Object Media.SoundPlayer "c:\Windows\Media\notify.wav").PlaySync();