Powershell

If you are in the Southeast US, you may be interested in the upcoming Codestock event coming up in June in Knoxville, TN. It seems to be heavily slanted towards developers, but they are doing IT Pro and Entrepeneur tracks this year as well. I have submitted one session for my Managing VMware with PowerShell thing. If you have a minute, please go over to the site to register and vote my session up.

I’ve never been to Codestock before, but it looks like fun. In fact, it looks like a lot more fun than your typical canned vendor convention. I don’t plan on doing many speaker engagements this year aside from the occasional SMUG or APUG meeting here in Atlanta, but I thought going to Knoxville might be a neat excuse to get out an d see a new city. The drive to Knoxville from Atlanta is pretty nice if you go through Chattahoochee and Nantahala national forests, so we are looking forward to that.

Brasstown Bald Road by tfdavis.

(credit tfdavis on flickr)

2010-2
28

This email arrived in my inbox today:

Just finished your book for the second time.  Man, have I learned a lot!  I am way ahead of the PowerShell curve for admins in general.  No one at my work can touch me!  SQl, AD, VMware, IIS, Group Policy, log extraction, etc…  I do it all with PowerShell.

A lot of people say, you can do all this stuff in the VMware client.  My reply is simply- no you can’t…  I have at least 30 automated PowerShell scripts that run throughout the week.  I don’t know how I lived without PowerShell. 

Again, your book rocked.  I actually paid for it!  I won’t let anyone borrow it either.  I need it way too much.  I tell them to BUY THEIR OWN!!!

G.B.

I really enjoyed reading it and wanted to share this with everyone. Very cool of him to take the time to send me the note.

Powershell

image When using PowerCLI, the first thing you have to do is to create a connection and authenticate yourself to your vSphere and/or vCenter servers. This is done with the Connect-VIServer cmdlet. Sometimes, this connection can be slow, taking ten or more seconds just to display a password prompt! That gets old pretty quickly.

There is a good reason for the slowness before you are prompted for credentials, and turns out, it’s a feature, not a bug. PowerCLI supports a single-sign-on (SSO) authentication when you attempt a connection to a vCenter server. What happens in the background is that your current Windows credentials are being passed on to the server and that is tried first, before even prompting you for credentials. This is great if you are sitting at the office and have a fast link to the vCenter server, and you happen to be logging into your workstation with a domain accont, and that domain account has vCenter rights. This transparent passing of credentials is definitely a timesaver under those circumstances.

But on the other hand, what if you are connecting from home over a slow link? What if you are on your home PC or a local account? What if, due to security policies at your company, your normal user account doesn’t even HAVE admin privileges? Yup, the authentication attempt fails (or simply takes a while), and you are left twiddling your thumbs, waiting for the “real” login prompt to appear.

Resolution

The fix is an easy one. Instead of typing this to connect:

Connect-VIServer vcenter.domain.com

…type something like this:

Connect-VIServer vcenter.domain.com -Credential (Get-Credential)

or the less-recommended, yet still quite functional:

Connect-VIServer vcenter.domain.com -user myuser -password mypass

By using one of these methods, you are instructing Connect-VIServer to explicitly use a set of credentials which you specify. This way, it won’t bother attempting to pass along your current credentials, thus saving you a few seconds and perhaps a gray hair or two.

Powershell

I needed some source text to test a regular expression pattern, so my goal tonight was to generate some. The regex pattern in question finds email addresses, so I needed to be sure to embed real-looking email addresses inside of gibberish. Step number one: I need some random letters. PowerShell v2’s Get-Random cmdlet comes to the rescue!

Get-Random has two modes. The first mode allows you to return random numbers, and you can specify a min and max range. The second mode will return random items from a list, and as an added bonus, you can specify the number of items to return. I plan on using both modes in this exercise.

In order to build gibberish words or email addresses, I need to start with a list of allowable characters. Let’s keep it simple and restrict things to lowercase letters, although adding in numbers would be simple.

You all remember ASCII, right? This is a conversion table that has been used to represent numeric values for letters (and every other character on you keyboard, plus others) for a long, LONG time. You are slowly seeing ASCII encoding supplanted by Unicode as that table has a much larger address space and can handle non-Latin alphabets, but ASCII suits me just fine. We are going to use ASCII values and PowerShell’s range operator (..) to generate the list of allowable characters.

If you have worked with Vbscript, then you might know how to to ASCII conversions with the Chr() function. You give that function a number, and it spits out the ASCII value. The reverse is done with the Asc() function. In PowerShell, it’s not done the same way at all, so just forget that. Instead, what we are going to do is to convert back and forth between a “char” (character) .NET type. Chars are really sort of an in-between data type. They look like strings (i.e., it’s a letter), but they are very easily converted into integers.

So let’s take that knowledge and combine it with a technique called “casting”. To cast in PowerShell means to state that you want a particular value to be a certain data type. For example, if I have a number, and I want to make sure it is treated like a string in my script, I can cast it as a string like so:

[string]12

If you pipe that to Get-Member, you’ll see that the result is a string object, with all of the properties and methods which that type has, as opposed to the much more basic [int] type.

Moving on, let’s take the letter “a”, and the letter “z”, and turn it into a range containing all of the letters in between. PowerShell’s range operator can be used here, but it only works with integers. I could ask a search engine for an ASCII chart to get the numbers I need, but there’s no need, I’ll just convert from the letters directly.

Here’s how to convert a single letter into its ASCII number representation:

PS > [int][char]'a'
97

What I am doing here is casting twice. Anything surrounded by single or double quotes is a string. I can convert any single letter (or symbol, or whatever) to a char data type by casting it as you can see. Then I take that char and cast it immediately to an integer, and as I said before, that’s an easy conversion for PowerShell to do because that’s the way chars types are wired.

Now we have our first integer. Just replace the ‘a’ with a ‘z’ and we have the second.

PS > [int][char]'z'
122

These integers are going to be perfect as input to the Get-Random cmdlet. Here’s how to return random letters using Get-Random’s first mode:

PS > $min = [int][char]'a'
PS > $max = [int][char]'z'
PS > Get-Random -Minimum $min -Maximum $max
104
PS > [char](Get-Random -Minimum $min -Maximum $max)
l
PS > [char](Get-Random -Minimum $min -Maximum $max)
q
PS > [char](Get-Random -Minimum $min -Maximum $max)
r

As you can see, turning an integer back into a letter is pretty simple, you just cast it to a [char]. (The parentheses are necessary.) And you can also see a new random letter popping up at each execution of Get-Random. Great! So how do we make random words? Well, in the context of this blog post, a word consists of an array of characters. That makes sense, right? There are a few ways to go from here to create the requisite [char] array. I could create a for loop, and run the above command inside the loop.

However, there is an easier way. Let’s go back a step and have a look at Get-Random’s second mode. Here is a table showing the two parameter sets (output created with my Get-Parameter script):

   ParameterSet: RandomNumberParameterSet

Name    Type       IsMandatory Pipeline
----    ----       ----------- --------
SetSeed Nullable`1       False    False
Maximum Object           False    False
Minimum Object           False    False

   ParameterSet: RandomListItemParameterSet

Name        Type       IsMandatory Pipeline
----        ----       ----------- --------
SetSeed     Nullable`1       False    False
InputObject Object[]          True     True
Count       Int32            False    False

We used Minimum and Maximum in the first mode. Now we are going to use InputObject and Count. This mode is really handy because you can supply an array of items (letters in this case) as input, and tell it how many random items to return as output! That means no loop, so the code is going to be much simpler.

First, let’s build an array of all lowercase letters. We already know the numeric values to use in the range, so let’s use those. I’m going to use a little trick to take the integer range and cast it in one step to an array of characters, which is exactly what we want:

PS > $alpha = [char[]]($min..$max)
PS > $alpha | Select-Object -First 3
a
b
c

We build the range with “$min..$max” and put that in parentheses. Then we cast it, but not as a single [char], but as an array of [char]’s by adding an empty set of brackets []. Now, the variable $alpha contains our input to Get-Random. The next step is easy, just pass this variable to the cmdlet and give it a count:

PS > $alpha | Get-Random -Count 5
t
f
a
b
c

Presto! A five-letter word! Well…sorta. What we have is a series of characters, one per line. To turn this into adjacent characters we can cast the whole thing as a string.

PS > [string]( $alpha | Get-Random -Count 5 )
i h s p z

Almost there, we just have to get rid of those extra spaces. The spaces are generated because of something called the “output format separator”, otherwise known as $OFS. This is a variable predefined by PowerShell to be a single space, but you can change it to whatever you want. Here’s that final step:

PS > $ofs = ''
PS > [string]( $alpha | Get-Random -Count 5 )
qfzwg
PS > [string]( $alpha | Get-Random -Count 5 )
dnhbq

Now I am just a hop, skip, and a jump from generating random email addresses, but that’s enough for tonight.

Powershell

Please comment…

Logo1:
logo1

Logo 2:
logo3

Powershell

This is a sample script that I created to show how you might create a relatively complex virtual farm environment. The hypothetical requirements for this farm are:

  1. Add 10 ESX servers to a vCenter, one for each customer
  2. Create a resource pool for each customer
  3. Inside each of these, create a resource pool for each server role, and a specified number of virtual machines, based on previously-created VM templates
    1. 2 x proxy server
    2. 4 x web server
    3. 2 x app server
    4. 2 x database server

I hope you find the script useful!

2009-12
15

Just a quick post to get your comments. What do you think about this slide? Am I missing anything that needs mentioning here?

image 

P.S. Office “Smart Art” FTW

Powershell

A co-worker today asked me how he could redirect output from an external executable into a variable. Seemed easy enough, you just do this:

$var = mycmd.exe

He tried it and got back a $null for his trouble. Turned out, the executable was writing to the error stream (STDERR) instead of STDOUT. Now, the question came up of how to capture that information.

We had to get a little old school because this is a DOS convention (well, much older than that but anyway) and has nothing to do with PowerShell. The answer wasn’t hard, but the response wasn’t what we expected. Observe:

PS > $a = netstat bob 2>&1 # cause intentional err and redirect
PS > $a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

PS > $a[0].GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     ErrorRecord                              System.Object

I used “2>&1” to redirect the STDERR stream to the STDOUT stream. Worked fine, however when we tried to work with the results we found that it wasn’t a string array. Instead, as you see above, it is an array of ErrorRecord objects! In hindsight, that made sense to me. I mean, what else would you expect in the error stream but errors?

Anyway, long story short, the way to access the text inside of these error objects is by accessing the Exception property. But it was slightly more complex, as what you get is TWO errors. One with the “powershelly” NativeCommandError, and the second with the text that we needed. For example:

PS > $a[0]
netstat.exe :
At line:1 char:13
+ $a = netstat <<<<  bob 2>&1 # cause intentional err and redirect
    + CategoryInfo          : NotSpecified: (:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

PS > $a[1].Exception
Displays protocol statistics and current TCP/IP network connections.

NETSTAT [-a] [-b] [-e] [-n] [-o] [-p proto] [-r] [-s] [-v] [interval]

Powershell Windows

PowerShell is so cool…

I had no idea how to automate Outlook with COM before today. Took me about 5 minutes to learn how with PowerShell. I knew it could be done with VBS, right? That’s how viruses are made. :)

This won’t be a long blog unfortunately, but wanted to paste real quick a series of commands which I basically figured out in a shell interactively. I didn’t have to read any docs, Get-Member told me all I needed to know.

I did go back and add some comments. I hope you find it useful.

$ol = New-Object -com Outlook.Application # starts outlook

$ol.Reminders | select caption, nextreminderdate # show reminders

$ol | gm -mem method # show all methods (actions) on the com object

$n = $ol.CreateItem('olNoteItem') # creates a note

$n # display note object

$n.Body = 'test' # set body of note

$n | gm # display object members (methods & properties) of note

$n.Display() # show note

$n.Color # display color value

$n.Color = 4 # set color

1..5 | ForEach-Object { $n.Color = $_; sleep 1 } # change color of note 5 times

$m = $ol.CreateItem('olMailItem') # create mail object

$m # display mail object

$m | gm -mem property # show mail properties

$m.Subject = 'test' # set subject

$m.Body = 'test' # set body

$m.To = 'email@domain.com' # set to address

$m.Display() # display mail item on screen 

$m.Send() # send mail item

$ol # display outlook object

$ol | gm # display outlook methods

Powershell

If you are seeing crashes in MSCORSVW.DLL, try this, it may help (and it won’t hurt):

Start-Job {
    Set-Alias ngen (dir (join-path ${env:\windir} "Microsoft.NET\Framework") ngen.exe -recurse |
    sort -descending lastwritetime
    )[0].fullName
    ngen executequeueditems
}

For more details, see this Connect bug:

  • Microblog

  • Recent Posts

  • Recent Comments

  • meta

  • PowerShell Blogroll