Loading...

Follow Hey, Scripting Guy! Blog on Feedspot

Continue with Google
Continue with Facebook
or

Valid

Summary: Using Windows PowerShell to remove Stale / Dead Domain Controller records.

Q: Hey, Doctor Scripto!

How can I quickly clean up all my dead Domain Controller’s DNS records?

A:

That’s a great question. The good Doctor also knows the very person to answer it best. My good friend Patrick Mercier, An Active Directory PFE who loves working with PowerShell.

Take it away Patrick!

Whether it’s as part of Active Directory Disaster Recovery, or because you had an old Domain Controller you needed to get rid of, cleaning up all the DNS records of a now dead DC left behind can be tedious: that is, unless you use PowerShell

So, as an Active Directory PFE, one of the common things we help customers out with is removing Domain Controllers from the environment. Sometimes that’s as simple as the old DC that has to go away or as scary as having recovered AD from backup and having to remove all other DCs as we rebuild. Regardless of the scenario, cleaning DNS is a critical part of this and I’ve frequently found it to be the part that scares customers the most.

I was cleaning up records manually one day and as I typically do, I thought to myself, there has to be a better way… and there is.

Before I continue though, this is not an Active Directory Disaster Recovery article. It’s not a DNS clean up article. If you’re looking for detailed explanations of all the DNS records this will delete, you’ll want to go find an article about Active Directory DNS! What I will do, is demonstrate an easy way to delete all DNS records related to a Domain Controller with a single PowerShell command.

First, let’s create an array of all the records in the zone _msdcs.contoso.com:

$dnsrecords = Get-DnsServerResourceRecord -ZoneName “_msdcs.contoso.com”

This outputs everything in our zone.

What we get though isn’t the full picture. The data we need to filter on is part of the “RecordData” data column which in and of itself is an array of data. And to isolate the DC we want to clean up, we’ll need to filter the resulting data. For that, we’ll filter on some of the attributes available in the RecordData record set, specifically, IPv4Address, NameServer and DomainName.

$deadDC = $dnsrecords | Where-Object {$_.RecordData.IPv4Address -eq “192.168.50.15” -or $_.RecordData.NameServer -eq “DC02.contoso.com.” -or $_.RecordData.DomainName -eq “DC02.contoso.com.”}

Sweet, now I have all the DNS records for my dead Domain Controller in one array!

From here, it’s super easy to delete them all, simply by calling the Remove-DnsServerResourceRecord cmdlet against the array and the zone! Because any good domain administrator has a bit of paranoia built in, let’s run that as a “What if” to confirm:

$deadDC | Remove-DnsServerResourceRecord -ZoneName “_msdcs.contoso.com” -whatif

And now, that I’ve got some peace of mind that nothing I need is being deleted, I simply remove the what if and the records are gone! No manual clean up.

So, if I were to bring all those components into one command, the result is:

Get-DnsServerResourceRecord -ZoneName “_msdcs.contoso.com” |

Where-Object {$_.RecordData.IPv4Address -eq "192.168.50.15"

-or $_.RecordData.NameServer -eq “DC02.contoso.com.” -or `

$_.RecordData.DomainName -eq “DC02.contoso.com.”} | Remove-DnsServerResourceRecord -ZoneName “_msdcs.contoso.com” -force

Simple really.

Thanks Patrick for an excellent tip to making all of this happen!

So that is all there is to using PowerShell to cleanup dead Domain Controller records.

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

Until then always remember that with Great PowerShell comes Great Responsibility.

Your Good friend, Dr. Scripto

Windows PowerShell, Patrick Mercier, Scripter

The post Clean up Domain Controller DNS Records with Powershell appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: Using the Get-Random Cmdlet to select a random list of names instead of numbers

Hey! Dr. Scripto!

I’d like to pick a random name from a list to generate user names in my lab.   Could you show me an example?

I’d be delighted to.   Just use an array of names and then add them as a parameter to Get-Random.   You could even pipe it to Get-Random if you liked as well.

$NameList=’John’,’Charlotte’,’Sean’,’Colleen’,’Namoli’,’Maura’,’Neula’

Get-Random -InputObject $NameList

Windows PowerShell, Sean Kearney, Scripting Guy, PowerTip

The post PowerTip: Use PowerShell to pick a random name from a list appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: Creating sample files with random sizes and dates for use in a Lab

Q: Hey, Dr. Scripto!

From time to time I like to show “how things works” at User Group meetings and to colleagues.   But I don’t always have a good pile of sample files.   Do you have any examples of how to create some “Demo data”?

—SH

A: Hello SH,

I actually ran into the same problem a few weeks ago when I was writing an article.   I needed exactly that!

What I needed was a folder full of sample files with not only random file names, but random content and even random dates.

Just *how* could I achieve that?

The first thought I had was “Just generate random filenames of numbers and put in a generic bit of content.”

This simple solution would be a start

# Provide Folder name and create
$Folder=’C:\Demo’

New-Item -ItemType Directory -Path $Folder

# Create a series of 10 files
for ($x=0;$x -lt 10; $x++)

{
# Let’s create a completely random filename
$filename=”$($Folder)\$((Get-Random 100000).tostring()).txt”

# Now we’ll create the file with some content
Add-Content -Value ‘Just a simple demo file’ -Path $filename

}

There! A repeatable solution to create 10 simple files!

Oh but wait, they were two problems I saw. Both were irritating.

  • Each file was the same size
  • Each filename was just a number followed by txt

These things I could improve.   I decided with preclude the number with a name like ‘LogFile’ so at least they *could* look a bit more legitimate.

For content…. How could I solve that?

I decided on a second loop of random limits and to populate it with ASCII values.

The useful values in ASCII (vs. PetSCII or ATASCII if you’re REALLY a Nerd from the ‘80’s) numbered from 32 to 96.   Those values would give me everything from a blank space to a little “Backtick”

Get-Random would work but it would start from 0 to a number. I needed to ensure I picked a numeric range between 32 and 96.

This was solved using this statement

(Get-Random 64)+32

Now the only challenge was to convert the Number to a Character.   You can convert an ASCII character to it’s numeric equivalent using the following statement. (Here we convert the letter ‘A’ to it’s ASCII equivalent).

We can REVERSE the process by swapping them around and providing the numeric equivalent.

To get my Random Number as character (Provide I have a range of values between 0 and 255 as a result) I would use this statement.

[char][byte]((Get-Random 64)+32)

So create a random string of content I just created a simple loop such as this.

# We’re going to build files up to 1K in size

   $limit=(Get-random 1024)

     # Let’s build the random content
   for($y=0;$y -lt $limit;$y++)
   {

       # We’re building a content of pure ASCII data
       $a=$a+[char][byte]((Get-Random 64)+32)

   }

Ok… it didn’t produce deep reading material, but I could produce random content up to 1 kilobyte in size to replace for the little string that read ‘Just a simple demo file’

To alter the filename to have “Logfile” at the beginning I simply injected the name into the string like this.

$filename=”$($Folder)\Logfile$((Get-Random 100000).tostring()).txt”

If you’re new to PowerShell I could also have put the pieces of the string together individually like this.

$filename=$Folder+’\Logfile’+((Get-Random 100000).tostring())+’.txt’

Let’s review

  • Each file now has a unique size and content
  • Each filename now has something a little more to the name

I was sitting there pleased with myself. I could easily alter the value and have Thousands of files.

“Muah ha ha ha haaaa!” I cackled like Doctor Frankenstein who is about to give life to the monster!

….and then (don’t you those?)

I realized every single file was just a sequence of the same date and time.   I wanted to be able to have content that had random dates and times.

For this I had to go up a level in permissions with using Administrative rights (Remember this is for DEMO content)

I knew with PowerShell I can access and CHANGE the current date and time with the following two Cmdlets.

Get-Date

Set-Date

I also knew I could adjust the Date and Time in precise increments in the following fashion

$TimeDifference=New-TimeSpan -Minutes 30

Set-Date -Adjust $TimeDifference

Now the wheels were churning.   I needed a loop to do the following

  • Pick a random number of days, hours and minutes (and remember them!)
  • Create a Timespan
  • Adjust the Set-Date with said Timespan
  • Once time was adjusted, create my file (Which would be stamped with this random date)
  • Create a “Negative Timespan” to undo my playing with the Clock
  • Correct the Date.

Now I’m certain many of you have access to a T.A.R.D.I.S. but good old Dr. Scripto doesn’t, so here at the Scripting Blog we use PowerShell.

Here’s an example of that very code that adjusts the time, creates the file and then Sets time back. Or mostly back at least.

   $DaysToMove=((Get-Random 120) -60)
   $HoursToMove=((Get-Random 48) -24)
   $MinutesToMove=((Get-Random 120) -60)
   $TimeSpan=New-TimeSpan -Days $DaysToMove -Hours $HoursToMove -Minutes $MinutesToMove

   # Now we adjust the Date and Time by the new TimeSpan
   # Needs Admin rights to do this as well!

     Set-Date -Adjust $Timespan | Out-Null

   # Create that file
   Add-Content -Value $a -Path $filename

   # Now we REVERSE the Timespan by the exact same amount
   $TimeSpan=New-TimeSpan -Days (-$DaysToMove) -Hours (-$HoursToMove) -Minutes (-$MinutesToMove)

   Set-Date -Adjust ($Timespan) | Out-Null

Now pleased with the results…. The Script was re-run

There are other things I could do to this script, such as have it test for existence of the Demo folder or ensure filenames were never duplicated.   But this was to create some basic “dummy Data”.

If you have to create a demo environment, you can use similar techniques to these for populating Active Directory users or SQL tables as well.

I hope this was a fun and informative read for you today and that you’re enjoying the weather as well!

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

Until we meet again, just remember we can all change the one world with just one Cmdlet at a time!

Cheers!

Sean Kearney, Premier Field Engineer, Hey Scripting Guy

Windows PowerShell, Sean Kearney, Hey Scripting Guy

The post Using PowerShell to create a folder of Demo data appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: A simple way to power off your computer by using the Windows PowerShell cmdlets.

   Hey, Scripting Guy! I’ve got a script that needs to power off a system after it’s done. How can I accomplish this with PowerShell?

   Look no further than the Stop-Computer cmdlet to turn off the power! (How’s THAT for a power tip?) Here are some examples:

# Try without doing anything bad

Stop-Computer -WhatIf

# Stop the local computer

Stop-Computer

# Try without doing anything bad on multiple systems

Stop-computer -ComputerName ‘computer01′,’computer02′,’computer03’ -whatif

# Stop multiple systems

Stop-computer -ComputerName ‘computer01′,’computer02′,’computer03’

The post PowerTip: Turn off the power to your computer with PowerShell appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: Having some fun with Abbott and Costello’s “Who’s on first?” comedy routine, and multiple voices with Bing Speech.

——————————-

Hello everyone!

The last few posts, I showed you all about the Cognitive Services Text-to-Speech API. You learned about the process to authenticate with Windows PowerShell.

It was also a great showcase for Invoke-RestMethod, as it demonstrated how REST API services are accessible with no real code for the IT professional.

Today, as an IT pro, I’m just going to have some fun. Sometimes that’s the best way to learn how to code.

Initially, all of this came about as a challenge from other members of “Hey, Scripting Guy!” I demonstrated a silly little script I wrote to play Abbott and Costello’s most famous comedy sketch, “Who’s on first?” with the internal voices in Windows. It’s a neat trick many PowerShell people love to play with like this.

# Establish to the Voice Comobject

$voiceAPI=New-Object -comobject SAPI.SPVoice

# Speed up the rate of the Speaker’s voice

$voiceAPI.Rate=3

I proceeded to get the voices, and then depending on who’s name (yes, that’s his name), I found I would pick a voice in Windows.

# Obtain the list of voices in Windows 10

$voiceFont=$voiceAPI.GetVoices()

# Establish a table to match the Microsoft voices with the names of the comedians

$nameMatch=@{‘Abbott:’ = ‘ZIRA’; ‘Costello:’ = ‘DAVID’ }

So it was neat. I had the text file on the hard drive, and it was all fun and games.

Some people said, “Cool, but you should try the same approach with Cognitive Services!”

It was at this point I read and learned everything I showed you in the last several posts. Today we’re going to have some fun: “Who’s on first?” portrayed by the “Azure Cognitive Services Players.”

Challenge #1 – Learn how to use Text-to-Speech in Azure. Accomplished, and built a function to leverage it. I’ve prepopulated all of the available sound file options, so I could just select from an array in this function.

Function Invoke-AzureTextToSpeech($Region,$Voice,$Content,$Filename)

{

# Obtain Access Token to communicate with Voice API

# I erased mine, you'll have to get your own ;)

$APIKey='00000000000000000000000000000000'

$AccessToken=Invoke-RestMethod -Uri "https://api.cognitive.microsoft.com/sts/v1.0/issueToken" -Method 'POST' -ContentType 'application/json' -Headers @{'Ocp-Apim-Subscription-Key' = $APIKey }

# Generate GUID for Access

# Just use this Cmdlet to generate a new one (New-Guid).tostring().replace('-','')

$XSearchAppId='00000000000000000000000000000000'

# Just use this Cmdlet to generate a new one (New-Guid).tostring().replace('-','')

$XSearchClientId='00000000000000000000000000000000'

# Current list of Audio formats for Azure Text to Speech

# HTTP Headers X-Microsoft-OutputFormat

# https://docs.microsoft.com/en-us/azure/cognitive-services/speech/api-reference-rest/bingvoiceoutput

#

$AudioFormats=(

'ssml-16khz-16bit-mono-tts',

'raw-16khz-16bit-mono-pcm',

'audio-16khz-16kbps-mono-siren',

'riff-16khz-16kbps-mono-siren',

'riff-16khz-16bit-mono-pcm',

'audio-16khz-128kbitrate-mono-mp3',

'audio-16khz-64kbitrate-mono-mp3',

'audio-16khz-32kbitrate-mono-mp3'

)

# WAV File format

$AudioOutputType=$AudioFormats[4]

$UserAgent='PowerShellForAzureCognitiveApp'

$Header=@{

'Content-Type' = 'application/ssml+xml';

'X-Microsoft-OutputFormat' = $AudioOutputType;

'X-Search-AppId' = $XSearchAppId;

'X-Search-ClientId' = $XSearchClientId;

'Authorization' = $AccessToken

}

$Body=''+$Content+''

Invoke-RestMethod -Uri "https://speech.platform.bing.com/synthesize" -Method 'POST' -Headers $Header -ContentType 'application/ssml+xml' -Body $Body -UserAgent $UserAgent -OutFile $Filename

}

I can now use this function and dynamically supply the region data, as well as the content, in a loop or script!

Challenge #2 – Get a nice way to play WAV files synchronously, without launching additional applications.

I used a simple function based upon the earlier posted PowerTip to solve this issue.

Function Play-MediaFile($Filename)

{

$PlayMedia=New-object System.Media.Soundplayer

$PlayMedia.SoundLocation=($Filename)

$PlayMedia.playsync()

}

Challenge #3 – Get rid of the text file.  I want to read the content straight from The Abbott and Costello Fan Club.

Connecting was easy. Just use Invoke-WebRequest, and store the content in an object.

$RawSketch=Invoke-WebRequest -Uri 'http://www.abbottandcostellofanclub.com/who.html'

The challenge was that the returned content was one massive string. I needed it broken up into lines for an array.

I’m sure I could have contacted some friends like Tome Tanasovski or Thomas Rayner for some help with regular expressions, but I like trying alternative approaches sometimes.

There were a lot of CRLF (CarriageReturn / LineFeed) and Tabs prefacing the lines. I needed that cleaned up.

$CR=[char][byte]13

$LF=[char][byte]10

$Tab=[char][byte]9

$RawSketchContent=$RawSketch.Content

$RawSketchContent=$RawSketchContent.Replace($cr+$lf+$tab,' ')

Once I completed this, I just had a nice list of content terminating in carriage returns. I could split this up into an array now, in the following fashion:

$SketchArray=$rawsketchcontent.split("r”)

I took a look at the raw HTML, and found a “Before” and “After” on the sketch content. I passed this into Select-Object and captured the line numbers of the array. This allowed me to have a “Begin” parsing point, and an “End.”

$StartofSketch=$SketchArray | Select-string -SimpleMatch ‘<PRE>’ | Select-Object -expandproperty LineNumber

$EndofSketch=$SketchArray | Select-string -SimpleMatch ‘</PRE>’ | Select-Object -expandproperty LineNumber

With this achieved, I needed to select two voices in Cognitive Services Text-to-Speech. If you remember Part 4 in the series, we showed the list to choose from. I decided on an Australian female voice for Bud Abbott, and an Irish male voice for Lou Costello.

I used a simple array to store the data.

$CognitiveSpeakers=@()

$CognitiveSpeakers+=’BUD:;en-AU;”Microsoft Server Speech Text to Speech Voice (en-AU, Catherine)”‘

$CognitiveSpeakers+=’LOU:;en-IE;”Microsoft Server Speech Text to Speech Voice (en-IE, Shaun)”‘

We need to initial certain variables to figure out Who is talking (well yes, of course he is, that’s his job), and to store away the audio content.

$CurrentSpeaker=’Nobody’

$TempVoiceFilename=’whoisonfirst.wav’

Now for the work to begin. We start our loop from the beginning of the content array to the end, and make sure any temporary WAV file is erased from a previous run.

For ($a=$StartofSketch+1; $a -lt $EndofSketch; $a++)

{

Remove-Item $TempVoiceFilename -Force -ErrorAction SilentlyContinue

We then identify a line of content to parse:

$LinetoSpeak=$sketcharray[$a-1]

Each line that has a speaker on the site began with either BUD: or LOU:, so I used a little RegEx to trap for where the identified speaker name ended. Anything after that would be their speaking content.

$SearchForSpeaker=(($LinetoSpeak | Select-String -Pattern ‘[a-zA-Z]+(:)’).Matches)

The next scenario to trap for was whether the line contained a speaker name with text, or just text (which meant a continuation of the earlier line).

This variable would set to 1 (beginning of a line). If a speaker was found, the beginning of the content would naturally be further down the line.

$LinetoSpeakStart=1

Then I had to trap for some “fun situations.” Did the speaker change? Is it the same speaker, but they have more lines to speak?

If ($SearchForSpeaker -ne $NULL)

{

$Speaker=$SearchForSpeaker[0].Value

$LinetoSpeakStart=$SearchForSpeaker[0].Index + $SearchForSpeaker[0].Length + 5

Then of course if the speaker did change, I needed to repopulate objects unique to the speaker for Azure.

If ($Speaker -ne $CurrentSpeaker)

{

$CurrentSpeaker = $Speaker

$RawSpeakerData=$CognitiveSpeakers -match $CurrentSpeaker

$SpeakerData=$RawSpeakerData.split(';')

$Region=$SpeakerData[1]

$Voice=$SpeakerData[2]

$Name=$SpeakerData[0]

}

As you can see, I’m pulling in the data needed for Azure, like Voice and Region from the SpeakerData array I created earlier.

Once we’ve identified the speaker and the content, we can call up the two key functions of Invoke-AzureTextToSpeech and Play-MediaFile:

If ($LinetoSpeak.Length -gt 1)

{

$LinetoSpeak.replace('','').replace('','')

$Content=$LineToSpeak.Substring($LinetoSpeakStart).replace('','').replace('','')

Invoke-AzureTextToSpeech -Region $Region -Content $Content -Voice $Voice -Filename $TempVoiceFilename

Do { } until (Test-Path $TempVoiceFilename)

Play-MediaFile -filename $TempVoiceFilename

Start-Sleep -Milliseconds 1000

}

You’ll note that there is a Start-Sleep in the loop. This is because there is a limit on the REST API of how many transactions it can take within a certain timeframe.

I thank you for sharing your time with me today. Hopefully you had a little fun, and maybe even learned of some ways you, too, can play with HTML content.

If you see a more efficient way of doing this, I’d love to see the results! It could be a really cool blog post itself!

Until next time, remember that the Power of Shell is in you!

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

Sean Kearney, Premier Field Engineer, Microsoft

Frequent contributor to Hey, Scripting Guy!

The post Parse HTML and pass to Cognitive Services Text-to-Speech appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary:  Identify your PowerShell environment by making use of built-in PowerShell variables.

   Hey, Scripting Guy! If I’m writing a script, how can I detect if I am running on Windows, Linux, or Mac with PowerShell?

   Just use the built-in variable $PSVersionTable, which has all of the properties you’ll need. Here is an example:

# Currently operating version

$PSVersionTable.PSVersion

# Current Host operating System

# If this value is $NULL you are currently running Windows PowerShell 5.x

# else it returns the host environment from the open Source release

$PSVersionTable.OS

The post PowerTip: Determine your version of PowerShell and host operating system appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: Send and receive content to the Text-to-Speech API with PowerShell.

Q: Hey, Scripting Guy!

Could you give a buddy a hand in getting the last pieces together for the Text-to-Speech API?

—SR

A: Hello SR,

No problem at all. The last few posts, we dealt with the “Heavy Lifting” (which really wasn’t that heavy):

  • Authentication
  • Creating the headers
  • Defining the SSML body

Now at this point, we only need to call up the REST API to have it do the magic. So just like our Authentication API, we have the following pieces:

  • Endpoint
  • Method
  • Authentication
  • Headers
  • Body

We have the final three already. In a previous post, we built the headers (Application ID, GUID, and audio format), and we’ve just finished building the body. The authentication token is contained within the headers.

What we need to know now is the endpoint, and what Invoke-RestMethod needs. This can all be found here at Bing Text to Speech API, under the “Authorization Token” section.

The endpoint is https://speech.platform.bing.com/synthesize. To determine the method required, just glance at the “Example: voice output request.” It shows you the method as the first line.

In many REST API examples, if you see an example of the output, the first line is often the method. You can use this trick in other scenarios with REST APIs in general.

All we need to do now is assemble the pieces, and call up Invoke-RestMethod. To avoid you running back and forth, I’ve assembled the entire script:

Try

{

[string]$Token=$NULL

# Rest API Method

[string]$Method='POST'

# Rest API Endpoint

[string]$Uri='https://api.cognitive.microsoft.com/sts/v1.0/issueToken'

# Authentication Key

[string]$AuthenticationKey='13775361233908722041033142028212'

# Headers to pass to Rest API

$Headers=@{'Ocp-Apim-Subscription-Key' = $AuthenticationKey }

# Get Authentication Token to communicate with Text to Speech Rest API

[string]$Token=Invoke-RestMethod -Method $Method -Uri $Uri -Headers $Headers

}

Catch [System.Net.Webexception]

{

Write-Output 'Failed to Authenticate'

}

$AudioOutputType='riff-16khz-16bit-mono-pcm'

$XSearchAppID='dccd93ecb3cf4535aac9350c9b5fb2f8'

$XSearchClientID='45b403b6ae0d4f9ca13ca05f61a58ab2'

$UserAgent='PowerShellTextToSpeechApp'

$Header=@{

'Content-Type' = 'application/ssml+xml';

'X-Microsoft-OutputFormat' = $AudioOutputType;

'X-Search-AppId' = $XSearchAppId;

'X-Search-ClientId' = $XSearchClientId;

'Authorization' = $AccessToken

}

; New Content from this post below here ;

$Locale='en-US'

$ServiceNameMapping='Microsoft Server Speech Text to Speech Voice (en-US, JessaRUS)'

$Content='Hello everyone, this is Azure Text to Speech'

$Body=''+$Content+''

$Endpoint= 'https://speech.platform.bing.com/synthesize'

$Method='POST'

$ContentType='application/ssml+xml'

$Filename='output.wav'

Invoke-RestMethod -Uri $Endpoint -Method $Method

-Headers $Headers -ContentType $ContentType

-Body $Body -UserAgent $UserAgent `

-OutFile $Filename

Notice that Invoke-RestMethod has a -filename parameter, which allows you to store received output directly as a file on the file system.

When this process is complete, you will have a WAV file (which is what we chose). It can be launched in your choice of audio application.

The reason the API has regions is that it accepts text in a local language (such as French). If you target the appropriate region, the speaking voice is tuned to speak with the appropriate accent and inflections of the text.

Pretty cool, eh? If you’re tripping over any of the pieces, don’t forget to review the earlier four parts of this series to get it all ironed out!

That’s all for the moment, but keep a lookout for more in the way of PowerShell here.

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

Sean Kearney, Premier Field Engineer, Microsoft

Frequent contributor to Hey, Scripting Guy!

The post Windows PowerShell and the Text-to-Speech REST API (Part 5) appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: Make use of the native features of Windows through PowerShell to play sound.

   Hey, Scripting Guy! I’ve got some WAV files I would love to play without launching an application. Is there a way in Windows PowerShell to do this?

     You sure can! Using the System.Media.Soundplayer object, you can do this quite easily. Here is an example of how to do this:

$PlayWav=New-Object System.Media.SoundPlayer

$PlayWav.SoundLocation=’C:\Foo\Soundfile.wav’

$PlayWav.playsync()

The post PowerTip: Use PowerShell to play WAV files appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: Send and receive content to the Text-to-Speech API with PowerShell.

Q: Hey, Scripting Guy!

I was playing with the Text-to-Speech API. I have it almost figured out, but I’m stumbling over the final steps of formatting the SSML markup language. Could you lend me a hand?

—MD

A: Hello MD,

Glad to lend a hand to a Scripter in need! I remember having that same challenge the first time I worked with it. It’s actually not hard, but I needed a sample to work with.

Let’s first off remember where we were last time. We’ve accomplished the first two pieces for Cognitive Services Text-to-Speech:

  1. The authentication piece, to obtain a temporary token for communicating with Cognitive Services.
  2. Headers containing the audio format and our application’s unique parameters.

Next, we need to build the body of content we need to send up to Azure. The body contains some key pieces:

  • Region of the speech (for example, English US, Spanish, or French).
  • Text we need converted to speech.
  • Voice of the speaker (male or female).

For more information about all this, see the section “Supported locales and voice fonts” in Bing text to speech API.

The challenge I ran into was in just how to create the SSML content that was needed. SSML, which stands for Speech Synthesis Markup Language, is a standard for identifying just how speech should be spoken. Examples of this would be:

  • Content
  • Language
  • Speed

I could spend a lot of time reading up on it, but Azure gives you a great tool to create sample content without even trying! Check out Bing Speech, and look under the heading “Text to Speech.” In the text box, type in whatever you would like to hear.

In the sample below, I have entered in “Hello everyone, this is Azure Text to Speech.”

Now if you select View SSML (the blue button), you can see the code in SSML that would have been the body we would have sent to Azure.

You can copy and paste this into your editor of choice. From here, I will try to break down the content from our example.

<speak version=”1.0″ xmlns=”http://www.w3.org/2001/10/synthesis” xmlns:mstts=”http://www.w3.org/2001/mstts” xml:lang=“en-US”><voice xml:lang=“en-US” name=“Microsoft Server Speech Text to Speech Voice (en-US, JessaRUS)”>Hello everyone, this is Azure Text to Speech</voice></speak>

The section highlighted in GREEN is our locale. The BLUE section contains our service name mapping. The locale must always be matched with the same service name mapping from the row it came from. The double quotes are also equally important.

If you mix them up, Azure will wag its finger at you and give a nasty error back.

The section in RED is the actual content that Azure would like us to convert to speech.

Let’s take a sample from the table, and change this to an Australian female voice.

We first replace the locale with “en-AU,” and then the service name mapping with “Microsoft Server Speech Text to Speech Voice (en-AU, Catherine).”

<speak version=”1.0″ xmlns=”http://www.w3.org/2001/10/synthesis” xmlns:mstts=”http://www.w3.org/2001/mstts” xml:lang=“en-AU”><voice xml:lang=“en-AU” name=” Microsoft Server Speech Text to Speech Voice (en-AU, Catherine)”>Hello everyone, this is Azure Text to Speech</voice></speak>

Now if we’d like to have her say something different, we just change the content in red.

How does this translate in Windows PowerShell?

We can take the three separate components (locale, service name mapping, and content), and store them as objects.

$Locale=‘en-US’

$ServiceNameMapping=‘Microsoft Server Speech Text to Speech Voice (en-US, JessaRUS)’

$Content=‘Hello everyone, this is Azure Text to Speech’

Now you can have a line like this in Windows PowerShell to dynamically build out the SSML content, and change only the pieces you typically need.

$Body='<speak version=”1.0″ xmlns=”http://www.w3.org/2001/10/synthesis” xmlns:mstts=”http://www.w3.org/2001/mstts” xml:lang=”‘+$locale+'”><voice xml:lang=”‘ +$locale+'” name=’+$ServiceNameMapping+’>’+$Content+'</voice></speak>’

At this point, we only need to call up the REST API to have it do the magic. But that is for another post!

See you next time when we finish playing with this cool technology!

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

Sean Kearney, Premier Field Engineer, Microsoft

Frequent contributor to Hey, Scripting Guy!

The post Windows PowerShell and the Text-to-Speech REST API (Part 4) appeared first on Scripting.

  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Summary: Here’s how to make sure your errors get caught with Try Catch Finally.

   Hey, Scripting Guy! I’ve been trying to use the Try Catch Finally, but some of my errors aren’t getting caught. What could be the cause?

   For Try Catch Finally, you need to make sure the error defaults to a “Stop” action for the cmdlet in question. Here’s a quick example:

try

{

Get-Childitem c:\Foo -ErrorAction stop

}

catch [System.Management.Automation.ItemNotFoundException]

{

'oops, I guess that folder was not there'

}

The post PowerTip: Ensure that errors in PowerShell are caught appeared first on Scripting.

Read for later

Articles marked as Favorite are saved for later viewing.
close
  • Show original
  • .
  • Share
  • .
  • Favorite
  • .
  • Email
  • .
  • Add Tags 

Separate tags by commas
To access this feature, please upgrade your account.
Start your free month
Free Preview