Advanced Windows PowerShell Scripting Video Training

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

Friday, December 9, 2016

Auto Populating a Parameters’ Value from a Dynamic List

First off, I want to give a shout out to Author: Martin Schvartzman and his blog posting https://blogs.technet.microsoft.com/pstips/2014/06/09/dynamic-validateset-in-a-dynamic-parameter/.

A question that I often get when teaching parameter validation is "can you load the values of a parameter dynamically?" Up until now, my answer was no.  Time to change that.  After getting that question again, I did some more research and found Martin’s article.  Simply adjusting 1 line of the code from his blog posting allowed me to load the SamAccountNames of all users in the domain as the valid, and TAB complete capable, values of a parameter.  Below is that code:

# Author: Martin Schvartzman
# https://blogs.technet.microsoft.com/pstips/2014/06/09/dynamic-validateset-in-a-dynamic-parameter/
# Minor modifications: Jason Yoder

function Test-DynamicValidateSet {
    [CmdletBinding()]
    Param(
        # Any other parameters can go here
    )

    DynamicParam {
            # Set the dynamic parameters' name
            $ParameterName = 'User'
           
            # Create the dictionary
            $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary

            # Create the collection of attributes
            $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
           
            # Create and set the parameters' attributes
            $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute
            $ParameterAttribute.Mandatory = $true
            $ParameterAttribute.Position = 1

            # Add the attributes to the attributes collection
            $AttributeCollection.Add($ParameterAttribute)

            # Generate and set the ValidateSet.
            # Change the next line to produce what you want to auto populate for the parameter.
            # Make sure it is DataType String.
            $arrSet = Get-ADUser -Filter * | Select-Object -ExpandProperty SamAccountName
            $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet)

            # Add the ValidateSet to the attributes collection
            $AttributeCollection.Add($ValidateSetAttribute)

            # Create and return the dynamic parameter
            $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParameterName, [string], $AttributeCollection)
            $RuntimeParameterDictionary.Add($ParameterName, $RuntimeParameter)
            return $RuntimeParameterDictionary
    }

    begin {
        # Bind the parameter to a friendly variable
        $User = $PsBoundParameters[$ParameterName]
    }

    process {
        # Your code goes here
        Get-ADUser -Identity $USer
    }

}



Thursday, December 8, 2016

Dealing with Property Names that Start with #

Tonight I’m doing my class maintenance on Microsoft Official Course 20697-2B Deploying and Managing Windows 10 Using Enterprise Services. For those of you who have taken my classes, you know I provide a OneDrive full of goodies to each class.  Right now I’m playing around with Chapter 3 and the migration of user data.  While working with size estimates for the migration store, I decided to import the XML file the ScanState.exe /p produces.

PS USMT:> $StorageInfo.Premigration.storeSize.Size | Get-Member –MemberType Properties

   TypeName: System.Xml.XmlElement

Name        MemberType Definition
----        ---------- ----------
#text       Property   string #text {get;set;}
clusterSize Property   string clusterSize {get;set;}

So, do you see the problem?  Take a look at the property called #text.  In PowerShell, the # symbol is the start of an inline comment.  That means that anything typed after it will not be processed.  That kind of makes calling this property a bit of a problem.  We can fix it.

If you do not code this correctly, PowerShell will interpret the # and everything after it as a comment.  The green font in the code demonstrates this.

$StorageInfo.PreMigration.StoreSize.Size |
    Select-Object -Property CluserSize,
        @{
           N = "SizeMB"
           E = {($_.#Text / 1MB).ToString('#.##') -as [Single]}
        }

To fix this problem, encapsulate our problematic property name inside of double quotes.

$StorageInfo.PreMigration.StoreSize.Size |
    Select-Object -Property CluserSize,
        @{
           N = "SizeMB"
           E = {($_."#Text" / 1MB).ToString('#.##') -as [Single]}
        }

Now you will be able to call the property and use it.



Wednesday, December 7, 2016

Using Events with SAPIEN PowerShell Studio

This is the last posting that I am doing on these series focusing on objects.  So far we have describe how properties describe an object.  We looked at how methods take actions against an object.  We also looked at how to subscribe to an objects events.  An event is triggered when something happens to an object.

Today we are going to create a very basic graphic interface using SAPIEN PowerShell Studio and demonstrate how to register and event and execute code when the event is triggered.

You can get a trial version from here (https://www.sapien.com/software/powershell_studio) .  Just click on the Try It link on the right.  This trial version is limit to just 5 graphical objects.  We will only be using one for simplicity.  Install and then launch the software.

Once you open SAPIEN PowerShell Studio, click File à New à New Form.

In the popup window, select Empty Form and then click Select.


From the Toolbox, drag and drop the Button object onto your form.


Now right click the button.  You can select the default event, which is a click, or Add Events to add any valid event for this object.  Select Edit Default Event (Click). This registers the event and takes us to the scripting window where we can add our code to execute when the click event is triggered.


Let’s just add the code to change the form’s background color to keep this simple.


Above is all the code that should be present.  Line 9 is the only code that we added.  There is a lot more code, but that you are not seeing.  PowerShell Studio write the code to build the form that you are using in the background so you did not have to do it yourself.  Go ahead and run your code.  You will be required to save it before running. Click the button and watch the button click event execute.




Tuesday, December 6, 2016

Describing Object Events

Today we take a look at the final member of an object, Events. Events are something that I use mostly if I need to put a graphical interface on top of my PowerShell code. You can also use them in your non-graphical PowerShell solutions. An event is generated when something happens to an object. So Properties describe an object. Methods are actions the object can take.  Events are when something happens to the object.  Let’s take a look at the member information for a Process Object and focus on the events.

PS C:\> Get-Process | Get-Member -MemberType Event


   TypeName: System.Diagnostics.Process

Name               MemberType Definition                                                                               
----               ---------- ----------                                                                              
Disposed           Event      System.EventHandler Disposed(System.Object, System.EventArgs)                           
ErrorDataReceived  Event      System.Diagnostics.DataReceivedEventHandler ErrorDataReceived(System.Object, System.Di...
Exited             Event      System.EventHandler Exited(System.Object, System.EventArgs)                             
OutputDataReceived Event      System.Diagnostics.DataReceivedEventHandler OutputDataReceived(System.Object, System.D...


We can see that there is an event called Exited.  We are going to subscribe to the Exited event of a process object. Here is what the MSDN documentation on System.Diagnostic.Process says about its events.

Go ahead an open an instance of Notepad.

PS C:\> Start-Process -FilePath Notepad

Save the instance of the Notepad process in a variable for easy reference.

PS C:\> $Proc = Get-Process -Name notepad

Now subscribe to your objects event. (I used the backtick character at the end of the first 2 lines to be careful not to miss it.)

PS C:\> Register-ObjectEvent -InputObject $Proc `
                     -EventName exited `
                     -SourceIdentifier notepad `
                     -Action {Write-Host "Process ended" -BackgroundColor DarkRed}

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                 
--     ----            -------------   -----         -----------     --------             -------                 
60     notepad                         NotStarted    False                                Write-Host "Process en...

We placed an action to take when this process ends.  It will display “Process ended” with a dark red background.  We can see that this is a background job.

PS C:\> Get-Job

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command                 
--     ----            -------------   -----         -----------     --------             -------                 
60     notepad                         NotStarted    False                                Write-Host "Process en...

We can also see the event that we are currently subscribed to.

PS C:\> Get-EventSubscriber -SourceIdentifier Notepad


SubscriptionId   : 8
SourceObject     : System.Diagnostics.Process (notepad)
EventName        : exited
SourceIdentifier : notepad
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  :
SupportEvent     : False
ForwardEvent     : False

Go ahead and stop the Notepad process.

PS C:\> Stop-Process -Name notepad

Process ended

You can see that our action executed.
Even though the process is closed and no longer exists, you are still subscribed to it.

PS C:\> Get-EventSubscriber


SubscriptionId   : 8
SourceObject     : System.Diagnostics.Process (notepad)
EventName        : exited
SourceIdentifier : notepad
Action           : System.Management.Automation.PSEventJob
HandlerDelegate  :
SupportEvent     : False
ForwardEvent     : False

You can unsubscribe to it.

PS C:\> Get-EventSubscriber -SourceIdentifier Notepad | Unregister-Event


That is how we subscribe to events in PowerShell.  Tomorrow, I’m going to show you how to do use events with SAPIEN PowerShell Studio.  You can get a trial version from here (https://www.sapien.com/software/powershell_studio) .  Just click on the Try It link on the right.

Monday, December 5, 2016

Using Overloaded and Static Methods

Yesterday, we looked at what a method is and the various ways to call them.  Today we are going to look at what is called an overloaded methods.  Let’s take a look at the System.String class (https://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx).  Take a look at the method for Replace.


The replace method has two implementations.  If you proved two single characters, the first implementation is used.  If you provide to strings, the second implementation is used.

PS C:\> $String = "You are number 1 in my book."

PS C:\> $String.Replace("1","2")
You are number 2 in my book.

PS C:\> $String.Replace("book","world")
You are number 1 in my world.

You can also utilize what are called Static Methods.  Take a look at the documentation for System.Math (https://msdn.microsoft.com/en-us/library/system.math(v=vs.110).aspx)


The purple box is the icon for a method.  The yellow ‘S’ means that it is a static method.  In short, you can call static methods without first creating an instance of the object.  In our previous example, we needed a System.Datetime object to call the AddSeconds() method on.  With static methods we do not.  I like System.Math a lot because it provides advanced mathematical functionality without having to write the functions myself.  For example, cosine.

PS C:\> [Math]::cos(40)
-0.666938061652262

We access these methods by first casting for System.Math.  The System namespace is already loaded in memory by default so you only need to cast for Math.  We then provide 2 colons and then the method name. Many of these methods are overloaded, so pay attention to the different ways to implement them.  They will save you a lot of time.

Sunday, December 4, 2016

Describing Object Methods

Yesterday, we took a look at how the properties of an object allows us to easily consume information.  The next object member we are going to look at are methods. Methods are awesome.  They essentially are free code that you can utilize so you do not need to write it yourself.  A method is usually an action that an object can on itself.  Take a look at the methods that are provided from the System.Datetime object that is produced by Get-Member.

PS C:\> Get-Date | Get-Member -MemberType Methods


   TypeName: System.DateTime

Name                 MemberType Definition                                                                            
----                 ---------- ----------                                                                            
Add                  Method     datetime Add(timespan value)                                                          
AddDays              Method     datetime AddDays(double value)                                                        
AddHours             Method     datetime AddHours(double value)                                                       
AddMilliseconds      Method     datetime AddMilliseconds(double value)                                                
AddMinutes           Method     datetime AddMinutes(double value)                                                     
AddMonths            Method     datetime AddMonths(int months)                                                        
AddSeconds           Method     datetime AddSeconds(double value)                                                     
AddTicks             Method     datetime AddTicks(long value)                                                          
AddYears             Method     datetime AddYears(int value)                                                          
CompareTo            Method     int CompareTo(System.Object value), int CompareTo(datetime value), int IComparable.C...
Equals               Method     bool Equals(System.Object value), bool Equals(datetime value), bool IEquatable[datet...
GetDateTimeFormats   Method     string[] GetDateTimeFormats(), string[] GetDateTimeFormats(System.IFormatProvider pr...
GetHashCode          Method     int GetHashCode()                                                                     
GetObjectData        Method     void ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info...
GetType              Method     type GetType()                                                                        
GetTypeCode          Method     System.TypeCode GetTypeCode(), System.TypeCode IConvertible.GetTypeCode()             
IsDaylightSavingTime Method     bool IsDaylightSavingTime()                                                           
Subtract             Method     timespan Subtract(datetime value), datetime Subtract(timespan value)                  
ToBinary             Method     long ToBinary()                                                                       
ToBoolean            Method     bool IConvertible.ToBoolean(System.IFormatProvider provider)                          
ToByte               Method     byte IConvertible.ToByte(System.IFormatProvider provider)                             
ToChar               Method     char IConvertible.ToChar(System.IFormatProvider provider)                              
ToDateTime           Method     datetime IConvertible.ToDateTime(System.IFormatProvider provider)                     
ToDecimal            Method     decimal IConvertible.ToDecimal(System.IFormatProvider provider)                        
ToDouble             Method     double IConvertible.ToDouble(System.IFormatProvider provider)                         
ToFileTime           Method     long ToFileTime()                                                                     
ToFileTimeUtc        Method     long ToFileTimeUtc()                                                                  
ToInt16              Method     int16 IConvertible.ToInt16(System.IFormatProvider provider)                           
ToInt32              Method     int IConvertible.ToInt32(System.IFormatProvider provider)                             
ToInt64              Method     long IConvertible.ToInt64(System.IFormatProvider provider)                            
ToLocalTime          Method     datetime ToLocalTime()                                                                
ToLongDateString     Method     string ToLongDateString()                                                             
ToLongTimeString     Method     string ToLongTimeString()                                                             
ToOADate             Method     double ToOADate()                                                                     
ToSByte              Method     sbyte IConvertible.ToSByte(System.IFormatProvider provider)                           
ToShortDateString    Method     string ToShortDateString()                                                            
ToShortTimeString    Method     string ToShortTimeString()                                                            
ToSingle             Method     float IConvertible.ToSingle(System.IFormatProvider provider)                          
ToString             Method     string ToString(), string ToString(string format), string ToString(System.IFormatPro...
ToType               Method     System.Object IConvertible.ToType(type conversionType, System.IFormatProvider provider)
ToUInt16             Method     uint16 IConvertible.ToUInt16(System.IFormatProvider provider)                         
ToUInt32             Method     uint32 IConvertible.ToUInt32(System.IFormatProvider provider)                         
ToUInt64             Method     uint64 IConvertible.ToUInt64(System.IFormatProvider provider)                         
ToUniversalTime      Method     datetime ToUniversalTime()        

What does all of this mean?  Well, let’s use this as an example.  It is December 31, 1999 at 23:59:59. Now, add 2 seconds to this DateTime object.  You need to provide the intelligence to your code to know:

  •       There are 60 seconds per minute
  •       There are 60 minutes per hour
  •       There are 24 hours in a day
  •       There are 31 days in December
  •       There are 12 months in a year
  •       December is the last month of the year.
  •       January is the first month of the year.


That sounds a bit daunting. Why do it when the System.DateTime object already has done this for you. Let’s first create the Datetime object to represent our situation.

PS C:\> Get-Date -Year 1999 -Month 12 -Day 31 -Hour 23 -Minute 59 -Second 59

Friday, December 31, 1999 11:59:59 PM

From the member information above, take note of the method called AddSeconds().  It accepts one argument.  That is the number of seconds that you want to add to the DateTime object.  Here are a few ways how to use it to add 2 seconds to our DateTime object and roll in the year 2000.

# Dot notation
(Get-Date -Year 1999 -Month 12 -Day 31 -Hour 23 -Minute 59 -Second 59).AddSeconds(2)

# Object enumeration with the basic syntax of ForEach-Object
Get-Date -Year 1999 -Month 12 -Day 31 -Hour 23 -Minute 59 -Second 59 |
    ForEach-Object -MemberName AddSeconds -ArgumentList 2

# Object enumeration with the advanced syntax of ForEach-Object
Get-Date -Year 1999 -Month 12 -Day 31 -Hour 23 -Minute 59 -Second 59 |
    ForEach-Object -Process {$_.AddSeconds(2)}

# Using a variable with dot notation
$Date = Get-Date -Year 1999 -Month 12 -Day 31 -Hour 23 -Minute 59 -Second 59
$Date.AddSeconds(2)

# Using a .NET constructor for System.DateTime and dot notation
([Datetime]$Date = "12/31/1999 23:59:59").AddSeconds(2)

Any of these solutions will give you the result.
Saturday, January 1, 2000 12:00:01 AM


Much easier than trying to code this object yourself. As with properties, you can find a variety of different methods in the online documentation at MSDN.