Monthly Archives: February 2015

Make Ping Accept Multiple Computers

Windows PowerShell, and an old-school command line tool favorite, collided today when I brainlessly typed the following:

PS C:\> ping computer1,computer2
Bad parameter computer2

This didn’t work, and as quickly as I realized my mistake, I thought, I’m going to have to fix it so ping can accept multiple computers.

There’s a couple ways I can do this, but my idea was to create an advanced function to do the work. I did that, but before I share the function, we should discuss what we could have done. We could have simply made an alias named ping that would run the Test-Connection cmdlet, a cmdlet that can handle a comma-separated list of computer names. Here’s an example of creating the alias and then using it to ping multiple computers.

PS C:\> New-Alias -Name ping -Value Test-Connection
PS C:\> ping computer1,computer2

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms)
------        -----------     -----------      -----------                              -----    --------
TOMMYMS PC... computer1       10.10.10.30                                              32       1
TOMMYMS PC... computer2       10.10.10.31                                              32       1
TOMMYMS PC... computer1       10.10.10.30                                              32       1
TOMMYMS PC... computer2       10.10.10.31                                              32       1
TOMMYMS PC... computer1       10.10.10.30                                              32       1
TOMMYMS PC... computer2       10.10.10.31                                              32       1
TOMMYMS PC... computer1       10.10.10.30                                              32       2
TOMMYMS PC... computer2       10.10.10.31                                              32       2

The reason this works is because of command precedence. If an alias and a command line tool share the same name, the alias will always run when the name is entered.

Well, this wasn’t quite want I wanted. I thought instead, I would make a wrapper around Test-Connection, called Test-TMConnection that would include a switch parameter (-Ping) that would return the standard ping results. I’ll dump in the function below and then we can walk though what it does.

Function Test-TMConnection {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)]
        [string[]]$ComputerName,

        [switch]$Ping
    )

    Begin {
    } # End Begin

    Process {
        If ($Ping) {
            ForEach ($Computer in $ComputerName) {
                ping $Computer
            }
        } Else {
            Test-Connection -ComputerName $ComputerName
        }
    } # End Process
} # End Function

Here’s how this works: The function is called by entering Test-TMConnection, the -ComputerName parameter, and then either one computer name, or a comma-separated list of computers. If the -Ping parameter is not used, it will run the standard Test-Connection cmdlet against the computer(s), like we saw in the alias example above. If -Ping is included, it will loop though the computers, using each one with ping. Here’s an example that includes the -Ping parameter.

PS C:\> Test-TMConnection -ComputerName computer1,computer2 -Ping

Pinging computer1.mydomain.com [10.10.10.30] with 32 bytes of data:
Reply from 10.10.10.30: bytes=32 time=2ms TTL=121
Reply from 10.10.10.30: bytes=32 time=1ms TTL=121
Reply from 10.10.10.30: bytes=32 time=1ms TTL=121
Reply from 10.10.10.30: bytes=32 time=1ms TTL=121

Ping statistics for 10.10.10.30:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 1ms, Maximum = 2ms, Average = 1ms

Pinging computer2.mydomain.com [10.10.10.31] with 32 bytes of data:
Reply from 10.10.10.31: bytes=32 time=1ms TTL=121
Reply from 10.10.10.31: bytes=32 time=2ms TTL=121
Reply from 10.10.10.31: bytes=32 time=1ms TTL=121
Reply from 10.10.10.31: bytes=32 time=1ms TTL=121

Ping statistics for 10.10.10.31:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 1ms, Maximum = 2ms, Average = 1ms

Important: Keep in mind, that if you were to use something like this, that you’ll be giving up other parameters that are included with ping and Test-Connection. This includes -t with ping, and -Count, and -Source with Test-Connection. In the end, the ping alias might be the better option.

Using OutVariable — Why Don’t I Do that More Often?

This week, Microsoft Virtual Academy had two live events about DSC (Desired State Configuration), hosted by Jeffery Snover and Jason Helmick. I watched as much as I was able, but there were some problems at work that demanded my attention, and so I was grudgingly pulled away from a good portion of both sessions. Luckily for me, and for you, if you missed them, is that the videos should be up in the next two to three weeks. That will allow anyone who is interested the ability to move through the modules (think sections, not PowerShell modules) around other ongoing tasks — like work.

I didn’t start this post to discuss DSC, but instead because of what I watched Jeffery Snover do several times. While I’ve always been aware of the existence of the -OutVariable common parameter, I’m not even sure if I’ve ever used it or not (although I’m certain I’ve used -ErrorVariable). This parameter is a great way to view your command’s results immediately, and write them to a variable at the same time.

In this example, we return the computers’ names from (all of) Active Directory (AD) that have the word ‘physical’ somewhere inside their description property. The problem here is that if we need to generate this list a second time, we’ll have to run the command again. This can be resource intensive, depending on the command, and not inline with best practice — at least, my best practice.

PS C:\> (Get-ADComputer -Filter {Description -like '*physical*'}).Name
DC01
DC02
DC03
WEB01
WEB02

In this example, we write our results to the variable $Physical. The difference here is that we don’t write the results to the screen automatically, but only when we echo the variable’s contents.

PS C:\> $Physical = (Get-ADComputer -Filter {Description -like '*physical*'}).Name
PS C:\> $Physical
DC01
DC02
DC03
WEB01
WEB02

In this example, we combine the best of both worlds: instant results written to the screen, with the “same” values stored in a variable. Notice that when I echo the variable, $P, it returns more than just the Name. This is because all the properties were written to the variable, before we displayed only the Name property. Note: I’ve concatenated the results after the first computer’s full results.

PS C:\> (Get-ADComputer -Filter {Description -like '*physical*'} -OutVariable P).Name
DC01
DC02
DC03
WEB01
WEB02
PS C:\> $P
DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mydomain,DC=com
DNSHostName       : dc01.mydomain.com
Enabled           : True
Name              : DC01
ObjectClass       : computer
ObjectGUID        : ...
SamAccountName    : DC01$
SID               : ...
UserPrincipalName :
...

Here’s how we can return only the Name property, using this variable.

PS C:\> $P.Name
DC01
DC02
DC03
WEB01
WEB02

Hopefully I can remember to use this common parameter more often. We’ve been taught to store our results in a variable, so we aren’t continually performing resource intensive queries. This is a great way to do that, with the option to have the results of a command written to the screen immediately. Adios, friends.

Extra – PowerShell Summit North America 2015

This series of posts was linked from PowerShell.org: https://powershell.org/2015/05/16/whats-it-like-at-powershell-summit/.

I decided in late February that I would document my trip and experience at the PowerShell Summit North America 2015 (that happens in April). This page is going to serve as the landing page for this project. I’ll link each of the new posts right from this post, so they can easily be read in chronological order (beginning at the bottom link), providing someone wants to do that, or reads any of this anyway. I truly believe this is going to be an incredible opportunity, and so I want to document my experience, and make it available to the PowerShell community, current and future. Thanks, and enjoy.

PowerShell Summit North America 2015 [#8]: Day Three
April 22, 2015

PowerShell Summit North America 2015 [#7]: Day Two
April 21, 2015

PowerShell Summit North America 2015 [#6]: Day One
April 20, 2015

PowerShell Summit North America 2015 [#5]: In Flight
April 19, 2015

PowerShell Summit North America 2015 [#4]: Closest
April 18, 2015

PowerShell Summit North America 2015 [#3]: Closer
April 13, 2015

PowerShell Summit North America 2015 [#2]: Close
April 10, 2015

PowerShell Summit North America 2015 [#1]: It’s So Far Away
February 22, 2015

Extra – PowerShell Summit North America 2015 [#1]

Read them all here: http://tommymaynard.com/extra-powershell-summit-north-america-2015-0-2015/

I decided I am going to write about my experience at my first PowerShell Summit—from beginning to end. The word ‘beginning’ is being used a bit loosely, as the PowerShell North America 2015 Summit is still 55 days away (see how I figured that out below). Regardless, I continue to find myself looking forward to this opportunity as it has every potential to be the highlight of my IT career, and so I’m going to post about it.

PS C:\> (New-TimeSpan -Start (Get-Date) -End 4/20/2015).Days
55
PS C:\> "$((New-TimeSpan -Start (Get-Date) -End 4/20/2015).Days) Days"
55 Days

Although, I’ve been registered for the summit for a few months now, and had my plane tickets for nearly as long, I just secured my hotel room. There was a bit of an internal debate with myself about where to stay. While some mentioned they prefer downtown, I just couldn’t expect that the daily cab fare both ways, and perhaps the extra cost of a downtown hotel, would be worth it. I really don’t know the first thing about North Carolina, or Charlotte, so it’s quite possible that I am very, very wrong.

That said, if anyone reading this is staying near the venue and wants to venture downtown for a meal, perhaps with others, then feel free speak up. Spitting the cab fare up a time or two would definitely be worth it, especially to discuss PowerShell over dinner. That is just something I cannot do with my wife and children. At least not often, and not for long—trust me, I’ve tried.

I’d be willing to discuss PowerShell over a meal closer to the venue, too. I’ve never eaten at a Ruby Tuesday, but that’s the closest food to my hotel. I added the link for me, but feel free to look at all the incredible food coming my way. Honestly, until today, I thought Ruby Tuesday was a buffet for retirees and grandparents, but some of that food looks surprisingly appetizing. The place looks much more appealing than I had assumed, too.

Moving on. Long before I knew I’d be attending the summit, PowerShell.org mentioned a program called Verified Effective. While the cost to take the test had always been mildly prohibitive, I was ecstatic to discover that the cost of the summit included this opportunity. Well, up until the program was cancelled really close after the time when I registered. My emotions were really being played with, even more so when I found out it was back on, although I was excited again. The difference was that the test would have to be taken in person (not remotely), and at the summit. I seriously may have been the first person to click and register on the Eventbrite URL that came via email. Based on opening the exam up to approximately 60 people, it appears that as of today, a touch more than half of the Verified Effective registrations have been claimed. I’m nervous, but looking forward to this opportunity.

I recently decided to read Don Jones’ and Jeffery Hicks’ Month of Lunches PowerShell books (book one & book two). I’ve finished the first one and a little over half way to complete the second title. I’d like to get these signed by their authors, but simply couldn’t do that without reading the books first. While I already know most of what I’ve read thus far, it has been a beneficial and comprehensive review. I long worried that in my learning, which was never front to back in any PowerShell book, that I may have missed something here and there. I had, and I’ve been filling in those little holes nicely since January. I would, without question, recommended these two titles to anyone that wants to learn PowerShell. They would’ve been a great way to learn, had I started with them first. Just find the money, buy them, learn it, and thank the three of us later—more so to them, of course.

I’ll stop here for now, but will be back with more summit ramblings as I find time and topics to cover. This really is going to be an amazing event. I’ll be up close and personal to people that think like I do, and that love automation and PowerShell. This occasion is going to bring together all the rock stars and celebrities of the PowerShell community. If you don’t hear more from me before my flight in April, then you can at least expect I’ll be writing on April 19th from the sky, somewhere between Arizona and North Carolina.

Finding Non-Resolveable IP Addresses

When preparing to bring new servers online, I often need a quick way to know what IP addresses, in a range of IP addresses, do not resolve to a name. This is the first step to determine unused IP addresses. The first time I did this was back before I was running Windows PowerShell 4.0 on Windows 8.1 which includes the Resolve-DnsName cmdlet. It meant I needed to use the command line tool nslookup; we’ll discuss both options in this post.

The first two examples below, use nslookup to try and resolve two different IPs: one that does resolve and one that doesn’t. It should be noted that resolving an IP address to a name is called Reverse DNS (rDNS). In the first example we have an IP address that resolves. That means it likely wouldn’t be an IP address I would want to use for a new server.

PS C:\> nslookup 10.10.10.2
Server:  dns.mydomain.com
Address:  10.10.10.1

Name:    dc01.mydomain.com
Address:  10.10.10.2

The next example shows an IP address that doesn’t resolve, and therefore, would likely be a useable IP address for one of my servers. Remember, we want to collect our failed name resolutions.

PS C:\> nslookup 10.10.10.4
Server:  dns.mydomain.com
Address:  10.10.10.1

*** dns.mydomain.com can't find 10.10.10.4: Non-existent domain

Let’s assume our range of possibly useable IPs is 10.10.10.2 – 10.10.10.254. This assumes we’re using .1 for the gateway and .255 for broadcast. We’ll use a sub range of this full range (10.10.10.2 through 10.10.10.5) for most of our testing and examples. We’re going to use the range operator (..) to help automate checking the IP addresses.

PS C:\> 2..5 | ForEach-Object {nslookup 10.10.10.$_}
Server:  dns.mydomain.com
Address:  10.10.10.1

Name:    dc01.mydomain.com
Address:  10.10.10.2

Server:  dns.mydomain.com
Address:  10.10.10.1

Name:    dc02.mydomain.com
Address:  10.10.10.3

Server:  dns.mydomain.com
Address:  10.10.10.1

*** dns.mydomain.com can't find 10.10.10.4: Non-existent domain
Server:  dns.mydomain.com
Address:  10.10.10.1

*** dns.mydomain.com can't find 10.10.10.5: Non-existent domain

Our results, above, indicate that .2 and .3 are resolving and therefore are likely not useable for us. It also indicates we may be able to use .4 and .5, since those are not resolving. There’s still too much information returned by nslookup, so let’s clean that up by only returning failed resolutions.

In the example below, we’ll pipe our nslookup results to the Select-String cmdlet and search for the three asterisks (***) that begin each line where there is a failed name resolution. By default, the Select-String cmdlet does a regex match, so we’ll need to use the more literal approach and include the -SimpleMatch parameter of Select-String.

PS C:\> 2..5 | ForEach-Object {nslookup 10.10.10.$_ | Select-String -Pattern *** -SimpleMatch}
*** dns.mydomain.com can't find 10.10.10.4: Non-existent domain
*** dns.mydomain.com can't find 10.10.10.5: Non-existent domain

PowerShell 3.0 on Windows 8 and Server 2012 brought us the Resolve-DnsName cmdlet as part of the DnsClient module. This is essentially the replacement for nslookup on newer versions of PowerShell, on newer versions of the underlying operating system. By default, this cmdlet will return much more information on a successful resolution and an error on a failed resolution. Although I’ve truncated the successful results, there is an example of both a success and failure, below.

PS C:\> Resolve-DnsName -Name 10.10.10.2

Name                       Type   TTL   Section    NameHost
----                       ----   ---   -------    --------
2.10.10.10.in-addr.arpa    PTR    214   Answer     dc01.mydomain.com
...

PS C:\> Resolve-DnsName -Name 10.10.10.4
Resolve-DnsName : 10.10.10.4 : The filename, directory name, or volume label syntax is incorrect
At line:1 char:1
+ Resolve-DnsName -Name 10.10.10.4
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (10.10.10.4:String) [Resolve-DnsName], Win32Exception
    + FullyQualifiedErrorId : ERROR_INVALID_NAME,Microsoft.DnsClient.Commands.ResolveDnsName

Now, what we need to do is find the failed name resolutions for our IP test range without displaying errors. This will require a little more work, but gives us more control over what’s actually displayed, instead of relying on the default output of nslookup.

In this example, we’ll run Resolve-DnsName for each IP address in our test range: 10.10.10.2 through 10.10.10.5. If it is unable to resolve, we’ll suppress the error using the -ErrorAction parameter, and then display our own message to inform us which IPs in our range didn’t resolve.

PS C:\> 2..5 | ForEach-Object {
>> If (-not(Resolve-DnsName -Name 10.10.10.$_ -ErrorAction SilentlyContinue)) {
>> Write-Output -Verbose "10.10.10.$_ -- Not Resolving"}
>> }
>>
10.10.10.4 -- Not Resolving
10.10.10.5 -- Not Resolving

If you made it all the way down here, then thanks for reading this post; I hope you found something useful. I would like to mention how to use .NET to resolve names to IPs, and IPs to names. Here’s a couple examples of both using a Microsoft name and IP.

PS C:\> [System.Net.Dns]::GetHostAddresses('microsoft.com')

Address            : 783919750
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 134.170.185.46

Address            : 3720129158
AddressFamily      : InterNetwork
ScopeId            :
IsIPv6Multicast    : False
IsIPv6LinkLocal    : False
IsIPv6SiteLocal    : False
IsIPv6Teredo       : False
IsIPv4MappedToIPv6 : False
IPAddressToString  : 134.170.188.221

PS C:\> [System.Net.Dns]::GetHostByAddress('134.170.185.46')

HostName                                Aliases                                 AddressList
--------                                -------                                 -----------
grv.microsoft.com                       {}                                      {134.170.185.46}

Get Some Help for Later Reading

I’m just starting to get my hands wet with Microsoft Lync. As I often do, I use the Windows PowerShell cmdlets to help learn more about a product; I did this same thing with Hyper-V. The unfortunate thing about the GUI (think, an MMC snap-in for instance), is that the menu options don’t always tell you exactly what that option is going to do, or its exact purpose. While the GUI can be unclear, PowerShell tells you exactly what a cmdlet does. With that knowledge, I’ve often been able to relate a cmdlet, and its purpose, to its respective menu option in the GUI.

I wanted to read though the Lync cmdlet’s help files, but only the cmdlet name and its synopsis. Here’s the command I ran to extract this information for later reading.

PS C:> Get-Command -Module Lync | Get-Help | Select-Object Name,Synopsis | Export-Csv -Path C:\LyncCmdlets.csv -NoTypeInfomation

The command above works this way: it returns all the cmdlets included in the Lync Module and sends (pipes) those to the Get-Help cmdlet. The Get-Help cmdlet pipes its results to Select-Object which filters the returned properties to just the Name and Synopsis from each cmdlet’s help file. At the end, those filtered results are sent to Export-Csv which creates a file I can read at my leisure.

Although there’s over 500 cmdlets, it’s safe to say that many of the nouns (the part after the dash [-]) will be the same across some of the cmdlets. That means that many of the Get-* cmdlets will have a partnering Set-* cmdlet. Get reads information and Set changes it. These nouns may also have a matching New-*, Remove-*, and possibly even a Test-* cmdlet. Now off to do some reading…

A Quick, Learn Windows PowerShell in a Month of Lunches, Review

I’ve been using, and continuing to learn, Windows PowerShell for a while now. While I’ve used various resources to promote my learning and understanding, I had never sat down and actually read a PowerShell book, front to back. Well, now I have.

While I knew upwards of 95% of the content, I went ahead and read Learn Windows PowerShell in a Month of Lunches by Don Jones and Jeffery Hicks. I have followed both authors in the past and was certain this would be a good title to start with—it was. In fact, being familiar with these two authors was why I was able to recommend this title, even long before I read the book myself. A bit backwards perhaps, but undeniable true. It’s a wonderfully, comprehensive guide to getting started with Windows PowerShell. As stated by Bennett Scharf, on the back cover, this in fact will be an extremely useful reference. With a generous and complete index, I will be able to easily pull up the concepts I read about in this book, whenever necessary.

Besides being able to say I’ve read the title (and with a good conscience, get it signed by the authors at the PowerShell Summit North America 2015 in April), I wanted to make sure that my method of learning PowerShell was in fact complete. I’ve learned PowerShell by reading help files, blogs, and articles posted to Twitter, as well as, trying things in the shell (this is key), and helping people on PowerShell forums. Even so, I wanted to be sure I hadn’t missed some of the fundamentals. I know many of the ‘hows,’ but was worried I may have missed a ‘why’ along the way. Like, why does it (PowerShell) do it this way?

My first, favorite part was the discussion on pipeline parameter binding. Parts of that topic never just came to me, and it is a concept that requires a complete understanding. The fantastic explanations in the book (chapter 9) have helped ensure I won’t have any questions about this concept again. After all my non-book learning, I never once read anywhere that you can only have one ByValue per cmdlet, even though it makes perfect sense as to why.

The second part that I greatly appreciated was the Regex (Regular Expressions) review. For whatever reason, I have the hardest time cementing these in my mind, and often find myself in need of a quick review. Knowing this book will spend all, or most, of it’s life after this weekend sitting with me at the office, will allow me to get a quick refresh when that’s required. It can be a scary concept for many, and this book laid it out in a quick and calm approach. I wish I read this the first time I was introduced to Regex. No kidding, but I folded down the top corner of this page—something I just don’t do to my books.

In the end, I will continue to recommend this book to people starting out with PowerShell. It explains PowerShell from the start, up to your first parameterized script. I had already purchased the toolmaking followup, Learn PowerShell Toolmaking in a Month of Lunches, even before I started this one, and plan to start reading it tomorrow. I left my copy in my office and so, sadly, I couldn’t start sooner.