PowerShell Version 1

Script Club – Coming to the Greater Milwaukee Area

Register here.

About PowerShell Script Club

1. You Always Talk About Script club
2. You Always Talk About Script Club
3. If Someone asks for Help, And You Can Help, You Help
4. Two People Help One Person at One Time
5. One Module Per Person Per Night
6. All Scripts, All PowerShell
7. Scripts will be as short as they can be
8. If This is your First time at Script Club, You Have to Script

The first Greater Milwaukee PowerShell Script Club is being formed.

The first meeting will be on Tuesday, January 19th at 6:00 PM at the Greenfield Law Enforcement Center (in the Municipal Court Room), 5300 W Layton Ave, Greenfield, WI  53220.  Register here.

All IT Professionals (sysadmins, network admins, developers, help desk, and all others) with any level of experience are welcome.  If you DO NOT KNOW POWERSHELL, but you WANT TO – This is the place.

Pizza and soda will be provided, but please bring a laptop with PowerShell installed (version 1 or 2 is fine).

What is a Script Club?

Andy Schneider describes a script club:

Script Clubs are like a hands on lab with no set topic or teacher. You bring an idea for a script, and ask your fellow PowerShell users for help getting the script written.

This is not a lecture or presentation based group (though we may have presentations from time to time).  Script Club is focused on creating working scripts that will help you get your work done or just enjoy yourself.

Register here.

Deep Dive: Error Handling – Error Types (part 1)

I started looking a little deeper at error handling in PowerShell after this StackOverflow question.

PowerShell has two kinds of errors – terminating errors and non-terminating errors.

Terminating errors are the errors that can stop command execution cold.  Non-terminating errors provided an additional challenge, as you need to be notified of failed operations and continue with pipeline operations.  To deal with this issue and to provide additional output options, PowerShell employs the concept of streams.  There are three additional streams (other than the primary pipeline stream) available in PowerShell – Verbose, Warning, and Error (and .  We’ll be concerning ourselves with the output from the Error stream.

There are some automatic variables in the shell that deal with errors as well.  $ErrorActionPreference is a variable that describes how PowerShell will treat non-terminating errors.  $ErrorActionPreference has four options: “Continue” (the default), “SilentlyContinue”, “Inquire”, and “Stop”.  $error is an array of all the errors that have occurred in the current session up to the number specified in $MaximumErrorCount.  $? is a boolean value that is $true if the previous operation succeeded and $false if it did not.

PowerShell does have some built in flexibility to turn non-terminating errors into terminating errors.  Based on our setting of $ErrorActionPreference, PowerShell will treat a non-terminating error differently.  If $ErrorActionPreference is set to ‘”Stop”, PowerShell will treat the errors from that scope and all sub scopes (unless explicitly overridden) as terminating errors.  If “Inquire” is chosen as the $ErrorActionPreference, then PowerShell will prompt the user at the console upon each error to ask whether it should continue (treat as non-terminating) or halt (treat as terminating), as well as providing an option to drop into a nested prompt.

$ErrorActionPreference is a global preference that can be set, but the PowerShell runtime also allows more granular control by providing common parameters for -ErrorAction and -ErrorVariable (shorthand -EA and –EV) which allow you to determine per cmdlet (and in V2 per advanced function) how errors should be handled.  The –ErrorAction parameter takes the same options as $ErrorActionPreference.

So what happens when you encounter an error?

If you hit a terminating error, your script, function, or command will stop.  The error will be logged to the $error variable and written to the error stream.  The $? will be set to false.  You can use the trap construct (or the try/catch/finally construct in V2) to deal with terminating errors and we’ll cover that further in the fourth post in this series.

If you hit a non-terminating error, the result will depend on the $ErrorActionPreference in the scope or the –ErrorAction parameter.  If the $ErrorActionPreference or –ErrorAction parameter is set to ‘Continue’, the error will be written to the error stream, added to the $error array, and the $? will be set to $false.  ‘SilentlyContinue’ will not write an error to the Error stream, but $error and $? are updated.  Finally, ‘Inquire’ provides you an option at each error as to whether to treat it as terminating or non-terminating.  If treated as a non-terminating error, the error will be treated like the $ErrorActionPreference or –ErrorAction parameter is ‘Continue’.

Now, I’ve mentioned that some terminating and non-terminating errors both write to the Error stream, so where does that actually get reported back to the user?  If an error has been written to the error stream, it will be written to the output stream (which may surface differently based on the PowerShell host) separately from the pipeline output unless it is redirected.  This means that the exception objects, which are how the errors are represented, are not saved to a variable if you are assigning the pipeline output to a variable.

For example:

$results = Get-WMIObject Win32_Bios –ComputerName localhost, ComputerThatDoesNotExist
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0×800706BA)
At line:1 char:22
+ $results = Get-WmiObject  <<<< Win32_Bios -ComputerName localhost, ComputerThatDoesNotExist

creates this output to the screen, but $results will only hold the results of the successful WMI query.  This is where the –ErrorVariable comes in.  You can specify a variable to hold the exceptions generated by a particular cmdlet (or in V2 advanced function).  Specifying a variable does not remove an item from being written to the error stream and displayed as output.

In a console session, you can redirect the error stream with the redirection operators ( 2> or 2>>) or you can merge the error stream with the output stream (2>&1) and write the output to a file, the pipeline, or assign it to a variable.

Up next:

  • Error Objects
  • Tracing Errors
  • Trapping Errors
  • Reporting Errors

Other great PowerShell Error Handling posts:

PowerShell, VMWare, and VESI in Wisconsin

On May 19th, Scott Herold and I will be presenting for the Wisconsin VMWare Users Group. 

I’ll be covering the basics of PowerShell, as well as an introduction to the VI Toolkit (for Windows)/PowerCLI.

Scott will be talking about  the Virtualization EcoShell Initiative (VESI).

If you are in Wisconsin, the meeting details can be found here.

If you are not able to make the meeting, VMWare will be providing a live stream of our presentations via WebEx, as well as providing recordings after the fact.  

My presentation starts at 9 AM Central time and Scott follows me at about 9:50.

Coming To A WSUS Server Near You –> PowerShell V1.0

Richard Siddaway has just posted that PowerShell 1.0 is available as an optional update.

I just checked my WSUS Server and there it is!!! Deployment is now a snap.

More details in his blog post.. or in the MS Knowledge Base.

Tip: Passing Parameters Revisited

In Jeff Hicks’s Prof. PowerShell series, he continues with his tips on working with functions.  He uses the Check-Service function that was in the previous article and that I provided another option in this post.  Jeff describes how you can make a function act more like a cmdlet.

The problem that you run into in V1 of PoweShell is that it is easy to make your functions work with the pipeline

Function Check-Service {
  Param([string]$service=”spooler” )
  PROCESS
  {
    $wmi=get-wmiobject win32_service -filter “name=’$service’” -computername $_ 
    if ($wmi.state -eq “running”)  {
      write $True
    }
    else {
      write $False
    }
  }
}
 
Get-Content servers.txt | Check-Service

OR work well with parameters being passed in.

Function Check-Service {
  Param([string[]]$server=$env:computername, [string]$service=”spooler” ) 
    $wmi=get-wmiobject win32_service -filter “name=’$service’” -computername $server 
    if ($wmi.state -eq “running”)  {
      write $True
    }
    else {
      write $False
    }

  
Check-Service –Server Server01, Server02, Server03

Advanced functions in V2 of PowerShell can alleviate this problem (a topic for a whole new post), but a workaround I’ve found for V1 is to use the Begin block to take certain command line parameters and pass them back into the function via the pipeline.

Function Check-Service {
Param([string[]]$server=$null,[string]$service=”spooler” )
  BEGIN
  {
    if ($server -ne $null)
    {
      $server | Check-Service –Service $service
    }
  }
  PROCESS
  {
    if ($_ -ne $null)
    {
      $wmi=get-wmiobject win32_service -filter “name=’$service’” -computername $_
      if ($wmi.state -eq “running”) {
        write $True
      }
      else {  write $False  }
    }
  }
}

This enables both of the above scenarios:

Get-Content servers.txt | Check-Service

Check-Service –Server Server01, Server02, Server03

PSMDTAG:FAQ param

PSMDTAG:FAQ pipeline

Updated: (Missed a little recursion bug.. thanks Aleksandar!)

Tip: Passing Parameters

Jeffery Hicks recently talked about the Param statement in his Prof. Powershell column for MCP Magazine (Keeping Your Options Open).  If you are new to PowerShell, I would definitely recommend reading the article, as provides a nice introduction to the Param statement. 

Jeffrey recommended to cast your parameter as the type of object that you are expecting, as way to catch errors.  I wholeheartedly agree.  That can cause trouble though, if you want to allow consumers of your script to pass in one or more values for that parameter.  In the spirit of the article’s title, I thought I would share a method I’ve come across to handle that situation.

Jeffrey gave is the below function.

Function Check-Service {
  Param([string]$computername=$env:computername,
    [string]$service=”spooler” )
  $wmi=get-wmiobject win32_service -filter “name=’$service’” -computername $computername
  if ($wmi.state -eq “running”)  {
    write $True
  }
  else {
    write $False
  }
}

Now, you can easily see where you might want to check for a service on multiple computers, but as this function stands, we would have to call it one time for each computer we want to check.

We can modify this script to take one or more computer names simply by changing the cast for the $computername variable from [string] to [string[]].  That changes makes our variable hold an array of strings, rather than just one. 

We don’t have to change the default value, as PowerShell handles the details of converting that value to an array. 

Since the –ComputerName parameter for Get-WMIObject can take an array of computer names, we don’t have to change much else in the function. 

I do add a foreach loop for the reporting end of the script, so we can see which machines have the service running.

And I end up with this (my changes in bold):

Function Check-Service

{

  Param( [string[]]$computername=$env:computername, [string]$service=”spooler” )

  $wmi=get-wmiobject win32_service -filter “name=’$service’” -computername $computername

  foreach ($one in $wmi)

  {

    if ($one.state -eq “running”)

    {

      write $one.SystemName, $true

    }

    else

    {

      write $one.SystemName, $False

    }

  }

}

 

I almost forgot

PSMDTAG:FAQ param

How To Send E-Mail From PowerShell

In my Exploring the .NET Framework series, I introduced the System.Net.Mail.MailMessage class.  Being able to create a MailMessage object is all well and good, but if you can’t send it, it’s really not helpful.

To send an email from PowerShell using the .NET Framework, you can use the System.Net.Mail.SMTPClient class.

First, you need to create your MailMessage

PS C:\scripts\PowerShell> $message = New-Object System.Net.Mail.MailMessage –ArgumentList steve@usepowershell.com, nobody@adomain.com, ‘This is a test’, ‘I’m going to send an email via PowerShell’

If you need to add an attachment, you can add one with the System.Net.Mail.Attachment class.

To create the attachment, we’ll create an use an overload of the Attachment class that allows us to specify a filename and a MIME type (the MIME types are available in several enumerations:  System.Net.Mime.MediaTypeNames.Application, System.Net.Mime.MediaTypeNames.Image, and System.Net.Mime.MediaTypeNames.Text – I’ve had a bit of trouble accessing those enumerations via PowerShell, but you can specify the name of the enumeration value in a string).

PS C:\scripts\PowerShell> $attachment = New-Object System.Net.Mail.Attachment –ArgumentList ‘c:\docs\test.xls’, ‘Application/Octet’

PS C:\scripts\PowerShell> $message.Attachments.Add($attachment)

After we have our email and optional attachment, we’ll create the SMTP client and have it configured to use the SMTP server of our choice.

The constructor of the SMTPClient class that we will use is

SmtpClient(
        String host,
)

PS C:\scripts\PowerShell> $smtp = New-Object System.Net.Mail.SMTPClient –ArgumentList 10.10.10.15

All that is left is sending our email..

PS C:\scripts\PowerShell> $smtp.Send($message)

Have fun!

NOTE:

There is a shortcut to creating the MailMessage object like we did.. there is an overload of Send where you can pass in four strings (from, to, subject, and message).  The SMTPClient handles the creation of the MailMessage in the background.

A faster method would be

PS C:\scripts\PowerShell> $smtp = New-Object System.Net.Mail.SMTPClient –ArgumentList 10.10.10.15

PS C:\scripts\PowerShell> $smtp.Send(‘steve@usepowershell.com’, ‘nobody@adomain.com’, ‘This is a test’, ‘I’m going to send an email via PowerShell’)

Exploring the .NET Framework with PowerShell – Constructors (Part 3)

In part 2(a & b) of this series, we talked about methods and looked at ways to view their overloads, or ways to call them.  We also looked at the objects returned from a method call.  In this post, we are going to explore a special kind of method called the constructor.

A constructor is a method whose job is to create the object that you want to work with.  When I created the Ping object

PS C:\scripts\PowerShell> $ping = New-Object System.Net.NetworkInformation.Ping

the New-Object cmdlet calls the constructor for Ping.

Like other methods, constructors can require parameters and can have multiple overloads. 

Let’s look at System.Net.Mail.MailMessage, which is a object that represents an email message.

The MailMessage constructor contains several overloads.  The first method listed is MailMessage(), which is the default constructor.  This method does not require any arguments and returns an empty MailMessage object.  In PowerShell, we would call this method via New-Object, just like with Ping class.

MailMessage()

PS C:\scripts\PowerShell> $message = New-Object System.Net.Mail.MailMessage

The first overload requires two MailAddress objects, the first of which is the “from” address and the second is the “to” address. 

MailMessage(
        MailAddress from,
        MailAddress to,
)

Creating an object in PowerShell from a constructor that requires parameters can be done in two ways.  The first is to use the method call notation.

PS C:\scripts\PowerShell> $message = New-Object System.Net.Mail.MailMessage($MailFrom, $MailTo)

The second is to use the ArgumentList parameter.

PS C:\scripts\PowerShell> $message = New-Object System.Net.Mail.MailMessage –ArgumentList $MailFrom, $MailTo

If you happen to have MailAddress objects floating around, this might work for you.  A more common scenario would be to use the next overload, which takes two strings.

MailMessage(
        String from,
        String to,
)

This overload requires two strings, one for the “to” and one for the “from” address. 

The final overload for MailMessage is

MailMessage(
        String from,
        String to,
        String subject,
        String body,
)

This overload allows you to pass in four strings and get back basic MailMessage object that is ready to be sent.

Wouldn’t it be great to have a function, where we could provide a type name and get a listing of all the constructors, right from the command line (not needing to go to the MSDN documentation every time).  Jeffrey Snover has beaten me to the punch and provided a function to find the constructors, appropriately called Get-Constructor.  Add that function to the your toolbox, and exploring the .NET Framework becomes a lot easier.

Next up, we’ll look at static methods.  Static methods are methods that can be called without having to create a instance of an object.

One particular type of static method that we’ll dig in to is the factory method, which is another way to create instances of objects.

Adding Custom Properties to Functions

A question was asked on StackOverflow regarding how to add properties to a function, and then be able to retain that custom property when recalling that function from the function Provider.   I’m not going to copy my answer here, but I do want to throw out a possible work around for this issue. 

(It has been bugging me and I can’t really concentrate on my other tasks, so I need to get this out of the way.)

One suggestion I had was to create a type extension that had the property he was adding, but he was more interested in tagging specific functions, not all of them.

So, I’ve written a couple of little ScriptProperties to save and restore NoteProperties which have been added to FunctionInfo objects.  I’ve added these to a PS1XML.

   1: <?xml version="1.0" encoding="utf-8" ?> 
   2: <Types> 
   3:     <Type> 
   4:         <Name>System.Management.Automation.FunctionInfo</Name> 
   5:         <Members> 
   6:             <ScriptMethod> 
   7:                 <Name>SaveMetadata</Name> 
   8:                 <Script> 
   9: $DefaultProperties = 'PSPath', 'PSDrive', 'PSProvider', 'PSIsContainer'
  10: $SaveDirectory = Split-Path $profile
  11: $File = Join-Path $SaveDirectory "$($this.Name).xml"
  12: $this.PSObject.Properties | Where-Object {$DefaultProperties -notcontains $_.Name -and $_.MemberType -like 'NoteProperty'} | Export-Clixml -Path $file
  13:                 </Script> 
  14:             </ScriptMethod>
  15:             <ScriptMethod> 
  16:                 <Name>LoadMetadata</Name> 
  17:                 <Script> 
  18: $SaveDirectory = split-path $profile
  19: $PathToCustomProp = Join-Path $SaveDirectory "$($this.name).xml"
  20: if (Test-Path $PathToCustomProp)
  21: {
  22:     foreach ($Property in Import-Clixml -Path $PathToCustomProp)
  23:     {
  24:         Add-Member -InputObject $this -MemberType NoteProperty -Name $Property.Name -Value $Property.Value
  25:     }
  26: }
  27:                 </Script> 
  28:             </ScriptMethod> 
  29:         </Members> 
  30:     </Type> 
  31: </Types> 

After saving this file as a PS1XML file, you can call Update-TypeData –Prepend path\to\thefile.ps1xml, and every FunctionInfo object will have two script properties – SaveMetadata and LoadMetadata.  As I’ve configured it, the data will be saved to the user’s profile directory and under a filename that matches the function name.  So, you can add NoteProperties to your heart’s desire and save and recall them as needed. 

I don’t have a direct application for this, and it can probably be cleaned up or done more efficiently, but I had to work through the problem.  I’d love to hear your feedback!

Comparing Database Schemas

I regularly am working with several versions of a database for an application that I manage (a live database, training database, test database, and previous version database).  Occasionally, I need to know what the differences between the databases are, especially after our vendor updates my test environment or right after an update in my training or live environment. 

Since I spend a good portion of my day in PowerShell, I wrapped some system table queries in a PowerShell script and use Compare-Object to find any differences in the tables and compare the column definitions as well.  The queries targets only user tables.

Compare-DatabaseSchema.ps1 takes several parameters.

  • SqlServerOne – SQL Server for the first database
  • FirstDatabase – Name of the first database for the comparison
  • SqlUsernameOne – SQL user name for the first database
  • SqlPasswordOne – SQL password for the first database
  • SqlServerTwo – SQL Server for the second database
  • SecondDatabase – Name of the second database for comparison
  • SqlUsernameTwo – SQL user name for the second database
  • SqlPasswordTwo – SQL password for the second database
  • FilePrefix – Prefix for the log file name
  • Log – Switch parameter that saves one CSV file with the difference in the tables.  If the Column switch parameter is chosen also, it will save one CSV file per table with differences in the columns
  • Column – Switch parametr that enables a comparison of the columns in the tables that match.  Columns are compared by name and datatype.

I still have to add some checks for the various constraints, but that will come later.

You can find the script on PoShCode.org.

Get Adobe Flash playerPlugin by wpburn.com wordpress themes