Advanced Windows PowerShell Scripting Video Training

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

Wednesday, March 26, 2014

How long can a variable name be in PowerShell?

Well, that is a good question.  Before I answer this, let’s just cover a few best practices when it comes to naming variables.

  • Choose a variable name that gives you an idea of what is stored in the variable.
  • Use letters, numbers, and “_” in your names.
  • Do not use spaces.  They really make things look bad.

Now, about how long can they be?  I wrote a little function to help be create long strings of random characters and the I used that string as the name of my variable.

Function New-String

{

Param ($Length)

 

    $String = ""

    For ($X=0;$X -lt $Length; $X++)

    {

        $String += [char]((Get-Random(26))+65)

    }

    Write-Output $String

}

New-String 10000

 

I copied this string into memory.  I then typed a dollar sign and pasted this string.  Automatic carriage returns were added by the ISE so I had to go to the end of the string and press Delete a few times to get it all back on the same line.  I then added = “Hello”.  Below is a screen shot of my ISE.  Take notice of the column number.

 

image

 

I pressed enter and it accepted it.  I hit the up arrow and removed ‘'= “Hello” and pressed enter.   The contents of the variable dumped to the host.  In short, you can go up to 10,000 characters and more in a variable name.

The Variable drive truncates it when you look at it.

image

Should you do this???  Absolutely not.  This is just an exercise to show you that you do not have to worry about the length of a variable.  You just need to make sure it makes sense and is readable to others who may view your code.

Friday, March 21, 2014

Comparison of PowerShell DISM Module and DOS DISM Commands

DISM has been used for many years to mount images and to make changes without actually first deploying the image and then re-capturing it. With the prevalence of Windows PowerShell. We now have DISM’s capabilities available to us in the familiar PowerShell syntax.

One of the issues that I have always had with DISM is the cumbersome parameters. Here is a DISM command:

DISM /Get-WimInfo /WimFile:Install.wim

And its PowerShell counterpart:

Get-WindowsImage –ImpagePath Install.wim

The green highlights are the switches. You can see a difference. Also, by using PowerShell, you are using a technology that will be supported well into the feature as well as the search and help features of Windows PowerShell. Below are the commands used to add the BITS feature to a Windows 2012 R2 server image. The length of typing may appear to be the same, but with PowerShell’s TAB completion, you will most likely not have typos on the PowerShell side. Good luck with not making a typo with DISM.

PowerShell

DISM

Description

Get-WindowsImage –ImpagePath install.wim

Dism /get-WimInfo /WimFile:install.wim

List all images inside of the WIM file

Mount-WindowsImage –Path E:\Offline –ImagePath Install.wim –Name “Windows Server 2012 R2 SERVERSTANDARDCORE”

Dism /Mount-WIM /WimFile:install.wim /Name:”Windows Server 2012 R2 SERVERSTANDARDCORE” /MountDir:E:\Offline

Mounts a specific image from a WIM file.

Get-WindowsOptionalFeature –Path e:\online

Dism /Image:e:\Offline /Get-Features

List all of the features for the image.

Enable-WindowsOptionalFeature –Path e:\Offline –FeatureName BITS

Dism /Image:E:\Offline /Enable-Feature /FeatureName:BITS

Enables a specific feature in the mounted image

Dismount-WIndowsImage –Path E:\Offline –Save

Dism /Unmount-WIM /MountDir:E:\Offline /Commit

Dismounts the image and saves all changes made.

Click here for a list of all DISM commands for PowerShell.

Thursday, March 20, 2014

How to hide my Windows 8.1 Task Bar on my 2nd Monitor

This week I’m delivering Microsoft course 20411C: Administering Windows Server 2012.  One of the members of the class asked if it was possible to hide the task bar on my extended screen.  Yes, my task bars were on both screens.  Here is how to do it.

 

Right click your taskbar and select Properties.

image

Uncheck Show Taskbar on all displays and click OK. 

Problem solved.

Wednesday, March 19, 2014

With the AD Recycle Bin Turned on, What Happens when you Create a User Account with a Password that does not meet the Password Policy?

This was an interesting observation from one of my Windows Server 2012 classes.  While working with the AD Recycle bin in a lab, one of my students discovered some interesting accounts that were created. When he created user accounts that did not meet password complexity requirements, an account is temporarily made and then deleted.  When a new password is provided that meets the password requirements, then a new account is made.

We discovered this in two places.  First off in the Active Directory Administrative Center.  This is what caused the initial confusion.  Take a look.  This is in the Deleted Objects OU.

image

You can see multiple deleted accounts for Test2 and one for Test3.  Test3 is a valid, functioning user account.  Using the PowerShell command Get-ADObject –IncludeDeletedObjects –Filter * –Properties ObjectSID we can see that indeed, two accounts were created, with one of them deleted. Notice the RID portion of the SID is different.

image 

So, here is the big question, Can the deleted version of Test3 be brought back to life.  Here is what I received in the AD Administrative Center:

image

This is when I tried to restore this object to its original location.  I expected this.  This is what I got when I attempted to restore this object to an alternate location:

image

image

A second attempt after reopening the AD Administrative Center yielded the first error.  Again this is what I expected. I made one attempt to try and trick AD into restoring this object by changing the real Test3’s UPN and restoring the deleted one, but then I received this:

image

A restore to a different OU than the original OU and it worked.  So, when I logged into a client with a username of Test3, which one worked?  The original one did.  This is the one with the altered UPN name. I still do not know why this one was selected when both user names are the same.  When I used the UPN name of the 2nd Test3 user (The restored one), it successfully logged into that account.

You can’t foul AD, but you can make life difficult for your users.  Unless your users are logging in with UPN names, you will have two duking it out to see who can lock the other others account.  Make sure you have unique user names in your system.

Wednesday, March 12, 2014

Testing connections with PowerShell and Sending a eMail Report

My budding PowerShell Rock Stars are at it again.  This time we helped out a Network Administrator with testing the connectivity to clients and then email a report.  I’ve come across this type of request several times before.  Those of you who attend my sessions at the SMB Nation Emerging Technology Tour have see some similar code demonstrated.  With this group, I decided to press them a bit and we tried out converting our object that contains our report to HTML.  Here is our result.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

# Dynamic array to hold the output.

$Output = @()

 

# grab a list of computers from AD.

$ComputerList = Get-ADComputer -Filter *

 

# Count the number of computers for the Write-Progress Cmdlet.

$Count = $ComputerList |

         Measure-Object |

         Select-Object -ExpandProperty Count

 

# Control variable

$I = 0

 

 

$ComputerList |

    ForEach-Object {

        # Increment the control variable

        $I++

 

        # Calculate percent completed

        $PC = ($I/$Count)*100

 

        # Display progress bar.

        $Splat = @{"Activity" = "Connectivity Test: $_.Name";

                   "Status" = "$PC% Complete";

                   "PercentComplete" = $PC}

        Write-Progress @Splat

       

        # Create an object for each computer with the client's online status.

        $Output += New-Object -TypeName PSObject -Property @{

            "ComputerName" = $_.Name;

            "Status" = Test-Connection -ComputerName $_.Name -Quiet -Count 1

        }

     

    }

# Convert the output to HTML

$MailOutput = $Output | ConvertTo-HTML -Fragment | Out-String

 

# Send the email.

$Splat = @{"TO" = "Administrator@TechTour.com";

           "From" = "Allofus@HP.com";

           "Subject" = "Connectivity Test";

           "BodyAsHTML" = $True;

           "Body" = $MailOutput;

           "SMTPServer" = "Tech-EX1"}

Send-MailMessage @Splat

 

Line 2 is a dynamic array to hold our output.

Line 5 - You may want to consider parameterizing the filter to better meet your needs.

Lines 8 – 10 get a count of how many clients will be evaluated.  This is used to generate a progress bar.

Line 13 is our control variable for the progress bar.

Lines 16 – 36 perform several activities.  Line 19 will increment our counter.  Line 22 will perform the math to give us a percentage for the progress bar.

Lines 25 – 27 creates a splat for the cmdlet Write-Progress

Line 28 implements the progress bar.

Lines 31-34 test the connection to the clients.  You can see that we are creating our object holding our results while we are running the connection test.  Take a look at line 33.  We are creating a property called “Status” and setting equal to the result of Test-Connection. We are using the –Quiet parameter to return only a $TRUE or $FALSE from Test-Connection

Line 38 converts the objects stored in $Output into HTML code.  We are using the ConvertTo-HTML cmdlet to do the conversion.  By default, this creates a complete HTML page.   This will not work with the Send-MailMessage cmdlet so we use the –Fragment parameter to produce only code for an HTML table which will work with Send-MailMessage.

Lines 41 – 36 creates the splat for Send-MailMessage.

Line 47 sends the email.

Tuesday, March 11, 2014

Removing Identical Content from Multiple Text Logs

This week I am delivering an advanced PowerShell course in Norfolk, VA.  This is my second week with this group of inspiring PowerShell Rock Stars so I decided to push this group a little earlier than usual and I had them help me develop a script to help an individual who posted a question on PowerShell.com (http://powershell.com/cs/forums/t/16403.aspx?PageIndex=1

His task was to examine 3 different text based logs.  Should there be a line that is the same in each of the 3 logs, that line was to be removed from each log.  Sounds simple.  The problem that he was looking at is that his logs were hundreds of thousands of lines long.  This is a perfect example of how to apply PowerShell to a real world situation. We did this as a brain storming session.  For the sake of time, we did not convert this into a cmdlet or a parameterized script.  We have to save some of the fun for the guy we were helping.  Here are our results:

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

# Cast three variables of of type [System.Collections.ArrayList]

# to hold the contents of each log.  Use the Get-Content cmdlet

# to populate the ArrayLists.

 

[System.Collections.ArrayList]$Log1 = Get-Content -Path "Log1.txt"

[System.Collections.ArrayList]$Log2 = Get-Content -Path "Log2.txt"

[System.Collections.ArrayList]$Log3 = Get-Content -Path "Log3.txt"

 

# Create a new ArrayList called $List to hold all strings that

# are present in each event log.

 

$List = New-Object System.Collections.ArrayList

 

# Utilizing Log1 as our control, perform a comparison operation to

# Log2 and Log3.  If they both report $TRUE (A match was found) then

# add that string to $List.

ForEach ($L in $Log1)

{

 

    If (($L -in $Log2) -and ($L -in $Log3))

    {

       $List.Add($L)

    }

 

 

}

 

# Cycle through $List and utilize the "Remove" method

# of the ArrayList to clear that cell of the array out

ForEach ($Item in $List)

{

    $Log1.Remove($Item)

    $Log2.Remove($Item)

    $Log3.Remove($Item)

 

}

 

# Commit the three filtered logs to new files.

$Log1 | Out-File -FilePath "Log1Filtered.txt"

$Log2 | Out-File -FilePath "Log2Filtered.txt"

$Log3 | Out-File -FilePath "Log3Filtered.txt"

In lines 5 – 7, we used an ArrayList.  The advantage of this data type (http://msdn.microsoft.com/en-us/library/system.collections.arraylist(v=vs.110).aspx) is that we have the Remove() method.  When we execute the Remove() method on data in the array, it automatically re-dimensions the array after removing the specified content.

Line 12 creates the ArrayList that will hold the content of any cell from $Log1, $Log2, and $Log3 that is present in all three logs.  We will use this information to remove content from those logs later.

Line 17-26 is where we are searching for content that is present in all three logs.  We are using $Log1  as our control for the ForEach loop. 

Line 20 utilizes 2 comparison operators joined by the –and logical operator.  Each of these comparison operations is using the –in operator.  Traditionally, we would have used a ForEach loop to search each of these other two logs.  In this case, we are using the functionality of the –in comparison operator provided to us by PowerShell.  It will return $True if the other logs contain the string that we are searching for.  If both $Log2 and $Log3 contain the string, then we add that string to $List.

Lines 30-36 cycle utilize the Remove method of the ListArray object to remove each string from all three array.

Lines 39 – 41 write new filtered versions of all three logs that do not  contain strings that are identical