if, oh if, wherefore art thou, if?

posh-getrand-v2

Recently, we looked at using PowerShell for generating pseudo-random names. The example script provided in that article was intentionally PowerShell version 1.0 and PowerShell version 2.0 compatible.

Those of you who know that PowerShell 2.0 is included in Windows 7 and Windows Server 2008 R2 and the foundation for the Exchange Management Shell in Exchange Server 2010 must be wondering what’s so new and great about PowerShell 2.0. In a series of articles, we’ll look at that from several angles – Exchange, Windows administration, and … well, we’ll start our journey with a language tack.

In the midst of that Get-RandomName script, we had a code snippet to pick a random first name, either male or female, from one of two distinct lists (arrays).

if( $rand.NextDouble() -lt $percentFemale ){

$gender = “male”

}

else{

$gender = “female”

}

$f = (Invoke-Expression (“`$_RN_{0}[`$rand.Next(`$_RN_{0}.Count)]” -f $gender)).Split(“`t”)[0].ToLower()

In PowerShell 1.0, the value of statements such as if or switch cannot be evaluated. PowerShell 2.0 changes this, which might not mean much to you if you aren’t prone to take the value of an if or switch statement, but… well, keep reading as we look at two variations on the above code.

First, in PowerShell 2.0, we can take the value of the if statement and therefore assign the variable $gender to the value of the if or else clause as follows.

$gender = if( $rand.NextDouble() -lt $percentFemale ){“male”}else{“female”}

That could of course still be written across six lines instead of one, however the important distinction is that we’ve specified the $gender = before the if, and not within each of the code blocks for the if and else clauses. If you’re a programmer familiar with the question-mark + colon operator in languages such as C, C++, and C#, then taking the value of an if or switch statement might seem ordinary. If you’re used to PowerShell 1.0, it might seem bizarre, but PowerShell 2.0 let’s us do this and more.

So riddle me this. If we can take the value of an if statement an assign a variable to the result, can we simply inject the whole shebang ($shebang = if( … ){ … }else{ … }) into the middle of another expression? Oh yes. Yes, we can. As such – noting that the following was written on one line in the modified Get-RandomName script which is only PowerShell 2.0 compatible.

$f = (Invoke-Expression (“`$_RN_{0}[`$rand.Next(`$_RN_{0}.Count)]” -f $(if( $rand.NextDouble() -lt

$percentFemale ){“male”}else{“female”}))).Split(“`t”)[0].ToLower()

The important “extra” syntax used to properly insert the if statement into the expression is to use $() around it.

PowerShell 2.0 has much more expressiveness as a scripting and programming language than PowerShell 1.0 had, making it that much more powerful in the arena of languages such as Icon and LISP. Yes, true fans, now with PowerShell 2.0 you can take the value of a switch block in an expression as well. “If” is just the beginning.

This is your brain on PowerShell… any questions?

Rose, by any random name…

posh-getrand

Mr. Shakespeare might not have had pseudo-random numbers nor huge names lists like those from the U.S. Census Bureau on his mind when he was writing Romeo and Juliet, yet if his “rose by any other name” allows us to generate pseudonyms for test systems, so be it.

Alright, I’ll put it to you straight. This article is about using my good friend Windows PowerShell to generate test data which could be used in a database, directory, spreadsheet, etc. For example, if you’ve ever wanted to generate a hundred test accounts in Active Directory, or 9764 mailboxes in Exchange Server, rather than just having boring names like user1, user2, etc. we can easily generate random names.

1..100 | %{ dsadd user “cn=user$_,ou=Test,dc=777,dc=wernerconsulting,dc=com” }

It’s true that a simple pipeline such as that shown above could easily generate accounts (well, it’s good if they have valid passwords and are enabled, but that’s marginally more complex). Several years ago when I had to generate test accounts, I found some files of sample names from the United States Census Bureau, then wrote a little script to generate user accounts in Active Directory based on pseudo-random combinations of first and last name.

Let’s revisit that now with Windows PowerShell. Assuming that we have downloaded three files of (1) female first names, (2) male first names, and (3) all last names, we could easily pick from the lists to compose fictitious names. Some URLs are at the bottom of this message.

Here’s an example PowerShell script to generate fictitious names.

$global:_RN_female = get-content FemaleFirstNames.txt

$global:_RN_male = get-content MaleFirstNames.txt

$global:_RN_last = get-content LastNames.txt

filter global:Get-RandomName( $percentFemale = 0.50 ){

BEGIN{

$rand = new-object Random

}

PROCESS{

$l = $_RN_last[$rand.Next($_RN_last.Count)].Split(“`t”)[0].ToLower()

if( $rand.NextDouble() -lt $percentFemale ){

$gender = “male”

}

else{

$gender = “female”

}

$f = (Invoke-Expression (“`$_RN_{0}[`$rand.Next(`$_RN_{0}.Count)]” -f $gender)).Split(“`t”)[0].ToLower()

“{0} {1}” -f $f,$l

}

END{

}

}

Once we’ve saved that script to a .ps1 file and then run it, we have the files of first and last names loaded and a function named Get-RandomName defined. Simply invoking this yields one name. Sending a number of objects to it generates a number of names at once. This script could easily be modified to keep the first and last names separate – that will be demonstrated in a later post.

To generate one name, simply use:

Get-RandomName

To generate a list of 100 names, use:

1..100 | Get-RandomName

Next, in a later article, we’ll take a look at how to use these names in the creation of test objects. For now, we’ll end with some URLs to name files, with the understanding that you could use any files with one name per line. Anything on the line after the first <TAB> character is discarded by the script.

<http://www.census.gov/genealogy/names/names_files.html>

<http://www.census.gov/genealogy/www/freqnames2k.html>

Mythical IIS Cmdlets

posh-iismod

The bleeding edge is sometimes a few years ahead of the leading edge, so every time I hear about some leading edge technology, I know it’s probably been around for a couple of years if not a few decades. Yes, I know, I’ve been on both of those edges many times before.

Anyway, when I was developing some Windows PowerShell courseware, I kept hearing people talk about the IIS cmdlets, and read about them several places, and knew that since I was supposed to be writing just about PowerShell version 1.0, I couldn’t include more than just a cursory reference about “IIS cmdlets could be written but there aren’t any in production… yet.”

That has changed. In case you’re not running Windows PowerShell version 2.0 with Internet Information Services (IIS) 7.5 on Windows Server 2008 R2 yet, the leading edge is calling you…

Yes, it’s true. Windows Server 2008 R2’s IIS 7.5 does indeed possess these mythical IIS cmdlets after all, and not just a half dozen of them. What can we manage using these IIS PowerShell cmdlets? The shell can tell – try the following command.

 get-command -module WebAdministration | group CommandType

As that command line can tell you, there are 71 IIS cmdlets, 2 aliases, and 1 function. What Get-PSDrive could tell you is that the WebAdministration provider also hosts an IIS PowerShell drive which the aforementioned function changes location to. For the moment, let’s focus on the cmdlets.

get-command -module WebAdministration | group noun | sort Count -desc

 

Grouping the IIS cmdlets by noun and subsequently sorting those groups by the cmdlet count within each group, we can quickly see what kinds of things can be managed using those cmdlets.

Are these cmdlets easier to use than appcmd, or the .NET or WMI interfaces which have been available for several years in PowerShell for managing IIS? That’s a matter of opinion, really. But let’s take a quick glimpse to get you started on being to give an opinion of your own to that question.

Twenty of these cmdlets start with the noun Get, such as Get-Website, Get-WebVirtualDirectory, Get-WebApplication, and Get-WebAppPoolState. Getting information is a good place to start before you start reconfiguring your IIS 7.5 configuration, therefore we’d recommend investigating those cmdlets first. In some cases, these Get-Web* cmdlets require parameters. In other cases, they require some context, such as having previously done a Set-Location (cd) into the a psDrive mapped to the IIS: provider – there’s such a drive already mapped to the local server by default.

There is a lot of power in the IIS cmdlets which deserves investigation. As you try these cmdlets, please feel free to send questions. Perhaps some future posts could come from your questions.

Here are two suggestions on how to launch PowerShell to make sure you have the IIS cmdlets available. Both of these suggestions assume that you have installed IIS 7.5 on your server first, although they can still work in some other scenarios.

Make a shortcut on the desktop to PowerShell, then modify it in one of two ways to get the IIS cmdlets, provider, aliases, and function. Right-click on the Desktop, select New, then Shortcut. Here’s the path to PowerShell to make the shortcut to first:

C:WindowsSystem32WindowsPowerShellv1.0powershell.exe

 

It’s a good idea to name the shortcut something notable like “IIS Shell.” After you’ve made the shortcut, go back and get it’s properties and one of the following to the shortcut’s Target after the “powershell.exe” and a space.

-NoExit -ImportSystemModules

 

When PowerShell is run with the -NoExit -ImportSystemModules parameters, it loads all system modules and the window stays open with an interactive shell.

You might have many modules loaded on your server, such as ActiveDirectory, ADRMS, AppLocker, BestPractices, BitsTransfer, GroupPolicy, PSDiagnostics, ServerManager, TroubleshootingPack, and WebAdministration. If you don’t want to load all of them, but just the WebAdministration module, add the following instead of -NoExit -ImportSystemModules at the end of your shortcut Target.

-NoExit -Command Import-Module WebAdministration

 

In either case, remember the space between the powershell.exe path and the -NoExit parameter. Yes, there should be spaces between the subsequent parameters as well. If you already have a shell open without these modules loaded, you could just use the Import-Module cmdlet inside the shell, as was done within the shortcut mentioned above. At the shell prompt, simply type the following.

Import-Module WebAdministration

 

The question still remains – once you get used to several dozen IIS cmdlets and the provider, will you ever use appcmd.exe again?

Munging Strings

posh-incrstring

Bean thread is often made of mung beans, but in Windows PowerShell, the capabilities to manipulate character string expressions can draw both on the power of .NET and the expression syntax particular to PowerShell.

This brief article will certainly not delve into the seemingly infinite possibilities of string manipulation nor any comparison to languages such as LISP or Icon. Instead, let’s just look at a bit of Exchange Server trivia expressed in PowerShell.

If you are an administrator of Exchange Server 2007 or have looked at the upcoming Exchange Server 2010, you know that version numbers expressed about Exchange aren’t always aligned with the “under the hood” version numbers. Because of the alignment with Office 2007 (Office 12), Exchange Server 2007 (RTM = 8.0) has often been referred to as Exchange 12. If you’re not an Exchange administrator, just read along for fun – we’ll get to string manipulation after the trivia story.

If you’ve transitioned from the world of Exchange Server 2003 to Exchange Server 2007 you may know that old features such as the ability to have multiple Administrative Groups and multiple Routing Groups were replaced with other ways of doing delegations of administrative settings and usually relying on Active Directory sites for internal message routing. But what about backward compatibility? Well, Exchange Server 2007 and Exchange Server 2010 environments have one administrative group in which all newer Exchange Servers reside. Similarly, E2K7 and E2010 have one routing group for backward compatibility as well.

That’s the background trivia. Now for a bit of PowerShell.

new-object string (,("EXCHANGE12ROCKS".ToCharArray() | %{ [char]([int]($_)+1) }))

 

And the output of this little code fragment is “FYDIGOHF23SPDLT” which is part of the name of the backward-compatible administrative group Exchange Administrative Group (FYDIGOHF23SPDLT).

new-object string (,("EXCHANGE12ROCKS".ToCharArray() | %{ [char]([int]($_)-1) }))

 

A similar code fragment, with a minus sign instead of a plus sign, decrements each letter in the original string rather than incrementing each as the previous example had. This results in the string “DWBG@MFD01QNBJR” which is not exactly part of the backward-compatible routing group name Exchange Routing Group (DWBGZMFD01QNBJR), in that the actual translation used by Microsoft wrapped the “decrement of A” back around the alphabet to “Z” rather than the to the previous Unicode/Latin-1/ASCII character “@” which our little code snippet generated. There are several ways our code snippet could be “fixed” to yield the proper result, yet those shall not be investigated here and now.

Sure, there are easier ways to explain strange names used on Active Directory objects, and there are likely easier ways to translate strings in PowerShell. The point however is this – PowerShell possesses a versatile expressivity with its ability to take a pipeline expression and use it as a parameter to a cmdlet or function. Let’s dive just a touch deeper – more like just sticking our big toe in the water – looking at what these lines of code do.

Let’s work from the inside out.

"EXCHANGE12ROCKS".ToCharArray()

 

This merely takes the string literal “EXCHANGE12ROCKS” and uses the string method ToCharArray() to convert it to a character array.

%{ [char]([int]($_)+1) }

 

Next, that character array is sent down a pipeline to the above ForEach-Object loop, with the percent sign (%) alias to the ForEach-Object cmdlet being used here.  For each character, $_, we convert it to an integer, add one, then convert it back into a character. That’s the heart of our chrazy translation in this example responsible for changing “A” to “B”, “2” to “3”, or “S” to “T.”  Note that the subtraction form is only one character different.

new-object string (,(…))

 

The final bit of magic lay in the use of the new-object cmdlet to convert the intermediately resultant character array back into a character string. In the snippet shown above, the aforementioned pipeline is replaced with an ellipsis for brevity and clarity. It’s important to note that the inner set of parentheses indicates that the pipeline value is to be used as an argument to the comma operator, while the outer set of parentheses makes sure that the result of the comma operator is used as the one value for the parameter after the “string” class name.

So how could you modify this to do something useful? That’s an interesting question, but instead let’s answer how it could do something marginally humorous in closing. How could we make a function (although a filter would be more fun) out of this sort of code to allow quick manipulations on names?

# Function to increment each character in a string function increment-string( $str, $inc = +1 ){ return new-object string ` (,($str.ToCharArray() | %{ [char]([int]($_)+$inc) })) }

 

All that has been changed from the fixed examples is that the string has been parameterized and the amount to increment or decrement by has been parameterized as well. Consider the following examples.

increment-string "VMS"

 

Which should yield “WNT,” and:

increment-string "IBM" -1

 

which should result in “HAL.”

What can this function do with your name? With product names? How about using +3, -12, or other offsets? Can you modify the function to wrap (rotate) within the alphabetic, numeric, or symbol parts of the character set? Can you change it from a function to a filter which accepts pipeline input? What would { gwmi win32_operatingsystem | rotate-string +13 } result in? Can you think of any useful purpose for such string operations as incrementing and decrementing characters?