Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Wednesday, March 27, 2013

Extract a Cmdlet’s Parameters into a Collection with PowerShell

While building a script to help out a reader of this blog, I came up with a handy little cmdlet to retrieve the parameters of a cmdlet and place them into a collection.

Function Get-ParameterList

{

    [cmdletBinding()]

    Param ($Cmdlet)

        Write-Verbose "== Cmdlet: Get-ParameterList =========================="

        Write-Verbose "Parameter - `$Cmdlet: $Cmdlet"

        $List = (get-help $Cmdlet -parameter * |

            Select-Object -Property Name |

            ForEach -Process {$_.name})

 

        Write-Verbose "Sending $($List.count) Items to the pipeline."

        Write-Output $List

        Write-Verbose "__ End Function: Get-ParameterList ____________________"

    <#

    .SYNOPSIS

    Extracts cmdlet parameters

 

    .DESCRIPTION

    Extracts the parameters from a supplied cmdelt and sends then as a collection

    into the PowerShell Pipeline.

 

    .PARAMETER Cmdlet

    The name of the cmdlet whose parameters you want to extract.

 

    .EXAMPLE

    Get-ParameterList Set-MailContact

 

    Sends a collection of strings containing the names of all of the parameters

    avaliabe to the cmdlet Set-MailContact.

    #>

} # End: Cmdlet: Get-ParameterList

 

 

Monday, March 25, 2013

Test your scripts without your profile

Many of you who have taken my PowerShell class may remember that I strongly advocate to not use person aliases in your scripts. They are fine for shell use, but not in scripts. This is for two reasons. The first reason is that they make your scripts less readable to others. These are your personal aliases that no help file exists for.  The second, and most important, is that your scripts are not portable. For someone else to use a script with your custom alias in it, they would have to add to their profile the code to create your alias. If you do utilize aliases, you will want to load a PowerShell session that does not load your profile to test your script prior to delivery. This way you will know for sure if your script is portable or not with regards to aliases.  To add code to make sure the other client as the modules that you need, check out my code for Confirm-Module.

To open a PowerShell session without your profile:

PowerShell.exe –NoProfile

Wednesday, March 20, 2013

Writing Event Log Entries with PowerShell

PowerShell contains a cmdlet, Write-EventLog that will allow you to place custom events generated by your scripts into the clients event logs.  One problem that I have had with this approach is that the source that is generating the event log entry needs to be registered with the log you are writing to.  In other words, an extra procedure on each client/server that needs to be completed before the script can be used.  Another option is to use the Windows PowerShell event log itself.  Take a look at this code:

Write-EventLog -Source PowerShell -LogName "Windows PowerShell" -EventId 10000 -EntryType Information -Message "This is a test"

 

Here you can see that we are using the Source of PowerShell with the event log of Windows PowerShell.  The key to using the Windows PowerShell event log for your own purposes is to make sure that you are using event IDs that are unique. Using this code, I was able to get an idea for the Event IDs being used by the Windows PowerShell event log.

 

Get-WinEvent -LogName "Windows PowerShell" |

 Select-Object -Property ID -Unique

It appeared that anything over 10000 was available.  When developing code that you want to make entries in the Windows PowerShell event log, make an Excel spread sheet of your scripts and the event ID numbers it will use.  Allow for some room for growth so separate blocks by sizes of 25 or 50.  That way as you add new code to the script in the future, your event IDs for that script will be sequential.  Having this list will also help you understand which IDs that you need to look up.  When you need to recover all the events from a particular script, you simply provide the Event ID range for that script.

$LogHash = @{LogName = "Windows PowerShell"; ID = 10000..10024}

Get-WinEvent -FilterHashtable $LogHash

A parameter that may help you clarify what you are writing in the event log is –EntryType.  EntryType has the following values:

  • Error
  • Warning
  • Information
  • SuccessAudit
  • FailureAudit

Using this parameter will help you to further filter your search results. It will also allow you to reuse event IDs because they will have different EventTypes.

For those of you who wish to create a custom event log for your scripts, take a look at the help file for New-EventLog.

Monday, March 18, 2013

New Way to add Note Properties with PowerShell V3

For those of you who have taken my PowerShell V2 class probably remember the step-by-step exercise that I took you through to help you build a custom object.  In PowerShell V3, we can create a new NoteProperty with a smaller amount of code.  Below is code that creates an object with a single note property.
$Obj = New-Object -TypeName PSObject
$Obj | Add-Member -MemberType NoteProperty -Name "Value1" -Value 10
Using the Add-Member cmdlet, we declare the member type that we are adding “NoteProperty”. Then we provide it with a name and a value.  In PowerShell V3, two new parameters were added to the Add-Member cmdlet.  They are –NotePropertyName and –NotePropertyValue.  Below is the same object created with this new method.
$Obj = New-Object -TypeName PSObject
$Obj | Add-Member -NotePropertyName "Value1" -NotePropertyValue 10
If your code will be running on clients or servers using PowerShell V2, do not use this new method.  Take a look at the screen shot below.
image
You can see that the script successfully executes in PowerShell V3.  When I switch the shell to the V2 engine and then executed the code, PowerShell V2 hit a run time error because its version of Add-Member does not have a parameter for ‘NotePropertyName’.
Just one of the little hidden tricks inside of PoSH V3.  As always, code for the lowest level of PowerShell that your code will execute on.

Monday, March 4, 2013

Utilizing PowerShell’s String Manipulation

The System.String object in PowerShell is a very useful object to get to know.  Many times I see Network Admins trying to create a lot of extra code that is not necessary when it comes to manipulating the contents of a string.  Even though I instruct that outputting data as a string is not a good PowerShell process, we need to be able to handle string data as input.  A case in point, what if you need to extract data from the message portion of an event log entry?  To simulate a string with multiple lines, I use this code:
$String = "This is a set of data.`n"
$String += "It has multiple lines.`n"
$String += "I need to extract the name of a computer.`n"
$String += "Computer Name: Indy-DC1.`n"
$String += "Now, try to extract it."
You can see that the string is telling us our objective.  I want to extract the name of the computer, Indy-DC1, from this string. The `n provides for a carriage return.  This is what the string looks like when you ask for the variable $String:
PS C:\> $String
This is a set of data.
It has multiple lines.
I need to extract the name of a computer.
Computer Name: Indy-DC1.
Now, try to extract it.
First let’s explore a couple of methods.  If you execute the command $String | Get-Member, you will see a list of the methods that are available to you.
To get a description of the methods for the object System.String, we can go to MSDN.  Take a look at the MSDN article for System.String. Since only one line of the string actually has the name of the computer, we need to somehow eliminate all the other lines.  Take a look at the Split method.  According to MSDN:
Returns a string array that contains the substrings in this string that are delimited by elements of a specified Unicode character array. Parameters specify the maximum number of substrings to return and whether to return empty array elements.
So we are going to turn this string into an array.  We need to use a delimiter to separate each line.  The easiest way to do this is by using the carriage return.
$String = $String.Split("`n")
The Split method has split up the string.  There are two ways to find the container of the array that holds the computer name.  If the string data is always on the same line, we could use the index number.  Remember, the first container of the array is at index 0.
$Data = $String[3]
If we do not know what line the value is on, we can utilize other information in the line that does not change to search for it.
ForEach ($Item in $String)
{
    If ($Item.Contains("Computer Name:"))
    {
        $Data = $Item
    }

}

This code cycles through each line of the string in the array.  It utilizes the Contains method of System.String.  If the string contains the text that follows (Computer Name:), the response is TRUE.  If it is TRUE, then that line of text is saved in the variable $Data.
If we take a look at $Data, this is what we get.
PS C:\> $Data
Computer Name: Indy-DC1.
We are getting close, but we are not down to just the computer name.  Utilizing the Replace method allows us to remove text from the string that we do not want.
$Data = $Item.Replace("Computer Name:", "")
Now the output looks like this.
PS C:\> $Data
 Indy-DC1.
We still have a period at the end of the string and a space at the beginning.  To deal with the period, let’s use the Replace method again.
$Data = $Item.Replace("Computer Name:", "").Replace(".","")
We then add our second Replace method to handle the period.  Now for the extra space.  We could use Replace, but the string method also has a Trim.  Trim will remove all spaces to the left and right of the string.  TrimStrart and TrimEnd will remove just the spaces to the left and right of the string.
$Data = $Item.Replace("Computer Name:", "").Replace(".","").Trim()
I used Trim to ensure there were not any spaces after the text that I could not see.  Here is the final output.
PS C:\> $Data
Indy-DC1
Take the time to look at the member information for each object that you use in PowerShell.  You never know, someone may have already written the code that you need.  Below is the final code for used in this post.
$String = "This is a set of data.`n"
$String += "It has multiple lines.`n"
$String += "I need to extract the name of a computer.`n"
$String += "Computer Name: Indy-DC1.`n"
$String += "Now, try to extract it."

$String = $String.Split("`n")


ForEach ($Item in $String)
{
    If ($Item.Contains("Computer Name:"))
    {
        $Data = $Item.Replace("Computer Name:", "").Replace(".","").Trim()
    }

}