Advanced Windows PowerShell Scripting Video Training

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

Wednesday, November 30, 2016

Describing Objects

With over 70 PowerShell classes under my belt, I have a good idea of where most IT Pros struggle when making the mind shift to the PowerShell world.  Objects is one of the concepts that take a bit of time to accept.  Even though everything in PowerShell is an object, we need to remember that objects have been in the realm of the developer for decades.  For IT Pros, this is a foreign concept that we must embrace.  Besides, objects make your scripting life so much easier.

Over the course of the next 7 blog postings, we will examine the different components of an object and supply you with some simple code examples to help you understand them better.

Object orientated programming was just a buzz word on the horizon when I graduated college with a degree in Computer Science in the late 90’s.  I was out in the real world as a Network Administrator as opposed to a programmer for many years.  Sure, I wrote some automation programs for myself, but they were not object based.  When PowerShell came about, I did not realize that objects were used at first.  It was not until a client asked me to stop teaching VBScript and teach PowerShell that I now needed to understand them.

As I started to play around with PowerShell, the light bulbs all of the sudden turned on in my head with regards to objects and this opened a whole new world of powerful, yet simplified coding for me. These next few blob post will hopefully open your eyes as to what objects are and help you make the transition to a much better place.

In the most basic sense, an object represents something. This could be a user account, a mailbox, a web page, or even a representation of the fan running on your device.  If you ask PowerShell to list all of the volumes on your device, each one will have the same members.  These members are properties, methods, and events.  We will describe each in more detail later on. Take a look at this output.
PS C:\> Get-Volume

DriveLetter FileSystemLabel FileSystem DriveType HealthStatus OperationalStatus SizeRemaining      Size
----------- --------------- ---------- --------- ------------ ----------------- -------------      ----
                            NTFS       Fixed     Healthy      OK                     99.03 MB    450 MB
                            NTFS       Fixed     Healthy      OK                    321.21 MB    350 MB
E           DATA            NTFS       Fixed     Healthy      OK                     21.73 GB 238.34 GB
D           DATA            NTFS       Fixed     Healthy      OK                     19.99 GB 238.34 GB
            WINRETOOLS      NTFS       Fixed     Healthy      OK                    212.47 MB    492 MB
C           OS              NTFS       Fixed     Healthy      OK                      5.06 GB 108.29 GB
            PBR Image       NTFS       Fixed     Healthy      OK                     243.9 MB   9.03 GB

Notice how each volume all contain the same members.  That is they all have a DriveLetter, HealthStatus, Size, etc… If I asked for the user accounts, would they have a SizeRemaining?  Doubtful.  In order to by a specific type of object, you must have the same members as other objects of the same type.  That way if I grab a list of all user objects, I know that all of the objects have a member called GivenName.


The next few articles in this series will describe each member in much further detail.

Friday, November 11, 2016

How to Search Strings with [ and ] in Them

One of the more difficult aspects of teaching PowerShell is the PowerShell pipeline. After delivering over 70 PowerShell classes, I know this is the part to really slow down and take our time with.  I’ve been working on some code to help answer the question “What can you pipe to what without plowing through the objects and help files.”  Since this is a repetitive task for anybody who codes in PowerShell, I thought it would be fun to automate the process.

While doing my R&D on this project, I discovered that to search for strings with ‘[‘ or ‘]’ cannot be done with the –Like comparison operator.  Take a look below.

PS C:\> $String = "ABC[CDE]"

PS C:\> $Sting -like "*[*"
The specified wildcard character pattern is not valid: *[*
At line:1 char:1
+ $Sting -like "*[*"
+ ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], WildcardPatternException
    + FullyQualifiedErrorId : RuntimeException



It turns out the characters ‘[‘ and ‘]’ are actually part of our wildcard characters.  That is why we get a pattern error. Take a look at this MSDN article: Supporting Wildcard Characters in Cmdlet Parameters.


The below image is from that MSDN article.

The last usage is the key to our success.  We actually need to encapsulate our query for a ‘[‘ or ‘]’ inside of square braces.

PS C:\> $String = "ABC[CDE]"

PS C:\> $String -like "*[[]*"
True

In this case, we are only looking for a pattern of anything with a ‘[‘ somewhere in it.

PS C:\> $String = "String[]"

PS C:\> $String -like "*[[]]"
True

In the above example, we are looking for a string that ends with ‘[]’.

Pattern matching is an extremely valuable tool to have in your PowerShell arsenal.  This little trick is helping me produce the code that I need to help make learning PowerShell even easier.


Wednesday, November 9, 2016

Speed Test with .NET vs PowerShell and 20,000 Leagues Under the Sea

I’ve given a presentation at PowerShell User Groups several times that involve quantifying how much money you save your organizations through PowerShell.  Of course my actual goal is to help IT Pros justify a bigger raise.  I’m working on some new coding practices to help speed up your code execution.  I’m actually developing this code for both my Advance PowerShell Toolmaking class and also as a topic to hopefully present at the PowerShell Europe Summit in 2017 (Keeping my fingers crossed).  Here is just one of 19 (and counting) ways that I have come up with to accelerate code execution.

I’m looking at replacing PowerShell cmdlets with .NET objects.  This example below looks at replacing Get-Content with [System.IO.StreamReader].  I utilized a text file of one of my favorite books, 20,000 Leagues Under the Sea by Jules Verne. The results are in measurement of time called ticks.  This is because milliseconds were too big.

[System.IO.StreamReader] vs. Get-Content
----------------------------------------

Information on 20,000 Leagues Under the Sea
Number of lines: 12518

ReadToEnd : ReadToEndAsync : Get-Content
25671     :    8039        : 3685429
47580     :    5030        : 3601630
18351     :    4040        : 3602349
47085     :    5056        : 3578195
19283     :    4447        : 3778645
47591     :    5425        : 3620563
19420     :    4615        : 3567812
44806     :    4961        : 3550549
20025     :    4219        : 3727009
45259     :    5125        : 3718870

As you can see, using the ReadToEndAsync method of System.IO.StreamReader is around 99% faster than Get-Content. The test was completed 10 times with clear results each time.  Below is the code.  I apologize for the excessive use of Write-Host, but this code is developed for use in the classroom, not production.


#region [System.IO.StreamReader] vs. Get-Content
# look at using [IO.Filestream] and [System.IO.StreamReader] as opposed to Get-Content or event Import cmdlets
    Clear-Host
    Write-Host
    Write-Host '[System.IO.StreamReader] vs. Get-Content' -ForegroundColor Yellow
    Write-Host '----------------------------------------' -ForegroundColor Yellow
    Write-Host
    Write-host "Information on 20,000 Leagues Under the Sea"
   

    # Location of 20,000 Leagues Under the Sea.
    $File = 'E:\One Drive\OneDrive\MCTExpert\Classes\PS405\CodeOptimization\20KUnderTheSea.txt'
    $Lines = (Get-Content -Path $File | Measure-Object -Line).Lines

    Write-Host "Number of lines: " -NoNewline
    Write-Host $Lines -ForegroundColor Cyan
    Write-Host
    Write-Host 'ReadToEnd : ReadToEndAsync : Get-Content'


    # Perform the test 10 times.
    For ($X = 0 ; $X -lt 10 ; $X++)
    {
        # Test 1 - Use the ReadToEnd() method of [System.Io.Streamreader]
        $Test1 = (Measure-Command -Expression {
                    $Book = New-Object -TypeName System.IO.StreamReader -ArgumentList $File;
                    $Book.ReadToEnd() | Out-Null
                    }).Ticks
   
        # Test 2 - Use the ReadToEndAsync() method of [System.Io.Streamreader]
        $Test2 = (Measure-Command -Expression {
                    $Book = New-Object -TypeName System.IO.StreamReader -ArgumentList $File;
                    $Book.ReadToEndAsync() | Out-Null
                    }).Ticks     
       
        # Test 3 - Use the PowerShell Cmdlet Get-Content.
        $Test3 =( Measure-Command -Expression {
                                        Get-Content -Path $File | Out-Null
                                        }).ticks
    
 
       # Provide for color coded output to display in class.
       # Green - Fastest.
       # Light blue - 2nd.
       # Dark blue - slowest.

       $Color1 = "DarkCyan"
       $Color2 = "DarkCyan"
       $Color3 = "DarkCyan"
       If ($Test1 -lt $Test2 -and $Test1 -lt $Test3) {$Color1 = "DarkGreen"}
       ElseIf ($Test2 -lt $Test1 -and $Test2 -lt $Test3) {$Color2 = "DarkGreen"}
       ElseIf ($Test3 -lt $Test1 -and $Test3 -lt $Test2) {$Color3 = "DarkGreen"}
      
       If ($Test1 -gt $Test2 -and $Test1 -gt $Test3) {$Color1 = "DarkBlue"}
       ElseIf ($Test2 -gt $Test1 -and $Test2 -gt $Test3) {$Color2 = "DarkBlue"}
       ElseIf ($Test3 -gt $Test1 -and $Test3 -gt $Test2) {$Color3 = "DarkBlue"}

       Write-Host "$Test1" -BackgroundColor $Color1 -NoNewline
       Write-Host '     :    ' -ForegroundColor White -NoNewline
       Write-Host "$Test2" -BackgroundColor $Color2 -NoNewline
       Write-Host '        : ' -ForegroundColor White -NoNewline
       Write-Host "$Test3" -BackgroundColor $Color3
    } # END: For ($X = 0 ; $X -lt 10 ; $X++)

    #endregion [System.IO.StreamReader] vs. Get-Content