Quantcast
Channel: Hey, Scripting Guy! Blog
Viewing all 3333 articles
Browse latest View live

Systems Center 2012 Orchestrator and PowerShell: Part 1

$
0
0

Summary: Sean Kearney explains how to use a Windows PowerShell script in System Center 2012 Orchestrator to access variables and published data.

Hey, Scripting Guy! Question Hey, Scripting Guy!

I’m using System Center 2012 Orchestrator at work, but I don’t know how to access the variables and published data in Windows PowerShell. Is it possible? Is it easy?

—SH

Hey, Scripting Guy! Answer Hello SH,

Honorary Scripting Guy, Sean Kearney here. I’m filling in for our good friend, Ed Wilson. He’s busy this week enjoying the beautiful colors in the trees and the foliage.

SH, when you put the word “PowerShell” in your question, the immediate answer is, “Yes, of course! You can achieve almost anything with Windows PowerShell." Right now I’m working on a module to allow Windows PowerShell to tie my shoes! (Of course I’m kidding. I’m pretty certain Ed has already written that.)

So for those of you just stepping in, Microsoft has a tool called System Center 2012 Orchestrator. It’s a really cool piece of technology that allows for some very complex automation to happen—but in a task-based scenario.

The strength of Orchestrator is that it presents a very simple to understand visual automation system. It’s also a very extensible system like Windows PowerShell. In fact, you can have Orchestrator launch Windows PowerShell scripts, which allows you to leverage in-house solutions within an Orchestrator runbook.

Within Windows PowerShell, we have objects like these:

$DOG=”I caught the kitty cat”

$USER=GET-ADUSER –filter “*”

System Center 2012 Orchestrator also has a way to store and retrieve user and system-provided data. But in Orchestrator, we call these Variables and Published Data. For a really great breakdown about System Center 2012 Orchestrator, here is a video from TechEd 2013 to bring you up to speed: Microsoft System Center 2012 Orchestrator: Crash Course.

If you were looking at a Windows PowerShell script in Orchestrator, you would be viewing a window similar to this, which is the .NET task in a runbook:

Image of menu

So as we can see this is a very blank script. It doesn’t have to do much today, other than access data in Orchestrator. So first we do the hard part—create a Windows PowerShell object:

Image of menu

Now if you’ve used Orchestrator before, this is actually the easy part. Right-click the middle of the script, click Subscribe, and select either Published Data or Variable (depending on the particular data in Orchestrator you want to access):

Image of menu

Now you’ll see a representation for the data in Windows PowerShell:

Image of menu

But wait now—you’re not done. You see, this is not a pointer. What Orchestrator will do when you run the Windows PowerShell script within (before it passes to the Windows PowerShell engine), is replace {DomainDNSName} with whatever your value is.

So if the value we had was a string called CONTOSO.LOCAL, this is what would be passed down to our good friend, Windows PowerShell:

$SomeVariableinOrchestrator=CONTOSO.LOCAL

Notice something wrong with this statement? There are no quotation marks around this string. So this would pass down to Windows PowerShell and be run as code, which of course, unless you had an alias called CONTOSO.LOCAL, would simply cough up some nasty error.

So what you’ll need to do is enclose the data in a pair of quotation marks when you subscribe as shown in the following image:

Image of menu

This would now translate to this:

$SomeVariableinOrchestrator=”CONTOSO.LOCAL”

Of course, this will work fine in Windows Powershell.

If the data being published is Date/Time data, you need to precede the Windows PowerShell object with [datetime] to allow it to be properly converted. Otherwise, it will simply be a string. Here is an example of this in action:

Image of menu

There are some situations where you won’t do this. If the data being published or the variable is an integer, there is no need to enclose any of this within quotation marks or precede it with [datetime].

Image of menu

Easy as pie!

Interested? Stick around for this entire week as we discuss Orchestrator and Windows PowerShell, the coolest two-punch combo in the industry—and see how to make them work together!

And tomorrow (if you’re really good), I’ll show you how to publish data to the Orchestrator data bus from Windows PowerShell.

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

Sean Kearney (filling in for our good friend Ed Wilson),
      Honorary Scripting Guy, Windows PowerShell MVP


PowerTip: Use PowerShell to Access Orchestrator Variables or Data

$
0
0

Summary: Use Windows PowerShell to access the Orchestrator variables or published data.

Hey, Scripting Guy! Question How can I use Windows PowerShell to access the Orchestrator variables or published data from the data bus?

Hey, Scripting Guy! AnswerRight-click the middle of the script, click Subscribe, and choose Variable or Published Data as you normally would in Orchestrator.

Ensure that you enclose the subscribed data within quotation marks if the information is a string or Date/Time data, and then assign it to a Windows PowerShell object as you normally would:

$FooString=”{SomeCoolThingInOrchestrator}”

$FooNumber={ACounterOfSomeKind}

[Datetime]$FooDate=”{DateFieldfromOrchestrator}”

Systems Center 2012 Orchestrator and PowerShell: Part 2

$
0
0

Summary: Make data from a Windows PowerShell script in System Center 2012 Orchestrator accessible on the data bus.

Hey, Scripting Guy! Question Hey, Scripting Guy!

We love using Windows PowerShell with System Center 2012 Orchestrator, but we’re having a hard time figuring out how to get our data to Orchestrator from Windows PowerShell. Can you lend us a hand? Please? Pretty please?

—TS

Hey, Scripting Guy! Answer Hello TS,

Honorary Scripting Guy, Sean Kearney here. I’m continuing to fill in for Ed this week.

So last time we saw how to get data IN to Windows PowerShell from Orchestrator:

Access Data from Orchestrator 2012 with PowerShell

Now is the time to flip things around and send it back. So would you believe me if I told you this is actually very easy to do?

Take a look at our tiny script from previously. Let’s pretend it has its own information that needs to be sent TO Orchestrator.

Image of menu

So here we have three pieces of data in a Windows PowerShell script. We’d like to make this information accessible to the next activity in the runbook.

To do this, you need to use the Published Data option. Click it to open it.

Image of menu

Click Add to open the Published Data Wizard (Hey, does this wizard have a cool wand? No?)

Image of menu

In the Name text box, type the Name to be used on the data bus if someone needs to subscribe to it. It can be a different name than your Windows PowerShell object, but it can also be the same.

Orchestrator (at the time of this post) supports three types of data: Date/Time, Integer, and String. In the drop-down list, select String.

In the Variable Name text box, type in the name of the Windows PowerShell variable you want to publish to the data bus.

In our earlier example, if we were trying to publish the object called $Important, we would fill out the Published Data as follows:

Image of menu

We just need to remove the $ from the name of the object. The name is also not case sensitive. As I mentioned earlier, the Name does NOT have to be the same as the Windows PowerShell object name. I could also publish it as FlyingRubberChicken or EvenMoreImportantDataThanTheFirstTime.

Image of menu

All this means is that if I access Published Data from that particular activity, and the names don’t match, I should have something in my documentation to draw a reference to the new name. Personally, I try not to change the names, but you can if you like or need to. Click OK whenever you’re done.

If you were publishing the Date/Time data, it would look like this:

Image of menu

Not so tricky is it?

In this case, I decided to publish all of the data. It turned out like this when I was done and clicked the Published Data tab:

Image of menu

When I click Finish and check the runbook in, I can access this data from other Orchestrator activities as I normally would with any other Published Data.

In the case of this particular script, I published all of the values. But I can publish as little or as much as I want. As you can tell, it is a manual process, and you must enter each object to be published individually.

So now we’ve seen how to get information IN and OUT of Windows PowerShell and Orchestrator. But is there anything else we need to worry about? Anything we can or cannot do?

Check back tomorrow and we’ll talk more…

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

Sean Kearney, Honorary Scripting Guy
Windows PowerShell MVP
 

PowerTip: Publish Data to Orchestrator Data Bus

$
0
0

Summary: Publish Windows PowerShell data to the Orchestrator data bus.

Hey, Scripting Guy! Question Can I access data in my Windows PowerShell script from within Orchestrator?

Hey, Scripting Guy! AnswerSelect Published Data in the Run .NET Script activity, click Add, and fill in the details for the object you want to publish:

“Name”              Name you wish to use on the Databus
“Type”                           Type of .NET Object, Date/Time, String or Integer
“Variable Name”             PowerShell Object Name without the “$”

For example:

PowerShell

$UserName=”John Smith”

Orchestrator Published Data option in “Run .NET Script”

Image of menu

Systems Center 2012 Orchestrator and PowerShell: Part 3

$
0
0

Summary: Learn how to troubleshoot a Windows PowerShell script within Orchestrator.

Hey, Scripting Guy! Question Hey, Scripting Guy!

I’m having some trouble debugging my Windows PowerShell script in Orchestrator. Do you have any tips that might help us along?

—DM

Hey, Scripting Guy! Answer Hello DM,

Honorary Scripting Guy, Sean Kearney here. I continue to fill in for Ed this week while he “branches out” to new areas with his camera.

So one thing you will have discovered if you have used Windows PowerShell with Orchestrator is that the Runbook Tester cannot view the Windows PowerShell objects. In fact, if you get an error message with your Windows PowerShell script in Orchestrator, you may very well be staring at some obscure looking .NET error message from the Windows PowerShell engine like this:

Image of error message

Looking at that is not very helpful. It doesn’t tell me where in the script it failed, what it was doing, or the value of my objects. Only that it…well…FAILED.

But remember, we are never lost in the world of Windows PowerShell. First off, let’s think about how we built the script.

You probably built it within some type of ISE with sample values and data to ensure that it actually worked outside of Orchestrator. Then at some point you copied in the script.

So logically (if this is the exact script you started with), it must be something that is introduced by Orchestrator. Say for example a Variable or Published Data you subscribed to? Or possibly something your script is monitoring is coughing up a $Null value?

Within Windows PowerShell, we have many built-in options for debugging. Within Orchestrator, you can start with the simplest approach, which is get the data out of the script into somewhere that you can examine it.

The simplest method I have come across is to drop points in the script and have it export various variables by using Export-Clixml. That way if the script crashes, you’ll have values from the script outside of Orchestrator with Date/Time stamps.

In the following sample script in Orchestrator, I have some lines that I can uncomment for testing purposes:

Image of menu

By Using the Export-Clixml to pull the data out, we get the object (how little or how much exists), so we can at least determine if we are getting the data we were supposed to be getting by diving into Windows PowerShell and examining these files like so:

[xml]$Filename=GET-CONTENT C:\Debug\Filename.xml

$Filename | GET-MEMBER

We can examine the data and view it externally to see if we are receiving a Null, an array, or complete jibberish.

We can also pull out two more options. We can temporarily Exit the script earlier to determine where the error actually is by using the Exit command.

Image of menu

This can at least tell us where things are going bad. If we can get the Runbook Tester to stop throwing errors, we can identify where in the script things are running poorly.

The main trick, of course, is to ensure that the script works in the ISE. If your logic is broken before you plug it into Orchestrator, you’ll have a bigger mess on your hands.

Next time we’ll look at some caveats and things to look out for when leveraging the two technologies.

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

Sean Kearney, Honorary Scripting Guy
Windows PowerShell MVP

PowerTip: Trapping Variables Within a PowerShell Script in Orchestrator

$
0
0

Summary: Get data from Windows Powershell in Orchestrator for debugging.

Hey, Scripting Guy! Question Is there an easy way to troubleshoot a Windows PowerShell script in Orchestrator so I can see if the data is $Null or is the right type?

Hey, Scripting Guy! Answer Leverage the Export-Clixml cmdlet within the script against the object in question:

$SomethingNotWorking=GET-CONTENT (C:\somefile.txt)

$SomethingNotWorking | EXPORT-CLIXML C:\debug\something.txt

Then in Windows PowerShell, rebuild the variable to examine it outside of the script:

[xml]$SomethingNotWorking=(GET-CONTENT C:\debug\something.txt)

$SomethingNotWorking | GET-MEMBER

Systems Center 2012 Orchestrator and PowerShell: Part 4

$
0
0

Summary: Learn about things to be aware of when working with a Windows PowerShell script in Orchestrator.

Hey, Scripting Guy! Question Hey, Scripting Guy!

I’m starting to use Orchestrator and Windows PowerShell, but before I get too involved, I’d like to know if there is anything I should look out for.

—DR

Hey, Scripting Guy! Answer Hello DR,

Honorary Scripting Guy, Sean Kearney, here. I’m continuing to fill in for Ed this week. With autumn around the corner, I’m going to “leaf” him alone right now.

So Windows PowerShell and Orchestrator do work well together but there are a few things to look out for. Here’s the biggest one I’m going to put on your plate now…before you trip over it and fall on your face.

Look at this Window from the Run .NET Script activity:

Image of menu

Now repeat after me, “This is not an editor! This is not an editor! This is not an editor!”

Are we clear on that information? Although you can go into this window and happily makes changes like the world was covered in pink bubble gum with twinkly green diamonds, do not trust this Window for making changes without doing two key things:

  • Export your runbook before editing, attempting to edit, or even thinking about editing.
  • Enter the window, press CTRL-A then CTRL-C, and paste your script into a backup Notepad.

Why am I so harsh on this window? For some reason, it’s missing the most critical feature needed for an editor: the undo option. There is no (just like life) CTRL-Z. Plan for this and be safe.

Now for the good news. Although your Windows PowerShell script might have some funky Orchestrator variables in there, when you use CTRL-C and paste it into Notepad, your Orchestrator data may look something like this.

$SomeVariableinOrchestrator="\`d.T.~Vb/{E013F159-9796-4E29-9E26-02AC82B8E1AD}\`d.T.~Vb/"

But that’s OK! That numeric GUID is all Orchestrator is looking for, and it is expecting the information in ASCII form. If you paste it back into your Windows PowerShell script, it will magically translate back to whatever it was.

$SomeVariableinOrchestrator="{DomainDNSName}”

A big one to remember with the Variables and Published Data is that Orchestrator replaces the content before passing to the interpreter. So if you subscribe to data that might contain characters that are special to Windows Powershell (for example, the quote), and it does not contain proper escape characters, it can break your script. Even if it’s enclosed in quotation marks. This is something to plan for with your data and your script.

And of course, as you noticed, at this time, the Runbook Tester cannot see your Windows PowerShell objects. So if you need to debug, plan for it within your script.

Pop in tomorrow as we touch on how the community has aided and extended Orchestrator with its own cmdlets!

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

Sean Kearney, Honorary Scripting Guy
Windows PowerShell MVP 

PowerTip: Copy Your Script to Notepad Before Editing in Orchestrator

$
0
0

Summary: Easily create a backup before editing in Orchestrator.

Hey, Scripting Guy! Question Ctrl-Z does not work in the Orchestrator editor window, so how can I protect myself if I make a typing error?

Hey, Scripting Guy! Answer Press Ctrl-A then Ctrl-C to copy the content of your script, open Notepad, and paste a backup copy there. Also within Orchestrator, you can (and should) export your runbook before any editing.


Systems Center 2012 Orchestrator and PowerShell: Part 5

$
0
0

Summary: Learn about cmdlets developed by the community for Orchestrator.

Hey, Scripting Guy! Question Hey, Scripting Guy!

I was looking, and I could not find any cmdlets to manage Orchestrator. Can you nudge me in the right direction?

—KC

Hey, Scripting Guy! Answer Hello KC,

Honorary Scripting Guy, Sean Kearney is here continuing to fill in for Ed while he pokes around a binary tree to see if its leaves have changed.

So although there are no built-in cmdlets for Orchestrator at this time, there is a powerful following in the community. On CodePlex, there is a module that was developed by a member of the community that addresses this issue by leveraging the supplied web service from Orchestrator: Community Project for System Center Orchestrator (SCORCH) Integration Packs and Utilities.

All we have to do is download the module, import it, and play with the cmdlets it offers. When you download the module, it will come out as a .zip file. You’ll need to extract it, of course. I extracted mine to a Folder called C:\Scorch:

Image of menu

After you extract the structure, you will find a Windows PowerShell script called Deploy.ps1. Run this script within Windows PowerShell to install the module in your system. You need Administrative credentials to use this feature.

Image of script

The module is now installed and registered as an available module. If you need to reload it, simply run:

IMPORT-MODULE Scorch

To get a list of cmdlets that are available, we can run the following command:

GET-COMMAND –module Scorch

Image of script

The author has provided us with nine new cmdlets to manage our Orchestrator environment from Windows PowerShell. If you check further, there are also some sample scripts that show how to leverage these cmdlets.

All of these cmdlets request the URL for the web service. Our good friend has been kind enough to save us the typing. Simply use this cmdlet with the name of the Orchestrator server (of course, replace MYORCHSERVER with the name of your Orchestrator server):

$OWS=New-ScoWebserverURL –servername MYORCHSERVER

You can now leverage Windows PowerShell to perform tasks like identifying your runbook server:

(GET-SCORunbookServer –WebServerUrl $OWS).Server.Name

Or possibly, you want to list all the runbooks that are available:

GET-SCOMonitorRunbook –WebServerUrl $OWS | format-table

You can now externally start a runbook manually (without launching the Orchestrator Runbook Designer interface or relying on the schedule within):

$rb=Get-SCOMonitorRunbook -webserverURL $web | where { $_.Name -eq 'Monitor Email' }

Start-SCORunbook -webserverURL $web -RunbookGuid $rb.Id

Or possibly, you want to stop one:

$rb=Get-SCOMonitorRunbook -webserverURL $web | where { $_.Name -eq 'Monitor Email' }

$list=GET-Scojob –webserverurl $ows –alljobs

$RBstop=$list.job | where { $_.Job.Status –eq ‘Running’ –and $_.Job.RunbookID –eq $rb.RunbookID }

$RBstop | STOP-SCOjob –webserverurl $ows

Much like Windows PowerShell, Orchestrator has a powerful community following that is helping to enhance and build the product.

So there you have it…many of the bits, pieces, and catch 22s I’ve picked up for Windows PowerShell and Orchestrator. Hopefully with what I’ve passed along, you have a little more time to yourself each day knowing how easy you can leverage these technologies together!

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

Sean Kearney, Honorary Scripting Guy
Windows PowerShell MVP

PowerTip: List Runbooks with PowerShell

$
0
0

Summary: Use community-based cmdlets to list available runbooks in Orchestrator.

Hey, Scripting Guy! Question How can I list the runbooks in Orchestrator by using Windows PowerShell?

Hey, Scripting Guy! Answer Leverage the Orchestrator Web Service PowerShell Cmdlets from CodePlex, and use the following new cmdlets:

$ORCHSRV=”MyOrchestratorServerName”

$OWS=NEW-SCOWebServerURL –servername $ORCHSRV

GET-SCOMonitorRunbook –WebServerUrl $OWS | FORMAT-TABLE Path,Name,Id -autosize

Weekend Scripter: Use Hash Table with PowerShell to Create a Simple Piano

$
0
0

Summary: Use a hash table to play musical notes in the console.

Honorary Scripting Guy, Sean Kearney, here—filling in for our good friend, Ed Wilson.

Today I decided to have some fun. It’s the weekend, I was bored, and I had too much time on my hands. (I have friends who suggest this happens a lot!)

I knew that in Windows PowerShell, I can make a beep noise by executing this:

[console]::beep(500,100)

If you check online, you will see that two values can be played with. The first is the frequency and the second is the duration. So if you want to drive the family dog (or possibly most of the people at the breakfast table) bonkers, you could do something like this

[console]::beep(7000,65000)

Of course we like the family dog, so we’re not going to actually do this. But it shows that we can alter frequencies and durations of the sound. So this is where my brain got bored. I wanted to do something that I hadn’t done in a very, very, very long time.

I wanted to turn my computer into a piano. It’s something I had done a long time ago on my old Commodore Vic 20. Granted, the console beep has none of the features I had on my Vic 20, or even in the early Commodore 64 SID chip. But I can make noise.

So I mucked about and figured out the notes for my piano by ear and by singing “Do Re Mi Fa So La Ti Do” about a hundred times. No, I didn’t sit down with a proper tuning fork, so for the most part, my notes are about as on-key as an angry parrot singing.

Here is my scale (my very off-key scale, I might add!) created in Windows PowerShell:

[console]::beep(290,400)

[console]::beep(330,400)

[console]::beep(360,400)

[console]::beep(390,400)

[console]::beep(440,400)

[console]::beep(480,400)

[console]::beep(530,400)

[console]::beep(580,400)

Cool. I’ve got some notes. Now for challenge number two…

I need a way to listen to the keyboard. Fortunately, this is actually pretty easy. By using the $Host variable and the following technique, we can listen to the keyboard:

$Key=$HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

This will allow us to wait until any key on the keyboard is pressed. Not the “ANYKEY”—they’ve stopped shipping that in newer models of computers.

We’ll have to run an additional command to make sure a pile of keys don’t build up in the keyboard queue:

$HOST.UI.RawUI.Flushinputbuffer()

Try this in your Windows PowerShell console: Tap the letter H, and you’ll notice some interesting results in the value of $Key:

Image of command output

You’ll see it traps the ASCII value of the key entered, in addition to the actual string content. So we know that we have an easy way to listen to the keyboard and retrieve information from it.

Let’s pick a set of characters for the “Piano” keyboard. We’ll take the regular notes (not sharp or flat) first, starting as the letter Q:

QWERTYUIOP

And then for the other notes, we’ll use appropriate numeric keys:

23 567 90

So our keyboard will look like this:

 2 3 5 6 7 9 0

QWERTYUIOP

But how will we match the keys to the notes? A big nasty pile of IF statements?

No, this is a perfect opportunity to set up a hash table. We’ll match the keys to each note value. I’ve also taken the liberty to add in some additional notes, such as the missing sharps, and a few extra notes beyond the base scale:

[array]$piano=$NULL

$piano+=@{"Q"=290}

$piano+=@{"2"=310}

$piano+=@{"W"=330}

$piano+=@{"3"=345}

$piano+=@{"E"=360}

$piano+=@{"R"=390}

$piano+=@{"5"=415}

$piano+=@{"T"=440}

$piano+=@{"6"=460}

$piano+=@{"Y"=480}

$piano+=@{"7"=505}

$piano+=@{"U"=530}

$piano+=@{"I"=580}

$piano+=@{"9"=605}

$piano+=@{"O"=630}

$piano+=@{"0"=670}

$piano+=@{"P"=710}

Lovely. We have a list of keys matched to numbers. If only there was an easy way to search an array for information…

But of course, in Windows PowerShell there is! Simply plug the value you’re looking for into the array. If it matches any entries, it will return them. For example, to find the entry that contains “T”, enter:

Image of command output

Oooo! So a simple little line like this should play a note after hitting a key:

$Key=$HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

$HOST.UI.RawUI.Flushinputbuffer()

$Note=$Piano.($Key.Character)

[Console]::Beep($Note,100)

So our loop would look something like this if we wanted to play it forever and ever and ever:

DO {

$Key=$HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

$HOST.UI.RawUI.Flushinputbuffer()

$Note=$Piano.($Key.Character)

[Console]::Beep($Note,100)

} Until ($False)

Come back tomorrow, and we’ll build on these ideas in an even more interesting toy, including a little error trapping and visualization! 

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

Sean Kearney,
Honorary Scripting Guy and Windows PowerShell MVP 

PowerTip: Use PowerShell to Wait for a Key Press

$
0
0

Summary: Learn about the Windows PowerShell version of “Pause.”

Hey, Scripting Guy! Question How can I use Windows PowerShell to wait for a key in scripts like I used to use “Pause” in the command console?

Hey, Scripting Guy! Answer Use the $Host variable in the console:

$HOST.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") | OUT-NULL
$HOST.UI.RawUI.Flushinputbuffer()

Weekend Scripter: Create a Visual Piano with Windows PowerShell

$
0
0

Summary: Use Windows PowerShell to interact with the console display.

Honorary Scripting Guy, Sean Kearney, here—filling in for our good friend, Ed Wilson.

For some reason, I find a need to open today’s blog post like a soap opera—you know, “Last time for Sean Kearney on the Hey, Scripting Guys! Blog.”

Sigh, it feels that way…

Last time, we played with a hash table and keyboard input to create a simple toy to play with—a loud, off-key piano in Windows PowerShell. It is somewhat (but not much) worse than my singing voice.

Today we’re going to polish it off a bit. A little error trapping. And how about an actual keyboard on the screen to interact with our piano?

First, I’ll show you a simple keyboard that I spent all day drawing up (or maybe it was only my lunch hour):

[array]$keyboard=$Null

$keyboard+=""

$keyboard+=" _____________________________________________________________"

$keyboard+=" ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !"

$keyboard+=" ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !"

$keyboard+=" ! !___! !___! ! !___! !___! !___! ! !___! !___! !"

$keyboard+=" !  !  !  !  !  !  !  !  !  !  !"

$keyboard+=" !  !  !  !  !  !  !  !  !  !  !"

$keyboard+=" !_____!_____!_____!_____!_____!_____!_____!_____!_____!_____!"

$keyboard+=""

$keyboard+="  *** Be A True Rockstar and Use WindowsPowerShell *** "

This may not be a fancy keyboard, but it will work nicely. We are going to map the keyboard that we built yesterday to physical positions on the screen.

What am I trying to do?

I am going to make sure that every time I hit a note on the keyboard, a key is highlighted on the screen. So we’ll need to identify the row and column for each note.

The first part is easy. All sharps are on one row (upper), and the rest of the keys are on the lower row. I played with the following combinations to set the positions on the screen:

$Location=$Host.UI.RawUI.cursorposition

$Location.Y=4

$Location.X=10

$Host.UI.RawUI.cursorposition=$Location; WRITE-HOST “*”

By altering values of Y, I was able to determine my rows:

Upper   3

Lower   6

Next, the less tricky part was to figure out the first position for each set of keys. After playing with the previous set of cmdlets and altering the value of X, I was able to determine the starting point for each: the lower row starts at position 6 and the upper row starts at position 9.

From that point, it was a matter of some simple math to determine the remaining columns because each key is exactly 6 points apart.

So now for some fun. Because we need to apply the X and Y coordinates based on the key that is tapped on the piano keyboard, we have to extend our original hash table as follows by adding a column to hold the Y and X values respectively for each key to display:

[array]$piano=$NULL

$piano+=@{"Q"=290,6,6}

$piano+=@{"2"=310,3,9}

$piano+=@{"W"=330,6,12}

$piano+=@{"3"=345,3,15}

$piano+=@{"E"=360,6,18}

$piano+=@{"R"=390,6,24}         

$piano+=@{"5"=415,3,27}

$piano+=@{"T"=440,6,30}

$piano+=@{"6"=460,3,33}

$piano+=@{"Y"=480,6,36}

$piano+=@{"7"=505,3,39}

$piano+=@{"U"=530,6,42}

$piano+=@{"I"=580,6,48}

$piano+=@{"9"=605,3,51}

$piano+=@{"O"=630,6,54}

$piano+=@{"0"=670,3,57}

$piano+=@{"P"=710,6,60}

With the values of the potential X and Y positions mapped to each key, we can search like before. But now, it will return not only the note, but also the Y and X coordinates for each key.

We can use a simple piece of script like the following to obtain the current location, and then write some information to the screen:

$Location=$Host.UI.RawUI.cursorposition

$Location.Y=$keyboarddata[1]
$Location.X=$keyboarddata[2]

$Host.UI.RawUI.CursorPosition=$Location

WRITE-HOST “*”

To return the original cursor position and erase the information, we can simply reset the position:

# Insert a Command we might do to eat up time, like maybe our [console]::beep(500,200)
$Host.UI.RawUI.cursorposition=$Location
WRITE-HOST " "

So really, we’re going to have a loop that runs forever. Or we could insert a special key—maybe such as “ESC”ape to “Escape” the loop?

do {

# Wait until some fool hits the keyboard

# We're not going to show the key on the screen

# And yes, we'll include Shift, Control and all the others

 

$Key=$Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

 

# Now flush it away so we don't get a pile of keys

# backing up in the queue (Flush? Backup? Ewww)

 

$Host.UI.RawUI.Flushinputbuffer()

 

# Grab the character from the $key Object and Match

# It Against the Array

 

$KeyboardData=$Piano.($Key.Character)

 

# Now IF we found something of value

# PLAY IT

 

If ($KeyboardData) {

 

$note=$KeyboardData[0]

$Location=$Host.UI.RawUI.cursorposition

$Location.Y=$keyboarddata[1]

$Location.X=$keyboarddata[2]

 

$Host.UI.RawUI.cursorposition=$Location

 

WRITE-HOST "*"

[console]::beep($note,150)

$Host.UI.RawUI.cursorposition=$Location

WRITE-HOST " "

 

}

 

# Key having fun until Somebody tries to ESCape

# Get it? Hit's the ESCape key? Bad Pun?

 

} until ( $key.VirtualKeyCode -eq 27 )

There you have it. A silly but fun project in Windows PowerShell that leverages hash tables and the console.

For some fun trivia, I did actually try to launch multiple beeps through different Windows PowerShell consoles to try to generate chords. No good. Doesn’t work. Although I would love to figure out later how to generate MIDI tones via Windows PowerShell. That could be more interesting.

If you don’t feel like doing a lot of typing, download it here from the TechNet Gallery: A Windows PowerShell Piano.

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

Sean Kearney,
Honorary Scripting Guy and Windows PowerShell MVP
 

PowerTip: Use PowerShell to Search a Hash Table

$
0
0

Summary: Quickly search a hash table in Windows PowerShell.

Hey, Scripting Guy! Question How can I easily search for information in a hash table full of data in Windows PowerShell?

Hey, Scripting Guy! Answer Plug in the name of a value, for example:

[array]$Hashtable=$NULL
$Hashtable+=@{Purple=54}
$Hashtable+=@{People=37}
$Hashtable+=@{Eater=78}

To find the value called People, add the name to the hash table variable:

$Hashtable.People

37

Conditional User Profile Deletion Revisited

$
0
0

Summary: Guest blogger, Bob Stevens, revises his script for conditional user profile removal.

Microsoft Scripting Guy, Ed Wilson, is here. I am happy to welcome back guest blogger, Bob Stevens. Take it away Bob…

Previously I released a blog post entitled Weekend Scripter: Use PowerShell for Conditional User Profile Removal. If you have not read this post, please do because it is necessary so that you’ll understand what I am talking about today.

It was pointed out to me that Windows Vista and later operating systems create temporary user directories instead of re-creating the directories when the user next signs in. To start at a reference point, here is the original script that I created:

IF ((Get-WmiObject Win32_OperatingSystem).version -like “5*”) {

$over30dayprofiles = @(Get-ChildItem -force "C:\Documents and Settings" | Where {

((Get-Date)-$_.lastwritetime).days -ge 30

} )

}

IF ((Get-WmiObject Win32_OperatingSystem).version -like “6*”) {

$over30dayprofiles = @(Get-ChildItem -force "C:\Users" | Where {

((Get-Date)-$_.lastwritetime).days -ge 30

} )

Set-Content ".\over30dayprofiles.txt" $over30dayprofiles

$over30dayprofiles = @(Get-Content ".\over30dayprofiles.txt" | Foreach-Object {

  $_ -replace 'Administrator', '' `
   -replace 'LocalService', '' `
   -replace 'NetworkService', ''

} | Select-String -pattern "\w" | ForEach-Object { $_.line })

$count = $over30dayprofiles.count

$i = 0

Set-Location 'C:\Documents and Settings'

Do {

 Remove-Item -force -recurse $over30dayprofiles[$i]

 $i++

}

Until($i -ge $count)

The first alteration that we need is to add a message to the user in the event that there are no profiles to remove. To do so, directly after we remove the desired accounts and white space from the variable $over30dayprofiles, we add the following:

If ($over30dayprofiles.count -eq 0){Write-Host " all profiles have been accessed in the last 30 days"}

If ($over30dayprofiles.count -gt 0){

Because of the brace that is located at the end of the second IF statement, we need to add a closing brace at the end of the script. This will run the command inside the script only when there are profiles that have not been accessed within the past 30 days.

Directly after that, we add the command to determine the SID of each profile that we are going to remove. First we need to define in a variable the number of profiles that we are going to remove:

$count = $over30dayprofiles.count

The Count property simply counts the items in the $over30dayprofiles array. Next we need to state that this is only to berunin any version of Windows 6 and later. I explained how to do this in another previous post: Weekend Scripter: Use PowerShell for Conditional User Profile Removal.

IF ((Get-WmiObject Win32_OperatingSystem).version -like “6*”) {}

Inside the braces, we are going to use the WMI object Win32_userprofile. To do this, we need to use the Get-WMIobject cmdlet to call Win32_userprofile:

Get-WMIobject win32_userprofile

Because we only want two properties (SID and Path), we are going to filter it by using the pipe operator (|) followed by the Select cmdlet:

Get-WMIobject win32_userprofile | select

The property types are the same for all profiles, so no quotations are needed. We simply need to separate them by a comma and a space:

Get-WMIobject win32_userprofile | Select SID, Localpath

We are going to manipulate this further, so we pipe it into the file named ProfileInfo.txt:

Get-WMIobject win32_userprofile | Select SID, Localpath | Out-File .\ProfileInfo.txt

The next portion of the script utilizes a Do-Until loop, so we set a counter at 0:

$i = 0

Now let’s create the item that we are going to be manipulating:

New-Item -path .\SID.txt -itemtype File

And finally, we can start the Do-Until loop:

Do{}

Until()

Inside the braces that follow the Do statement, we are going to pull the contents of ProfileInfo.txt, select any string that has the currently selected value from the $over30dayprofiles array, and split the line at the first whitespace that occurs. This is done by first retrieving the data, and then selecting the line:

Get-Content .\ProfileInfo.txt | Select-String -pattern $over30dayprofiles[$i] |

Now we split the line at the first white space by using a regular expression:

Foreach-Object { $_ -split ’\s+’ }

And we select the first half of the string:

ForEach-Object { $_ -split '\s+' | select -f 1}

If we append this command to the end of the content and set the output location, this is the result:

Get-Content .\ProfileInfo.txt | Select-String -pattern $over30dayprofiles[$i] | ForEach-Object { $_ -split '\s+' | select -f 1} | Add-Content .\SID.txt

Now we nest this into the Do portion of our Do-Until loop, and add the escape value. An escape value is a predetermined number that will end the loop when the counter meets the inequality presented by the Until or While statements.

Do {

Get-Content .\ProfileInfo.txt | Select-String -pattern $over30dayprofiles[$i] | ForEach-Object { $_ -split '\s+' | select -f 1} | Add-Content .\SID.txt

$i++}

Until($i -ge $count)

As you can see, the escape value is $i when our counter reaches a value greater than $count. $count is the number of elements in the $over30daysprofiles array.

IF ((Get-WmiObject Win32_OperatingSystem).version -like “6*”) {

Get-WMIobject win32_userprofile | select SID, Localpath | Out-File .\ProfileInfo.txt

$i = 0

New-Item -path .\SID.txt -itemtype File

DO {

get-content .\ProfileInfo.txt | Select-String -pattern $over30dayprofiles[$i] | ForEach-Object {

                        $_ -split '\s+' | select -f 1

            } | Add-Content .\SID.txt

$i++

}

Until($i -ge $count)

$SID = @(Get-Content .\SID.txt)

Now we are going to take the contents of the SID.txt file, and set them as the values for another array, $SID:

$SID = @(Get-Content .\SID.txt)

Because this script is to be run on any current computer, we need to add the following line so that we are working out of the Documents and Settings folder:

IF ((Get-WmiObject Win32_OperatingSystem).version -like “5*”) {Set-Location 'C:\Documents and Settings'}

For the sake of clarity, the next set of script will be explained in its entirety.

First we set our counter and Do-Until statement:

$i = 0

Do {}

Until()

Now we add the conditional IF statements:

$i = 0

Do {

            IF(){}

            IF(){}

}

Until()

Next we add our operating system identifiers by using the WMI object we have already been using:

$i = 0

Do {

            IF((Get-WmiObject Win32_OperatingSystem).version -like “5*”){}

            IF((Get-WmiObject Win32_OperatingSystem).version -like “6*”){}

}

Until()

Here is where the script changes depending on the operating system. For version 5 operating systems, we need to simply remove the profile folders because they will re-create if the user signs in again. It was suggested that I use the utility Delprof for this, but because there is no way to differentiate between administrator accounts and user accounts, we will go with this:

$i = 0

Do {

            IF((Get-WmiObject Win32_OperatingSystem).version -like “5*”){

Remove-Item -force -recurse $over30dayprofiles[$i]}
            IF((Get-WmiObject Win32_OperatingSystem).version -like “6*”){}

}

Until()

Now we move on to what actually changed. As expressed in the comments from the previous post, when you delete the profile folder from the Users folder in Windows Vista and later, the operating system will continually generate a temporary profile because the registry key located at:

“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList”

So instead of removing the profile folder or doing some truly interesting stuff with the registry, we are going to use the win32_userprofile WMI object, this bit of script is courtesy of the user, JRV. Specifically, we are going to filter it for the SID in the $SID array that corresponds with the counter, and we are going to set this as the value of the $profile variable:

$profile = Get-WmiObject win32_userprofile -filter "SID='$($SID[$i])'"

Now that we have the $profile variable defined with the desired SID, we are going to delete the profile that it refers to. This is done with the Delete() property (this will NOT work without the empty parentheses).

$profile.delete()

Now we add these two lines together and nest them in our second IF statement:

$i = 0

Do {

IF((Get-WmiObject Win32_OperatingSystem).version -like “5*”){Remove-Item -force -recurse $over30dayprofiles[$i]}

IF((Get-WmiObject Win32_OperatingSystem).version -like “6*”){ $profile = Get-WmiObject win32_userprofile -filter "SID='$($SID[$i])'"

 

$profile.delete()}

}

Until()

We need to add the rest of the script to increment the counter:

Do {

IF((Get-WmiObject Win32_OperatingSystem).version -like “5*”){Remove-Item -force -recurse $over30dayprofiles[$i]}

IF((Get-WmiObject Win32_OperatingSystem).version -like “6*”){ $profile = Get-WmiObject win32_userprofile -filter "SID='$($SID[$i])'"

 

$profile.delete()}

 $i++

}

Until($i -ge $count)

And finally, we need to close the brace that we left open with If “($over30dayprofiles.count -gt 0){“ and clean up our temporary files:

Remove-Item .\over30dayprofiles.txt

Remove-Item .\ProfileInfo.txt

Remove-Item .\SID.txt

}

Following is the complete and working script. Although it will generate errors if there is an issue with the accounts being removed, it will function on all others. These errors are reported, and the script will continue to run to completion. I have used Bold formatting to highlight the sections that have been added. _____________________________________________________________

Set-Location $home\desktop

New-Item -path .\over30dayprofiles.txt -itemtype File

IF ((Get-WmiObject Win32_OperatingSystem).version -like “5*”) {

$over30dayprofiles = @(Get-ChildItem -force "C:\Documents and Settings" | Where {

((Get-Date)-$_.lastwritetime).days -ge 30

} )

}

IF ((Get-WmiObject Win32_OperatingSystem).version -like “6*”) {

$over30dayprofiles = @(Get-ChildItem -force "C:\Users" | Where {

((Get-Date)-$_.lastwritetime).days -ge 30

} )

}

Set-Content ".\over30dayprofiles.txt" $over30dayprofiles

 

$over30dayprofiles = @(Get-Content ".\over30dayprofiles.txt" | Foreach-Object {

 

  $_ -replace 'Administrator', '' `

  -replace 'LocalService', '' `

  -replace 'NetworkService', ''`

  -replace 'desktop.ini', ''`

  -replace 'temp', ''`

  -replace 'All Users', ''`

  -replace 'Default', ''`

  -replace 'Default User', ''`

  -replace 'Public', ''`

  -replace ' User', ''

 

} | Select-String -Pattern "\w" | ForEach-Object { $_.line })

If ($over30dayprofiles.count -eq 0){Write-Host "all profiles have been accessed in the last 30 days"}

If ($over30dayprofiles.count -gt 0){

$count = $over30dayprofiles.count

IF ((Get-WmiObject Win32_OperatingSystem).version -like “6*”) {

get-WMIobject win32_userprofile | select SID, Localpath | Out-File .\ProfileInfo.txt

$i = 0

New-Item -path .\SID.txt -itemtype File

DO {

Get-Content .\ProfileInfo.txt | Select-String -pattern $over30dayprofiles[$i] | ForEach-Object {

                        $_ -split '\s+' | select -f 1

            } | Add-Content .\SID.txt

$i++

}

 

Until($i -ge $count)

$SID = @(Get-Content .\SID.txt)}

IF ((Get-WmiObject Win32_OperatingSystem).version -like “5*”) {Set-Location 'C:\Documents and Settings'}

 

$i = 0

Do {

  IF((Get-WmiObject Win32_OperatingSystem).version -like “5*”){

   Remove-Item -force -recurse $over30dayprofiles[$i]

  }

 

  IF((Get-WmiObject Win32_OperatingSystem).version -like “6*”) {

   $profile = Get-WmiObject win32_userprofile -filter "SID='$($SID[$i])'"

   $profile.Delete()

  }

 $i++

}

Until($i -ge $count)

 

Remove-Item .\over30dayprofiles.txt

Remove-Item .\ProfileInfo.txt

Remove-Item .\SID.txt

}

The complete script is uploaded to the Script Center Repository: Over 30 Day Removal. Please download it from there, rather than attempting to copy from this web page. As with my previous posts, I welcome all critiques. It is my firm belief that anything can be improved by the collectiveknowledge of the community.

~Bob

Thank you, Bob, for your time and efforts in writing this blog to share with our readers.

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

Ed Wilson, Microsoft Scripting Guy 


PowerShell Summit North America 2014 announced

$
0
0
PowerShell Summit North America 2014 will open for public registration on September 15th; we'll have some discounts available and everything is described at http://powershell.org/wp/?p=9776 . We've already run through registration periods for our 2013...(read more)

PowerTip: Display Only Hidden Files and Folders in PowerShell

$
0
0

Summary: Use Windows PowerShell to display only hidden files and folders.

Hey, Scripting Guy! Question How can I use Windows PowerShell 3.0 to display only hidden files and folders?

Hey, Scripting Guy! Answer Use the –Hidden parameter from Get-ChildItem:

Get-ChildItem -Hidden

Recursively Search Active Directory Security Groups

$
0
0

Summary: Guest blogger, system admin Marc Carter, talks about recursively searching AD security groups with Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. Marc Carter is back with us today as our guest blogger. Marc is a system administrator at the Corpus Christi Army Depot. Take it away, Marc…

Like many other mid- to large-sized organizations, we use Active Directory Security Groups to help us manage access and permissions to our organization’s various IT resources (such as file shares and Microsoft SharePoint). By nesting those security groups, we create a parent/child hierarchy that is representative of our organization’s business structure. Throughout most of that business structure, our end-user environment consists of a standard pyramid of three primary groups:

  • Few: executive-level management
  • Several: mid-level chiefs
  • Many: staff members

Employee’s positions within that hierarchy dictate the level of access they have to subordinate resources. The higher you are in the organization’s hierarchy, the more resources you have access to. Members at the staff-level typically only require access to resources that impact their daily tasks and duties, and they aren’t concerned with resources outside their office or work area. Moving up the pyramid, chiefs and executives need access at their level and to the subordinate resources directly under them. We accomplish this one-to-many relationship by adding groups as “Members” to their subordinate security groups.

Thankfully, the Active Directory cmdlets that come with Windows PowerShell 2.0 make it extremely easy to view and manage members of an Active Directory group. By using the Get-ADGroupMember command, you can view the member objects of a group by simply specifying an identity value. In fact any one of the following four options can be used to identify which group you’re interested in:

  • DistinguishedName
  • GUID (objectGUID)
  • Security Identifier (objectSid)
  • Security Accounts Manager (SAM) Account Name (SAMAccountName)

In the following example, I’m using the SAMAccountName of one of the mid-level chief groups to return a list of members.

Image of command output

Text version:

Get-ADGroupMember -Identity “alpha-chiefs”

 

distinguishedName : CN=roger.moore,OU=Users,OU=M16,DC=contoso,DC=com

name    : roger.moore

objectClass  : user

objectGUID  : 00743c39-22a2-415a-812c-062b4af5c349

SamAccountName : roger.moore

SID    : S-1-3-21-4201780169-38368224-110244791-28519

Using the optional Recursive switch returns a list of accounts that have a membership to the specified group. It provides a bottom-up perspective of membership, and it is effective to see who has permissions on a specific resource.

Get-ADGroupMember -Identity “alpha-staff” -Recursive

Typically, this information is sufficient to analyze and manage resources on a daily basis. However, because of change or transition in our operations, we also have a need to assess our memberships from a top-down view to see not only what resources align under the executive or mid-level managers, but also the staff members who belong to those groups.

To accomplish this, I wrote an advanced function based on the Get-ADGroupMember and Get-ADGroup cmdlets. I use them to traverse the MemberOf attribute and list users within each of the associated subordinate groups.

I begin by defining the VerbosePreference constant and trying to load the Active Directory module (if not already present) within a Try/Catch statement so the script will fail if it’s unable to access the necessary cmdlets:

Image of command output

Text version:

Try {

 If(-not(Get-Module -Name "ActiveDirectory")){

  Import-Module -Name ActiveDirectory

 }

} Catch {

 Write-Warning "Failed to Import REQUIRED Active Directory Module...exiting script!”

 Write-Warning "`nhttp://technet.microsoft.com/en-us/library/ee617195.aspx"

 Break

}

When the script successfully passes this test, I start the process of collecting and storing information within a PSCustomObject array, again using Try/Catch so I don’t end up collecting superfluous or unnecessary information.

On line 59 in the following example, I define the $ADGroup variable with the results of the Get-ADGroup cmdlet and include the Members and MemberOf properties. I’m now ready to start my first loop through the Members collection, adding them to my array. I use an array because I want to collect the name of the Active Directory Group where each member belongs as I traverse down. I use splatting to pass my parameters to my array as shown in lines 64-73 in the following example:

Image of command output

Having recorded all the Members at the current group level, I’m now ready to start my recursion and loop through the MembersOf attribute. This Active Directory property contains all the subordinate groups that the dominate group is a member of (thus the name MemberOf).

Passing this information back to the function, I start the entire process all over again until there are no more subordinate group memberships (that is, MemberOf is empty). I’m now ready to exit my function, but before doing so, I want to display all that information. I simply call the array and then reset the $VerbosePreference constant back to its original state (when I first initiated the script).

I have to point out that our organization has a fairly stringent policy for naming offices and organizations, which makes it easier to sort the data, but this will work for any situation.

Uses for this script

Following are two of my favorite uses for this script:

  • Use Group-Object to provide a quick overview of each group and the count of users (members) within each group.

Image of command output

  • Format output in a table (or use Out-GridView) to get a detailed list by Group of all the members. This is an effective way to provide our administrative staff with a security group view of our organizational roster. It helps us ensure that only the folks who require access to sensitive information have it.

Image of command output

I hope this information helps you better organize your company’s Active Directory groups, memberships, and permissions. You can download this function from the Script Center Repository: Get-MemberOfGroup.

I look forward to your comments and suggestions.

~Marc

Thank you, Marc.

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

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Find Disabled User Accounts in AD DS

$
0
0

Summary: Easily find disabled user accounts in Active Directory Domain Services (AD DS) by using Windows PowerShell.

Hey, Scripting Guy! Question How can I easily use Windows PowerShell to find disabled user accounts?

Hey, Scripting Guy! Answer Use the Search-ADAccount cmdlet from the Active Directory module in the RSAT tools, and specify the AccountDisabled and UsersOnly switches:

Search-ADAccount -AccountDisabled -UsersOnly

Creating ACLs for Windows Azure Endpoints—Part 3

$
0
0

Summary: Learn how to use Windows PowerShell to create ACLs for Windows Azure endpoints.

Microsoft Scripting Guy, Ed Wilson, is here. Windows networking engineer, James Kehr, is back with us today to share more Windows Azure goodies. Now here’s James…

Imagine this if you will. I’ve written two rather large blog posts about creating endpoints and ACLs with Windows PowerShell in Windows Azure. Each one was long enough to be considered a good size short story in the literary world. If you would like a frame of reference for this post, here they are:

And then I see it. An update to the Windows Azure PowerShell module released the day before my deadline. Do I ignore it, or do I install it and make sure my script still works? Better safe than sorry…update goes on…

Test endpoint script. All good.

Test ACL script. Works great.

Test load balanced endpoint script. No problems found.

Awesome. All is well. “Hmmm,” I thought. “Hmmm,” I said aloud. “I wonder if they fixed the -VM parameter?” Sure enough, it works. Now comes the dilemma. Push back the publishing date and rewrite, or move on as planned? The script does work after all. What to do, what to do?

At this point, a committee was called to order with five executives, sixteen directors, and forty-two middle managers. After six hours of deliberations, a sub-committee of eighty-four Windows PowerShell and Windows Azure experts was created. The sub-committee then formed an action plan, signed in triplicate, carbon copied, emailed, responded to, and replied to all. This generated a massive email storm, which was lost to drive corruption, restored, rechecked, and brought back to the committee. They convened an independent review and gave recommendations to the sub-committee, which was waiting for a secondary audit from Vogon Consulting services, who gave a recommendation to the committee to rewrite the blog. The committee then ignored the recommendations and ordered the blog posts be published as is.

Or at least that’s how some people on the Interwebz might think it happened. In reality this is closer to what really happened…

Ed: Hey James, why don’t you just write a follow-up post with the shortened script?

Me: Sure.

Ed: Cool, thanks.

Which brings us to this post—the unexpected Part 3.

ACLs done quicker

This post focuses on making the endpoint and ACL script from Parts 1 and 2 shorter. Specifically how the fixed -VM parameter works and how it can make your script a bit more efficient. I will forego the technical nitty gritty. If you find yourself lost because of this omission, please read Part 1 and Part 2, which is where you will find the technical and script deep dives.

The first thing you need to do is get the newest Windows Azure PowerShell module. For this script to work you need at least the August 2013 update. The latest standalone installer can be found at: WindowsAzure/azure-sdk-tools.

This is also a great resource to see what cmdlets have been added since the previous update. This is important to know because the Windows Azure PowerShell module is in constant change, and features that weren’t there last month could very well be there this month. As the Windows Azure features settle and the Windows Azure PowerShell module matures, it won’t change as rapidly, but for now expect change.

The post-August 2013 Windows Azure PowerShell module script can be changed to this:

# create an endpoint for HTTP

$avm = Get-AzureVM -ServiceName Web01

 

# create a new ACL

$acl = New-AzureAclConfig

 

# add some rules to the ACL

Set-AzureAclConfig -AddRule -ACL $acl -Order 0 -Action Permit -RemoteSubnet "1.2.3.4/31" -Description "Allow App01"

Set-AzureAclConfig -AddRule -ACL $acl -Order 1 -Action Permit -RemoteSubnet "172.16.0.0/29" -Description "Allow corp proxies"

Set-AzureAclConfig -AddRule -ACL $acl -Order 2 -Action Deny -RemoteSubnet "0.0.0.0/0" -Description "DenyAll"

 

# create endpoint

Add-AzureEndpoint -Name "HTTP" -VM $avm -ACL $acl -Protocol tcp -PublicPort 80 -LocalPort 80 | Update-AzureVM

The big advantage to this technique is that you can make all your changes offline, and then push them to Windows Azure all at once. The AzureVM variable ($avm) stores all your changes. When you are done making changes, simply pipe $avm to Update-AzureVM. Or do what I did, and pipe your final change to Update-AzureVM.

The fixed -VM parameter also means that you can perform other endpoint and ACL commands without doing a lot of pipeline work.

# get HTTP endpoint

Get-AzureEndpoint -VM $avm -Name http

 

# get HTTP ACLs

Get-AzureAclConfig -vm $avm -EndpointName http

 

# remove the HTTP endpoint

Remove-AzureEndpoint -vm $avm -Name HTTP | Update-AzureVM

When you run commands this way, please remember that the changes are made to the AzureVMobject and not to the virtual machine. Because of this these cmdlets, using -VM will reflect the object, and not what’s in Windows Azure. If you need to see what’s in Windows Azure, using the older pipeline technique is still the best:

Get-AzureVM -ServiceName Web01 | Get-AzureAclConfig -EndpointName http

A little love for load-balanced endpoints

There is one gotcha with the -VM parameter that I would like to mention. It currently does not support arrays of AzureVM objects. This means the script for load-balanced endpoints is, at this time, almost unchanged. When you create a new load-balanced endpoint, you can shorten the script a bit, but you must still use the pipeline. The only real difference is that you can now create a variable that contains an array of Windows Azure VM objects. This allows you to queue several changes and then pipe the variable to the update command.

# get VMs in LB set

$avm = Get-AzureVM -ServiceName jak-az-12r2-tst

 

# create ACL

$acl = New-AzureAclConfig

Set-AzureAclConfig -AddRule -ACL $acl -Order 0 -Action Permit -RemoteSubnet "1.2.3.4/31" -Description "Allow App servers"

Set-AzureAclConfig -AddRule -ACL $acl -Order 1 -Action Permit -RemoteSubnet "172.16.0.0/29" -Description "Allow corp proxies"

Set-AzureAclConfig -AddRule -ACL $acl -Order 2 -Action Deny -RemoteSubnet "0.0.0.0/0" -Description "DenyAll"

 

# create new load balanced endpoint

$avm | `

Add-AzureEndpoint -Name "HTTPS" -ACL $acl -Protocol TCP -PublicPort 443 -LocalPort 443 -ProbePort 3443 -ProbeProtocol HTTP -ProbePath "/” -LBSetName "Web-HTTPS-LB" | `

Update-AzureVM

That does it for Windows endpoints and ACLs. I even kept this post down to short-short-story length. I hope to publish a few more Windows Azure PowerShell blog posts in the near future, so stay tuned.

~James

Thank you for sharing, James.

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

Ed Wilson, Microsoft Scripting Guy 

Viewing all 3333 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>