WS-Man, Powershell, and MRTG

There's a cool site over at http://wsman.msft.net/ that has some examples of using MRTG (Multi Router Traffic Grapher) coupled with Powershell and Win RM.

There are some Powershell scripts up there that show how to access data with WinRM in Powershell and cast it from XML to a rich PS based object.

Take a look!

Enabling WinRM with Powershell

Searching Event Logs with Powershell

I recently had  a situation where I needed to be able to search an event log for a particular value.

I wrote a quick little script so that our PM could run it with little effort

   1: param ($name)
   2: $user = '*' + $name + '*'
   3: get-eventlog application | where {$_.Message -like $user} | 
   4: format-list Message,TimeGenerated

I am basically searching for event logs that contain a particular name.

It's pretty straight forward once you find that .Message is what contains the real meat of the event log entry.

You could also obviously use get-eventlog system as well.

Objects or Text in a pipeline ?

Since the release of Powershell there have been a variety of discussions in the community debating which is more powerful, objects or text in a shell environment. Really it depends on what you are managing with  the shell.

In the case of the *NIX world, there is a bunch of configuration files that need to be changed, and for this a text based shell is a great thing. A text based shell to manipulate text is completely appropriate.

The world of Windows is a very different story. Windows was not built around configuration files. It is an OS that is accessed and manipulated using API's and a set of objects. This of course leads into why Windows needs an object based shell.

What is really comes down to is using the right tool for the job. I am not so sure I would want to manage a Linux server with Powershell, nor would I really want to manage windows with bash.

Server Core – Preparing Your Desktop

I find it amusing that the longest task that occurs the first time you log into Server Core is "Preparing Your Desktop."

image

I can just here the server now... "where the heck am I going to put that console window anyway?"

Custom Prompt and $NestedPromptLevel

I have had a custom prompt for quite some time now. I am pretty sure I got started with by using the custom prompt from the PowerShell Community Extensions.

I have tweaked it here and there and apparently at some point I dropped the part of the default prompt that used $NestedPromptLevel.

This wasn't a problem until I was reading about some great debugging techniques in PowerShell in Action by Bruce Payette which used the Nested Prompt feature.

This was quickly fixed with the following:

   1: if ($NestedPromptLevel -gt 0) {$myPrompt = "PS-nested >>"}
   2: Write-Host ($myPrompt)  

Now my nested prompt works quite well. When I hit S to suspend, I get dropped into my custom nested prompt.

   1: PS 10 >  notepad
   2: PS 11 >  gps notepad | kill -confirm
   3:  
   4: Confirm
   5: Are you sure you want to perform this action?
   6: Performing operation "Stop-Process" on Target "notepad (4512)".
   7: [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): S
   8: PS-nested >> gps notepad
   9:  
  10: Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
  11: -------  ------    -----      ----- -----   ------     -- -----------
  12:      57       6     2000       9884    78     0.08   4512 notepad
  13:  
  14:  
  15: PS-nested >>
  16: PS-nested >>
  17: PS-nested >>
  18: PS-nested >> exit
  19:  
  20: Confirm
  21: Are you sure you want to perform this action?
  22: Performing operation "Stop-Process" on Target "notepad (4512)".
  23: [Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"): Y
  24: PS 14 >

Note to self: when messing with defaults, don't delete stuff when you don't know what they are for.

 

Andy

Confessions of a Powershell Evangelist

For the last year or so I have been trying to get people I work with excited about Powershell. Some people love it right away, but for others, it is a bit overwhelming. That being said, I had an interesting experience the other day. In order to set the context of this, I must confess something.  I have not been a big fan of PowerGui. My attitude was always something like this: "PowerShell is a SHELL, not a GUI, and the last thing in the world that I need is yet another GUI application."

Don't get me wrong here. It's not that I thought PowerGui is a bad application, its just that I personally didn't see the value in it for me and what I was doing with Powershell on a daily basis.

In spite of my point of view, I let my team know that PowerGui had RTM'd and forwarded a link to my co-workers.

Within about an hour I got an email from one of our Operations guys that included the following:

 

"Dude, this is fricking AWESOME, I installed it with the Active Directory Quest management pack and E2K7 Management tools (32bit) on a Windows 2003 R2 box. Super sweet!"

 

After reading that my attitude about PowerGui started to change :) Another 4 or 5 hours go by and I get another email from the same person:

 

"WOW, I have being playing with some of the AD and E2K7 stuff, this tool kicks so much butt !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"

 

I would like end my confession with an apology to Dimitry and the rest of the PowerGui crew.  I just wish I had started telling people about it earlier. You guys have created an awesome tool and it has absolutely helped me in getting more people in my organization using Powershell. Thank you very much for your hard work and all that you give to the Powershell Community.

By the way, I have been a die hard fan of the Quest AD Cmdlets from the very beginning.

As we - the Powershell Community - work together to get people on board with Powershell, we must remember and realize that what works well for us as individuals may not work well for others and vice versa. We must be able to step into the shoes of people we are working with, understand their concerns, and help them solve their problems, (with Powershell of course.)

Using System.Char Static Methods

Event 5 in the Scripting Games dealt with testing whether or not a password is secure or not.  Among many qualifications, the password had to contain at least one digit, at least one upper case character and at least one lower case character. There also needed to be a check to see if the password contained any non-alphanumeric characters, such as $%^ or (.

All these could be dealt with using regular expressions, but regex skills are weak at best, so I always default to check and see if if someone has done it for me already. Sure enough, there are a bunch of static methods for System.Char that we can use.

   1: [char]::IsUpper()
   2: [char]::IsLower()
   3: [char]::IsDigit()
   4: [char]::IsLetterOrDigit()

From these we can build a filter that will pass the string if it meets the criteria. For the sake of example, lets build "Select-ContainsUpper"

   1: # Create a filter that can be used in a pipeline
   2: filter Select-ContainsUpper {
   3:     
   4:     # coerce the string into an array of chars and then pass each one to IsUpper
   5:     # IsUpper returns $TRUE or $FALSE for each char
   6:     # So ContainsUpper now contains an array of a bunch of Booleans
   7:     $containsUpper = $_.toCharArray() | % {[char]::IsUpper($_)}
   8:     
   9:     # if any char was uppercase, some element in ContainsUpper will be $TRUE
  10:     if ($containsUpper -contains $TRUE) {$_}
  11:     }
  12:     
  13: "one","Two","5","ContainsUpperCase","all-lower-case" | Select-ContainsUpper

Building Select-ContainsDigit and the others is left as an exercise to the reader.

You could also quite easily build a function that takes the string as a password, but lately I have been big on using filters and then putting them all together in a nice pipeline for the sake of clarity and a nice overall PowerShelly look.

Creating an Array of PowerShell Custom Objects

During the Scripting Games I found myself creating a lot of custom objects with properties that I could use to sort , select, take averages of, and a number of other cool things. Getting results into a Powershell object can make life a lot easier for a number of reasons.

There was one little piece I was missing. Not only did I want to create a single object, quite often I would want to put all the objects I created into a collection of objects. Did you know you can add collections of like objects to each other ?

   1: PS 13 >  $a = get-process

   2: PS 14 >  $a.count

   3: 66

   4: PS 15 >  $b = get-process

   5: PS 16 >  $c = $a + $b

   6: PS 17 >  $c.count

   7: 131

   8: PS 18 >

The code above shows that I can add two collections of process objects together. Very cool.

So I tried doing this in the scripting games and came across a problem. For instance, in Event 3 we needed to tally up a bunch of votes. So what I really needed was to create a bunch of $vote objects and put them all together in a collection called $votes

Here's what I came up with at first.

By the way, when I create PS Custom Objects I cheat and use the "" | Select-Object prop1, prop2 nomenclature. My easier than using new-object followed by a bunch of add-member commands.

   1: $votes = "" | Select-Object v1,v2,v3,v4

   2: foreach ($v in Get-Content votes.txt)

   3:     {    

   4:         $vote = "" | Select-Object v1,v2,v3,v4;

   5:         $vote.v1,$vote.v2,$vote.v3,$vote.v4 = $v.split(",")

   6:         $votes += $vote

   7:     } 

Looks nice and shiny until you run it :) I get the following error:

Method invocation failed because [System.Management.Automation.PSObject] doesn't contain a method named 'op_Addition'.

Not so shiny

The trick is that we $votes needs to be a collection of $vote objects, not another object identical to $vote.

So we instantiate $votes with a cast to [array] and life is good.

   1: $votes = @()

   2: foreach ($v in Get-Content votes.txt)

   3:     {    

   4:         $vote = "" | Select-Object v1,v2,v3,v4;

   5:         $vote.v1,$vote.v2,$vote.v3,$vote.v4 = $v.split(",")

   6:         $votes = $votes + $vote

   7:     } 

A quick update, thanks to Aleksandar. We should instantiate $votes as $votes = @(). I have updated the example above.