Monthly Archives: June 2016

PSMonday #9: Monday, June 27, 2016

Topic: Less Used Variable Properties Continued I

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

As was mentioned last week, variables have some properties we don’t often use, and many of us, may not even know about them. Last week we briefly learned about the Description property of a variable, and today, we’ll start to learn about the Options property.

While a variable’s Options property is set to None by default, there’s at least two other possibilities, and one of them, is ReadOnly. The first example uses New-Variable to create a new, read-only variable named String3, and Get-Variable and Select-Object to return all the variable’s properties.

New-Variable -Name String3 -Value 'A new week; another Monday.' -Option ReadOnly

Get-Variable -Name String3 | Select-Object *

Name        : String3
Description :
Value       : A new week; another Monday.
Visibility  : Public
Module      :
ModuleName  :
Options     : ReadOnly
Attributes  : {}

Now, what does it mean that it’s read-only? It means that we can’t change the value that’s stored by the variable, as is indicated below.

Set-Variable -Name String3 -Value 'A new week; another Friday!'

Set-Variable : Cannot overwrite variable String3 because it is read-only or constant.

Notice in the error message that it indicates we can’t overwrite the variable because the variable is read-only or constant. It turns out that we actually can change the value stored in a read-only variable, if we use the -Force parameter.

Set-Variable -Name String3 -Value 'We Want Friday!' -Force

Get-Variable -Name String3 | Select-Object *

Name        : String3
Description :
Value       : We Want Friday!
Visibility  : Public
Module      :
ModuleName  :
Options     : ReadOnly
Attributes  : {}

So, in the end, a read-only variable can be overwritten if absolutely necessary. Keep this read-only option in mind as you create variables in Windows PowerShell. There may be times you create variables and want to mostly protect the original, stored value. In that case, you can choose to make them read-only.

If we already have a variable created, how do we then make it read-only? We have to use Set-Variable, whether we created the variable with New-Variable, or the standard way, as is used below.

$String4 = 'Last variable for today.'
$String4

Last variable for today.

(Get-Variable -Name String4).Options
None

Get-Variable -Name String4 | Set-Variable -Option ReadOnly

(Get-Variable -Name String4).Options
ReadOnly

To clear a variable’s value (to continue to allow a variable to exist, but to remove the value it stored), we have to use the -Force parameter. Same goes for removing the entire variable; that will also require the -Force parameter if it’s a read-only variable.

Clear-Variable -Name String3 -Force

Remove-Variable -Name String4 -Force

Get-PSCallStack Demonstration Using Multiple Functions

I wrote a couple recent posts that used the Get-PSCallStack cmdlet. In my case, Get-PSCallStack helped one function determine what function invoked it, and used the information to further determine if that function was approved to invoke it, or not. In doing this, I wrote a series of small functions I’d like to share to help demonstrate this process.

In the below code example, I’ve defined a series of functions. The first function defined is called Get-Main, and it does a few things. It sets a variable $Index to zero, dumps the Get-PSCallStack commands into a global variable (that will exist after the function completes), and then loops through each of the command properties in the second variable, displaying its correctly assumed index, and the command name.

The following functions are in place to progressively call one another from the bottom up. Working downward, however, Get-OneUpOne invokes Get-Main (discussed above), Get-OneUpTwo invokes Get-OneUpOne, Get-OneUpThree invokes Get-OneUpTwo, etc. These multiple functions end up being listed in Get-PSCallStack, as we’ll soon see.

Function Get-Main {
    $Index = 0
    $Global:Var = (Get-PSCallStack).Command
    $Var | ForEach-Object {
        "Index $Index : $_"
        $Index ++
    }
}

Function Get-OneUpOne {
    Get-Main
}

Function Get-OneUpTwo {
    Get-OneUpOne
}

Function Get-OneUpThree {
    Get-OneUpTwo
}

Function Get-OneUpFour {
    Get-OneUpThree
}

Get-OneUpFour

The last line in the above example, starts the magic by invoking Get-OneUpFour, that invokes Get-OneUpThree, etc., moving upward. Here’s a gif that shows how these are invoked, working up from the bottom.

get-pscallstack-demonstration-using-multiple-functions01

When this chunk of code is dropped into the ISE and run, we get the results listed below. They indicate the index and value of Get-PSCallStack’s recorded commands, or steps, on the way to invoking the Get-Main function. Notice, that it’s backwards, and what I mean is this: The first index 0, is the last command recorded. The last index, 5, is the first command recorded.

Index 0 : Get-Main
Index 1 : Get-OneUpOne
Index 2 : Get-OneUpTwo
Index 3 : Get-OneUpThree
Index 4 : Get-OneUpFour
Index 5 : <ScriptBlock>

Since we created the global variable $Var, we can verify if the above results are correct — if our assumed index is accurate. We’ll check with a single index first, and then run $Var though a For loop to see each index.

$Var[2]

Get-OneUpTwo
For ($i = 0; $i -lt $Var.Length; $i++) {
    "Index $i -- $($Var[$i])"
}

Index 0 -- Get-Main
Index 1 -- Get-OneUpOne
Index 2 -- Get-OneUpTwo
Index 3 -- Get-OneUpThree
Index 4 -- Get-OneUpFour
Index 5 -- Get-PSCallStack_Example.ps1

Take a look at index 5 in the directly above example, and then the further above example. One says, “<ScriptBlock>,” and one says, “Get-PSCallStack_Example.ps1.” Any idea what changed between these two examples? If you guessed that I saved my code example, while writing this post, then you’d be correct.

The highest numbered index* — 5 in this example — is always going to be the starting point — whether it’s called from the prompt, or a saved file, and the lowest index — index 0 — will always be the currently invoked function. This means that index 1 will always be the calling function, of the last function that was invoked.

* The highest numbered index will also always be index -1, such as $Var[-1] would equal “<ScriptBlock>,” or “Get-PSCallStack_Example.ps1.” Knowing this, it’s possible to work backwards through these results, or any other array.

So it’s been said, the other time we see an array in reverse, is the $Error variable. $Error[0] is always the most recent error, not the first error. Thanks for reading, and we’ll do it again sometime soon.

Build a Number Line

A year or two ago, I wrote my one and only game in Windows PowerShell. It’s 1 to 100; maybe you played it as a kid. The computer chooses a random number between 1 to 100. You make guesses and every time you’re wrong, the computer will tell you if you should guess higher, or lower, on your next turn. This continues until you guess the correct number. Once you’re a winner, it’ll display the number of attempts it took, the number of games played, and your average attempts per game. Here’s an image that shows that it only took me three guesses (the average, over time, seems to be around 6 to 7).

build-a-number-line01

In the last few months, my daughter has begun to occasionally ask me to play. She’s a smart, little 4-year-old, but the more she plays, the more I wish I had built in an easier mode, or two. Those may be coming.

As we were sitting there last night, she mentioned that she couldn’t find her number line. I had drawn one a few months ago that she’d use to help determine the range of numbers she should choose from next. Well, it went missing. As I try to solve all my worldly problems with PowerShell, I threw together a quick function that would allow us to draw a quick number line in a separate console. Now, she could easily locate a number in the middle of her closest high number and closest low number. Here’s the function, now.

Function Show-NumberLine {
    Param ([int]$Num1, [int]$Num2)
    $Num1..$Num2 | ForEach-Object {$NumberLine += "$_-"}
    "<--$NumberLine->"
}

Show-NumberLine -Num1 1 -Num2 20
<--1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-->
Show-NumberLine -Num1 1 -Num2 10
<--1-2-3-4-5-6-7-8-9-10-->

One of these days, I’ll add to the 1 to 100 function, and enable an easier mode, or two, to perhaps include the number line for beginner users. In the meantime, you can download the function here: https://gallery.technet.microsoft.com/The-1-to-100-Game-5288e279 and use number line function separately, if you need it. 😉

PSMonday #8: Monday, June 20, 2016

Topic: Less Used Variable Properties

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

When someone sets, or assigns, a variable in Windows PowerShell, we typically expect it to look a certain way, as is demonstrated below. This example also shows how we typically return a variable’s value, after it’s been assigned.

$String = 'Welcome back to Monday.' # Assign a value to variable.
$String # Return a variable’s value.

Welcome back to Monday.

This assigns, or sets, the variable named string, the value of ‘Welcome back to Monday.’ Straightforward, right? Well, this isn’t the only way to assign a variable in PowerShell. There’s a more formal process that offers a few extra options. When we use the *-Variable cmdlets, we don’t use the dollar sign ($). The dollar sign is only used to indicate to the PowerShell parser that what follows it, will be a variable name. The difference here is that these variable cmdlets already know you’re providing a variable name.

New-Variable -Name String2 -Value 'Come on, Friday.'
Get-Variable -Name String2

Name                           Value
----                           -----
String2                        Come on, Friday.

If you choose to use the Get-Variable cmdlet to return just the value, you can use the -ValueOnly parameter, dotted-notation, or Select-Object’s -ExpandProperty parameter. In older versions of PowerShell, dotted-notation may not be an option.

Get-Variable -Name String2 -ValueOnly
(Get-Variable -Name String2).Value
Get-Variable -Name String2 | Select-Object -ExpandProperty Value

Come on, Friday.
Come on, Friday.
Come on, Friday.

I’m not here to suggest variables should always be created with New-Variable, that values should always be returned with Get-Variable, that variables should always be updated with Set-Variable, or even that we should always clear or remove variables with Clear-Variable and Remove-Variable, respectively. What I’m out to do, is tell you about a couple extra properties that are attached to our variables, that you might not know about, and how we might use them.

Let’s modify the command we used to return the value of our $String2 variable, so we return all the properties. Keep in mind, that we can do the same thing with our $String variable that was created without the New-Variable cmdlet.

Get-Variable -Name String2 | Select-Object *

Name        : String2
Description :
Value       : Come on Friday.
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

Notice that we have a Description property and an Options property. The Description property is another way to provide additional meaning to a variable. While you should strive to name your variables in a way that describes their contents, if you’re feeling up to it, you can add additional information about the variable in this property.

Set-Variable -Name String2 -Description 'Demo purposes only'
(Get-Variable -Name String2).Description

Demo purposes only

Let’s talk about the Options property next week, as it’s a bit more useful.

Specify Which Functions Can Invoke Another Function Part II

It wasn’t long after I wrote and posted Part I of this topic — which I didn’t know was a Part I at the time — that I had another idea.

For those that didn’t read the post linked above, I have a function called Send-ErrorMessage. Its purpose is to send an email if the catch block of a try-catch, that doesn’t include an error exception, executes. It’s a safety net, just in case I haven’t properly coded for an unknown error condition. Because I had to export the function, so that it’s available to other functions in other modules, I needed a way to ensure that only specific functions were able to invoke Send-ErrorMessage. I didn’t want a user using the function; I only wanted the functions I wrote, that were approved, to be able to use the Send-ErrorMessage function.

Well today, I took the conditional logic that was taking up space in my Begin block and moved it to the [ValidateScript()] attribute. This also helped clean up some of the Process block, too. The only thing that I’m giving up, is that now the message to someone trying to invoke this function with an unapproved function, or at the prompt, is that it’ll show an error using red text, instead of a warning using orange text (in the ISE).

I may have mentioned this before, but I believe it’s okay to display standard, red text error messages in your tools, depending on the audience. If I’m writing tools for my team, they should be comfortable enough to decipher PowerShell errors. If the tool is being written for end-users, or lower tier employees, then it may be wise to better control the errors and warnings.

The complete, modified code is below. It begins by defining the Send-ErrorMessage function. Then it creates two additional functions — one that is approved to invoke Send-ErrorMessage, and one that’s not. Then, it invokes those two functions — Test-Allowed and Test-NotAllowed, respectively — and displays the results one right after the other. The first function will be permitted and will write the verbose statements in the Process block, but the second function will fail inside the [ValidateScript()] attribute, as it’s not approved to invoke Send-ErrorMessage.

Copy, paste, and take it for a run. After you’ve run the code, enter Send-ErrorMessage manually. It still won’t let you run it from the command line, even if you provide an approved function name, as the value of the -FunctionName parameter. That’s right, you can’t fake it out, as it’s not taking your word, it’s using the value returned by Get-PSCallStack. Thanks for reading!

Function Send-ErrorMessage {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)]
        [ValidateScript({
            $AcceptableFunctions = 'Get-AJob','Test-Allowed','Get-Real'
            $CallingFunction = (Get-PSCallStack)[1].Command
            If (-Not ($CallingFunction -in $AcceptableFunctions)) {
                Throw "The `"$_`" function or command, does not have approval to invoke this function. Send-ErrorMessage will not work if you use the function manually and enter an approved function name."
            } Else {
                $true
            }
        })]
        [string]$FunctionName
    )

    Begin {
    } # End Begin.

    Process {
        Write-Verbose -Message "The calling function ($($PSBoundParameters.FunctionName)) is approved." -Verbose
        Write-Verbose -Message 'Beginning to send error message ...' -Verbose
    } # End Process.
    
    End {
    } # End End.
} # End Function: Send-ErrorMessage.


Function Test-Allowed {
    # Divide by 0 to force error/catch block.
    try {
        10 / 0
    } catch {
        Send-ErrorMessage -FunctionName $MyInvocation.MyCommand.Name
    }
} # End Function: Test-Allowed.


Function Test-NotAllowed {
    # Divide by 0 to force error/catch block.
    try {
        10 / 0
    } catch {
        Send-ErrorMessage -FunctionName $MyInvocation.MyCommand.Name
    }
} # End Function: Test-NotAllowed.


# Invoke Function.
Test-Allowed

# Invoke Function.
Test-NotAllowed

Specify Which Functions Can Invoke Another Function

I have a function called Send-ErrorMessage. Its sole purpose is to send me an email if the catch block of a try-catch statement executes. Now, not just any catch block, as there can be more than one, but one where a specific error exception is not included.

The below example obtains a random Exchange server name as part of its try block. If that command produces an error, one of two catch blocks will execute. The first catch block will execute if the error produces a Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException exception. The exception is listed in square brackets after the catch keyword. The second catch block will execute if it’s any other exception. This, is the error I want to know about. When the code in the second catch block executes, it first creates a parameter hash table and it then sends that to the Send-ErrorMessage function, where the error is presented to the user, and an email is sent.

try {
    # Randomly select Exchange Server.
    $ExchServ = Get-Random (Get-ADGroupMember $ADGroup |
       Where-Object -FilterScript {$_.objectClass -eq 'computer'}).Name

} catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
    Write-Warning -Message "Cannot find object with the identity $ADGroup."

} catch {
    # Unknown error exception.
    $ErrorParams = @{
        FunctionName = $MyInvocation.MyCommand.Name
        ErrorMessage = $Error[0].ToString()
        ErrorType = $Error[0].Exception.GetType().FullName
    }
    Send-ErrorMessage @ErrorParams
}

At first, I decided that the Send-ErrorMessage function wasn’t to be exported from its module. This meant that only the other functions in that module, would be able to use Send-ErrorMessage. This was done to prevent a human from directly interacting with the Send-ErrorMessage function. In time, I had a decision to make, as I decided I wanted to invoke Send-ErrorMessage from functions that weren’t in the same module, where Send-ErrorMessage was declared.

To do this, I had to export Send-ErrorMessage, thus making it available to all my functions regardless of module, and anyone that invoked the function manually. It was this second part I wanted to prevent; I didn’t want a user to be able to use this function. I only wanted specific functions, in varying modules, to be allowed to use the Send-ErrorMessage function.

What I needed was a way to prevent the function from doing much, if it was invoked by something other than an approved function. To do this required me to know what function invoked the Send-ErrorMessage function while the Send-ErrorMessage function was currently being invoked. I hadn’t considered this before, and so it took some thinking and testing. In the end, I have a solution.

To help demonstrate, let’s start with two functions: The first one is allowed to invoke Send-ErrorMessage, and the second one is not allowed to invoke Send-ErrorMessage. You’ll see this in the upcoming Send-ErrorMessage function. Before we get to that function, though, get comfortable with the two below functions.

Function Test-Allowed {
    # Divide by 0 to force error/catch block.
    try {
        10 / 0
    } catch {
        Send-ErrorMessage
    }
} # End Function: Test-Allowed.


Function Test-NotAllowed {
    # Divide by 0 to force error/catch block.
    try {
        10 / 0
    } catch {
        Send-ErrorMessage
    }
} # End Function: Test-NotAllowed.

They work this way: try to divide by 0 and intentionally error. The catch block will then invoke Send-ErrorMessage. Inside Send-ErrorMessage is where the determination is made as to whether or not the function that invoked it, is allowed to continue to use it. If the function that invoked it, is in the $AcceptableFunctions variable, then the code to send an email with the error information, which isn’t actually included in the below function, can be sent. If the function isn’t in the $AcceptableFunctions variable, then the user will get a warning and nothing will be sent.

Function Send-ErrorMessage {
    [CmdletBinding()]
    Param (
    )

    Begin {
        # This variable can be set a number of ways to include Get-Command.
        $AcceptableFunctions = 'Get-AJob','Test-Allowed','Get-Real'
        $CallingFunction = (Get-PSCallStack)[1].Command
        
        $Proceed = $false
        If ($CallingFunction -in $AcceptableFunctions) {
            $Proceed = $true
        }
    } # End Begin.

    Process {
        If ($Proceed) {
            Write-Verbose -Message "The calling function ($CallingFunction) is approved." -Verbose
            Write-Verbose -Message 'Beginning to send error message ...' -Verbose
            # DO STUFF!!!
        } Else {
            Write-Warning -Message "The calling function ($CallingFunction) is NOT approved."
            Write-Warning -Message "This function ($($MyInvocation.MyCommand.Name)) can only be invoked by approved functions."
        }
    } # End Process.
    
    End {
    } # End End.
} # End Function: Send-ErrorMessage.

Let’s invoke Send-ErrorMessage now, by invoking both the Test-Allowed and Test-NotAllowed functions. In the below example, the first two lines, that start with VERBOSE, are returned from invoking the Test-Allowed function, and the last two lines, that start with WARNING, are returned from invoking the Test-NotAllowed function. It works just like it should, allowing me to do something (send that error email), when I trust the calling function.

# Invoke Function.
Test-Allowed

# Invoke Function.
Test-NotAllowed

VERBOSE: The calling function (Test-Allowed) is approved.
VERBOSE: Beginning to send error message ...
WARNING: The calling function (Test-NotAllowed) is NOT approved.
WARNING: This function (Send-ErrorMessage) can only be invoked by approved functions.

Here’s the entire code, so you can copy it to the ISE, etc. and test it for yourself.

Function Send-ErrorMessage {
    [CmdletBinding()]
    Param (
    )

    Begin {
        # This variable can be set a number of ways to include Get-Command.
        $AcceptableFunctions = 'Get-AJob','Test-Allowed','Get-Real'
        $CallingFunction = (Get-PSCallStack)[1].Command
        
        $Proceed = $false
        If ($CallingFunction -in $AcceptableFunctions) {
            $Proceed = $true
        }
    } # End Begin.

    Process {
        If ($Proceed) {
            Write-Verbose -Message "The calling function ($CallingFunction) is approved." -Verbose
            Write-Verbose -Message 'Beginning to send error message ...' -Verbose
            # DO STUFF!!!
        } Else {
            Write-Warning -Message "The calling function ($CallingFunction) is NOT approved."
            Write-Warning -Message "This function ($($MyInvocation.MyCommand.Name)) can only be invoked by approved functions."
        }
    } # End Process.
    
    End {
    } # End End.
} # End Function: Send-ErrorMessage.


Function Test-Allowed {
    # Divide by 0 to force error/catch block.
    try {
        10 / 0
    } catch {
        Send-ErrorMessage
    }
} # End Function: Test-Allowed.


Function Test-NotAllowed {
    # Divide by 0 to force error/catch block.
    try {
        10 / 0
    } catch {
        Send-ErrorMessage
    }
} # End Function: Test-NotAllowed.


# Invoke Function.
Test-Allowed

# Invoke Function.
Test-NotAllowed

My first thought after these functions were written and tested, was what happens now that Send-ErrorMessage is in memory. Can I, as a user, just invoke Send-ErrorMessage myself? I can try, but I won’t get anywhere, as is demonstrated below.

Send-ErrorMessage
WARNING: The calling function (<ScriptBlock>) is NOT approved.
WARNING: This function (Send-ErrorMessage) can only be invoked by approved functions.

Keep in mind other ways to assign the $AcceptedFunctions variable. This doesn’t, and realistically, shouldn’t need to be a static. Instead, use the Get-Command cmdlet to collect the functions that will be allowed to invoke Send-ErrorMessage. If you use a prefix in your function names, it’s easy to isolate which functions can invoke Send-ErrorMessage. The below example assumes you prefix the nouns in your functions with Work, such as Get-WorkUser, and Get-WorkJob.

$AcceptableFunctions = (Get-Command -Noun Work*).Name

In closing, if you didn’t pick it up yourself, this works in thanks to the Get-PSCallStack function. It stores the called commands in a reverse array. That means, that the final function, Send-ErrorMessage, in this example, is index 0: (Get-PSCallStack)[0]. Therefore, the calling function, or command run in the console, is going to be (Get-PSCallStack)[1]. Tada! And to think, just a day or two ago, and I don’t think I had ever used the Get-PSCallStack cmdlet.

Update: There’s a Part II: Read it here.

More AWS PowerShell Changes Due to Twitter (and Me)

It happened again. My Tweet, linked to a post here, became the catalyst for a change in the AWS PowerShell module. I’m 2 for 2. This time, AWS didn’t simply correct the spelling of a parameter name; they wrote a new cmdlet. Remove-EC2Instance works as advertised. It’ll prompt for confirmation before terminating an EC2 instance unless the Force parameter is also included with the command. It is flawless. You can always get the newest AWSPowerShell module at http://aws.amazon.com/powershell.

What this didn’t do, however, is fix Stop-EC2Instance. Steve, the individual that spotted this and my last AWS Tweet, and likely made these corrections and additions, said they couldn’t remove the malfunctioning Terminate parameter from Stop-EC2Intance. For those that didn’t read my last AWS post, the Terminate parameter never prompted for confirmation before terminating an instance (unless a change has been made since Remove-EC2Instance was released).

I read an interesting article recently that indicated to use termination protection:

Use termination protection for non-auto-scaling instances. Thank me later.
If you have any instances which are one-off things that aren’t under auto-scaling, then you should probably enable termination protection, to stop anyone from accidentally deleting the instance. I’ve had it happen, it sucks, learn from my mistake!”

While it was still quite amazing to get a second change made to the AWSPowerShell module, I’d recommend that everyone continue to be careful with Stop-EC2Instance. Perhaps you can write your own wrapper function, with the same name as the cmdlet (and therefore, it’ll be the default when Stop-EC2Instance is called), that forces confirmation. Then again, you can just use Remove-EC2Instance now. We’ll hope that when people look to terminate an EC2 instance, they find Remove-EC2Instance before they find the Terminate parameter in Stop-EC2Instance, such as I would have, had it previously existed. 🙂

PSMonday #7: Monday, June 13, 2016

Topic: Test-NetConnection

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

Let’s spend a small part of this Monday morning learning about the Test-NetConnection cmdlet — a potential, telnet replacement. This cmdlet was introduced in PowerShell 4.0 which shipped “in box” with Windows 8.1 and Server 2012 R2.

Test-NetConnection returns a connectivity test to a remote computer. When the cmdlet is entered without a specific computer in which to test against, it will use internetbeacon.msedge.net, a domain owned by the Microsoft Corporation.

Test-NetConnection

ComputerName           : internetbeacon.msedge.net
RemoteAddress          : 13.107.4.52
InterfaceAlias         : Ethernet
SourceAddress          : 10.10.10.50
PingSucceeded          : True
PingReplyDetails (RTT) : 38 ms

This can be helpful, and provides proof of Internet connectivity, but often you’ll want to test a connection closer to the computer that initiated the test. In the case where you want to check a computer in a data center, or only a room away, you can use the -ComputerName parameter and provide a computer name as the parameter value, such as DC01 in this example.

Test-NetConnection -ComputerName DC01

ComputerName           : DC01
RemoteAddress          : 10.10.20.2
InterfaceAlias         : Ethernet
SourceAddress          : 10.10.10.50
PingSucceeded          : True
PingReplyDetails (RTT) : 39 ms

There’s a port parameter that can be used, that will allow you to test against a specific port on the remote computer.

Test-NetConnection -ComputerName DC01 -Port 5985

ComputerName           : DC01
RemoteAddress          : 10.10.10.2
RemotePort             : 5985
InterfaceAlias         : Ethernet
SourceAddress          : 10.10.10.50
PingSucceeded          : True
PingReplyDetails (RTT) : 42 ms
TcpTestSucceeded       : True

If you don’t know the port number, you may be able to use the -CommonTCPPort parameter and supply one of the accepted parameter values. There’s directions at the bottom of today’s PSMonday on how to view the help for this cmdlet, that indicate the accepted values. In this next example, we use RDP as the parameter value for this -CommonTCPPort parameter.

Test-NetConnection -ComputerName DC01 -CommonTCPPort RDP

ComputerName           : DC01
RemoteAddress          : 10.10.10.2
RemotePort             : 3389
InterfaceAlias         : Ethernet
SourceAddress          : 10.10.10.50
PingSucceeded          : True
PingReplyDetails (RTT) : 45 ms
TcpTestSucceeded       : True

There’s also an -InformationLevel parameter that will allow you to specify that you want detailed information returned, or in the case of the example below, only want a Boolean (true or false), value returned.

Test-NetConnection -ComputerName DC01 -CommonTCPPort HTTP -InformationLevel Quiet

False

There are more features to Test-NetConnection, to include a -TraceRoute and a -Hops parameter. If you’re interested in learning more about those, or want to read the full help — much of which you already know, now — enter one of the next two commands.

Get-Help -Name Test-NetConnection -Full
Get-Help -Name Test-NetConnection -ShowWindow

Next time you need to telnet from one host to another, try Test-NetConnection instead of telnet, and see if it isn’t a little more helpful.

PSMonday #6: Monday, June 6, 2016

Topic: Splatting and Hash Tables Continued

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

So, back to splatting: If you ever have a parameter that doesn’t need an assigned value, where the value is equal to true if the parameter is included, and false if it’s not — a switch parameter — then use $true or $false as the parameter value in the hash table. You can see an example of this below. Notice that in the example one of the parameter values wasn’t hardcoded, and instead was assigned using the value from another variable. Doing this isn’t always necessary, but it’s being shown, as an example for a time when it may be needed.

$Command = 'Get-ADUser'
$Params = @{
    Name = $Command
    ShowWindow = $true
}

Get-Help @Params

It should be said, that if you don’t include a switch parameter in the hash table, that it won’t be included when the cmdlet is run, and will therefore be false by default.

Let’s splat Send-MailMessage. This command, and its need for so many parameters and parameter values, makes it a great candidate for splatting, unlike the above Get-Help command where there was only two included parameters.

$MailParams = @{
    From = 'noreply@mydomain.domain.com'
    To = 'tommymaynard@mydomain.domain.com'
    Subject = 'Using Send-MailMessage and Splatting'
    Body = "This email sent from $env:USERNAME."
    SmtpServer = 'smtp.mydomain.domain.edu'
}

Send-MailMessage @MailParams

Bonus: If you have more parameters to add to a command, and they’re not included in the hash table (for whatever reason), you can still add them to the command.

Send-MailMessage @MailParams -Attachments 'C:\file.txt'

Second Bonus: What could be done instead of adding a separate parameter and parameter value to the command, as we saw in the above Bonus section, is adding another key-value pair to our hash table using the .Add() method.

$MailParams.Add('Attachments','C:\File.txt')

$MailParams

Name              Value
----              -----
Attachments       C:\File.txt
SmtpServer        smtp.mydomain.domain.com
Subject           Using Send-MailMessage and Splatting
Body              This email sent from tommymaynard.
From              noreply@mydomain.domain.com
To                tommymaynard@mydomain.domain.com

Send-MailMessage @MailParams

That’s it. Enjoy your Monday.

Two Year Anniversary

Just a quick post to mention that tommymaynard.com has been up for two years this month. That’s June 2014 through 2016.

I remember early 2014 and thinking about buying the domain name, about the prospect of writing assistive PowerShell content, and about working to associate my name with Windows PowerShell. Two years later, and it’s been somewhat of a success — I didn’t know if I could do it, but I have. It’s almost difficult to believe, but I’ve been told that my efforts have helped people improve their knowledge of PowerShell, and even assisted in their careers. To help, was always the original idea. To learn it deeper, myself, was a welcomed benefit.

There’s no stopping here. This post is a just a brief intermission until the next topic.

Update: As of yesterday (June 7, 2016), I’ve renewed the tommymaynard.com domain for another two years. 🙂