Twitter Reply – Rebel Doesn’t Mean Rebel to Everyone

Twitter Reply to: no link

I saw a recent Twitter #PowerShell post and while I wanted to respond to it on Twitter, I didn’t. I was opposed to what it said, but I didn’t feel it was my place to call anyone out in that fashion. That’s why there isn’t a link above, where they might’ve been otherwise.

The twitter post in which I’m referring indicated that a person was a “rebel” by not using an approved PowerShell verb. I saw the included :P, and that’s fine, but only if the author is joking about the whole thing — I didn’t get that they were.

To use an unapproved verb, especially while knowing you shouldn’t, is everything that PowerShell is trying to stay away from. Part of the success of PowerShell has been the consistency in which it’s been developed by Microsoft, and others. While you might consider yourself a rebel, I consider what you’re doing, a problem.

I will admit, there has been a time or two that I’ve struggled with the best option for my verb, but I’ve always found one. Here’s my recommendation if you are not satisfied with the list of approved verbs: Use an alias; don’t be a “rebel.”

Let’s say I have a function I want to invoke using the name Smack-Yourself, and it looks like this:

Function Smack-Yourself {
    Write-Output -Verbose "I've been smacked!"
}

I can tell you without looking; smack is not an approved verb. We’ll check if it exists anyway.

PS C:\> Get-Verb -Verb Smack
PS C:\>

Nope, this verb hasn’t (yet?) been approved by Microsoft.

Instead of using an unapproved verb, let’s give our function an approved verb and then make an alias we can use instead. There’s no best practice for aliases; name them whatever you want. As far as your function name, please stay consistent and follow the verb dash noun naming convention, using an approved verb.

Set-Alias -Name Smack-Yourself -Value Pop-Yourself

Function Pop-Yourself {
    Write-Output -Verbose "I've been smacked!"
}

In the example above, we’ve used Set-Alias to modify (or create) an alias, called Smack-Yourself. When run, this alias will ultimately execute the Pop-Yourself function, where Pop is an approved verb. Even if the approved verb you choose doesn’t perfectly align with the verb you wanted to use, you can use whatever you want, if you’re using an alias.

Extra – PowerShell Summit North America 2015 [#3]

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

Well, I did it; I figured out what sessions I want to attend at next week’s PowerShell Summit North America 2015. It wasn’t easy, and I had to con-tin-u-al-ly remind myself that the sessions are being recorded, and that I’ll have an option to watch the ones I missed at a later time.

The sessions I selected are going to offer me the ability to hear various PowerShell big names speak. I’m mean seriously, when this event is over, I’ll be able to say that I’ve heard Don Jones and Jeffrey Snover speak (again), Mike Robbins (who recently followed me on Twitter — what!?), Dave Wyatt, Jeffery Hicks, Lee Holmes, Richard Siddaway and June Blender — the list goes on. That’s an accomplishment for me, and I’m not even doing anything but sitting and listening. It’s hardly any work on my part, but I’ll do it.

Here’s a screen capture of the sessions I plan to attend. While the speaker is important, the content is as well. We’re just days away, now, so I’ll be back to write more soon.

MyAgendaReduced85

Extra – PowerShell Summit North America 2015 [#2]

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

I cannot believe how quickly April has come. The last, and first, time I decided to write about the upcoming PowerShell Summit North America 2015, it was 55 days away. Today, it’s only 9 days away — well, that’s exciting! I took a command from my previous post about this topic and wrapped it in a function. While I may never use it again, here it is: proof that this event is ridiculously close — as if you needed a function to tell you this.

Function Get-TMDaysUntilPSSummit2015 {
    [CmdletBinding()]
    Param ()

    Begin {
    } # End Begin.

    Process {
        Write-Output -Verbose "$((New-TimeSpan -Start (Get-Date) -End 4/20/2015).Days) Days"
    } # End Process.
} # End Function

Get-TMDaysUntilPSSummit2015
9 Days

As of recent, we now have a downtown venue for the meet-and-greet Sunday night. While all the details haven’t been worked out, I supposedly have a ride there with a PowerShell MVP — how cool is that? The sessions have been updated, too. I’m suddenly second guessing all the sessions I should attend.

The Scripting Wife has been adding to the excitement with a recent series of posts about the summit’s speakers, which I’ve linked below. I’ve read all of these, and they’re great. While I haven’t spoken to anyone but Don Jones and The Scripting Guy and Wife in person (and I doubt they remember that anyway), I am quite aware of the big names in PowerShell. I read their blogs and articles; I read their posts on forums and social media. There’s going to be a ridiculous amount of PowerShell talent at this event.

Meet the PowerShell Summit 2015 Speakers #1
Meet the PowerShell Summit 2015 Speakers #2
Meet the PowerShell Summit 2015 Speakers #3
Meet the PowerShell summit 2015 Speakers #4
Meet the PowerShell summit 2015 Speakers #5

While I’m short on things to say today, I will reiterate that I’m so excited to get this summit underway. On that note, I should mention that I am very grateful to my employer for this opportunity, and for my family, to help keeps things in order while I’m gone. Of course, my wife pretty much owns that anyway.

Back to my employer: I want to note that I’m grateful working in an environment where my desire to know and implement PowerShell is supported. I’m pleased that they understand the importance of PowerShell and automation, and that having me attend this summit is seen as beneficial.

Give a Parameter a Default Value

Part II: http://tommymaynard.com/quick-learn-give-a-parameter-a-default-value-part-ii-2015/

If you’re into Windows PowerShell, then you probably think a little like me. You want to do things fast, and efficiently. There’s a reason we pound out commands and write scripts: we want to make the most of our time, and PowerShell let’s us do that. With that in mind, I decided I should modify a cmdlet I often use, so that using it takes less time, by default.

The Test-Connection cmdlet does for us what ping always has. It sends ICMP request packets to a remote computer or device. If the remote computer or device sends us a reply, then we know the device is up. It should be stated, that ICMP replies can be restricted so that a computer or device that is up, may not reply. Although I’ve opted to use Test-Connection for my example, this concept can be used with any number of other cmdlets and their parameters.

Let’s start by taking a look at the default output of the Test-Connection cmdlet. By default, Test-Connection will ping a given computer four times. If I were checking for latency, four replies would probably be better than one, but because I just want to know if the computer is up or down, a single reply is suitable.

PS C:\> Test-Connection -ComputerName bing.com

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms)
------        -----------     -----------      -----------                              -----    --------
TOMMYMAYNA... bing.com        204.79.197.200                                            32       14
TOMMYMAYNA... bing.com        204.79.197.200                                            32       13
TOMMYMAYNA... bing.com        204.79.197.200                                            32       14
TOMMYMAYNA... bing.com        204.79.197.200                                            32       13

This cmdlet includes a -Count parameter, and so I could have used that, as -Count 1, so that my computer only sent a single packet. But remember, I want be fast and efficient — I don’t want type more to see less. I want to type the same and make things faster. To accomplish this, what I’ll do is change the default behavior of this command to only send one packet. These means I’ll need to make use of the $PSDefaultParameterValues variable.

The $PSDefaultParameterValues variable stores any modifications to the default values of any of our cmdlet’s parameters. Since I don’t have any modified default values, the variable has nothing to return.

PS C:\> $PSDefaultParameterValues
PS C:\>

In the example below, we’ll use the Add() method to add a key/value pair to the variable. The keys are anything in the Name property, and the values are anything in the Value property. There is a one-to-one ratio between keys and values. These are also referred to as hash tables, associative arrays, or a dictionary object.

After we’ve added our key/value pair, we’ll try Test-Connection again, as we did in the first example.

PS C:\> $PSDefaultParameterValues.Add('Test-Connection:Count','1')
PS C:\> $PSDefaultParameterValues

Name                           Value
----                           -----
Test-Connection:Count          1

PS C:\> Test-Connection -ComputerName bing.com

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms)
------        -----------     -----------      -----------                              -----    --------
TOMMYMAYNA... bing.com        204.79.197.200                                            32       13

PS C:\>

As we can see, Test-Connection will now only ping a computer one time by default. Now, what happens when I do want to test for latency? I can use the -Count parameter and supply whatever number I want, so long as it’s 1 through 2147483647. Using zero or less, or 2147483648 will not work. I know, I tried.

You can read more information on the about_Parameters_Default_Values page here: https://technet.microsoft.com/en-us/library/hh847819.aspx.

Give your Variable a Description

When we think of variables in Windows PowerShell, we often only consider two parts: the name of the variable, and the value of the variable. Well, it turns out that those aren’t the only properties; let’s discuss the description property.

I can’t say I’ve ever added a description to a variable until now, but I can think of times, when looking at someone’s code, where I wish I knew the reason why a variable existed. Best practice would indicate we use meaningful names for our variables, so it’s probably safe to assume that the same people that might use a poorly-named variable, probably don’t know or care that variables can have descriptions… but, I digress.

In this first example, we’ll create a new variable using what I’d call the standard method — the equal sign assignment operator.

PS C:\> $a = 12345
PS C:\> $a
12345
PS C:\> Get-Variable a | Select-Object *

Name        : a
Description :
Value       : 12345
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

In line 1, we created a new variable, $a, and set its value to the numeric 12345. In the next line, we simply echoed the variable’s value. In line 4, we used the Get-Variable cmdlet and piped it to the Select-Object cmdlet and * so we were able to view all of its properties. If you take a look at the results, you’ll see the description property, and notice that it’s currently blank.

In the next example, we’ll use the Set-Variable cmdlet to modify the variable’s description.

PS C:\> Set-Variable a -Description 'This variable contains a 5-digit number.'
PS C:\> Get-Variable a | Select-Object *

Name        : a
Description : This variable contains a 5-digit number.
Value       : 12345
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

PS C:\>

Once we use the Get-Variable cmdlet, and return all the properties again, we can see that our variable now contains a description value. Now, while many user-defined variables, such as we created here, don’t often contain descriptions, many of the automatic and preference variables do — take a look at a segment of the results returned by the next command.

PS C:\> Get-ChildItem variable: | Select-Object Name,Description | Format-Table -AutoSize

Name                       Description
----                       -----------
...
MaximumAliasCount          Maximum number of aliases allowed in a session
MaximumDriveCount          Maximum number of drives allowed in a session
MaximumErrorCount          Maximum number of errors to retain in a session
MaximumFunctionCount       Maximum number of functions allowed in a session
MaximumHistoryCount        Maximum number of history objects to retain in a session
MaximumVariableCount       Maximum number of variables allowed in a session
MyInvocation
NestedPromptLevel          Dictates what type of prompt should be displayed for the current nesting level
...

Well, there you go: something you might not have known about, and something you may never use.

Protect your Variables with ReadOnly and Constant Options

I wrote a post a day to two back about creating an array variable that contained other arrays. I then went on to create additional, easier-to-remember variables, to use as the indexes. Here’s the post if you’d like to read it: http://tommymaynard.com/ql-working-with-an-array-of-arrays-2015/.

I started thinking, what if you create a variable for this easier-to-remember purpose, and then acidentally overwrite it? Well, as assumed, it is no longer going to work as first intended. Here’s a quick example starting back at the array of arrays concept.

PS C:\> Set-Variable -Name TeamWareServers -Value @(('serv01','serv02'),('serv03','serv04','serv05'))
PS C:\> $TeamWareServers
serv01
serv02
serv03
serv04
serv05
PS C:\> Set-Variable -Name f -Value 0 # Front end servers
PS C:\> $f
0
PS C:\> Set-Variable -Name b -Value 1 # Back end servers
PS C:\> $b
1
PS C:\> $TeamWareServers[$f]
serv01
serv02
PS C:\> $TeamWareServers[$b]
serv03
serv04
serv05

Although it’s easier to remember which servers are which, we have the possibility that our variables, $f and $b, could easily be overwritten. Here’s an example of overwriting the variables’ values and then not being able to use them as we did in the last example. I added an extra space after the results, of which there were none, so it’s easy to tell that these variable no longer work.

PS C:\> $f = 20
PS C:\> $b = 'newvalue'
PS C:\> $TeamWareServers[$f]
PS C:\>
PS C:\> $TeamWareServers[$b]
PS C:\>

So, how can we better protect our variables? There’s two ways we’ll discuss: ReadOnly and Constant. These two options will protect our variables from being assigned any new value(s). Take a look at this example where we’ll reset our $f and $b variables back to their original values.

PS C:\> Set-Variable -Name f -Value 0 -Option ReadOnly
PS C:\> $f
0
PS C:\> Set-Variable -Name b -Value 1 -Option Constant
Set-Variable : Existing variable b cannot be made constant. Variables can be made constant only at creation time.
At line:1 char:1
+ Set-Variable -Name b -Value 1 -Option Constant
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (b:String) [Set-Variable], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableCannotBeMadeConstant,Microsoft.PowerShell.Commands.SetVariableCommand

In the example above, we assigned a new value to our $f variable and made it ReadOnly using the -Option parameter. When we tried to modify the $b variable to make it a Constant, we received an error. This is because we don’t have the ability to make an existing variable a Constant. In the next example, below, we’ll remove the $b variable and then recreate it with the Constant option. Keep in mind that Set-Variable will work like New-Variable, if the variable doesn’t already exist.

PS C:\> Remove-Variable -Name b
PS C:\> Set-Variable -Name b -Value 1 -Option Constant
PS C:\> $b
1

Now let’s try what we did earlier and assign new values to these variables. You’ll soon see that when the variable’s option is set to Read-Only or Constant, that we’re not able to change their values.

PS C:\> $f = 20
Cannot overwrite variable f because it is read-only or constant.
At line:1 char:1
+ $f = 20
+ ~~~~~~~
    + CategoryInfo          : WriteError: (f:String) [], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotWritable

PS C:\> $b = 'newvalue'
Cannot overwrite variable b because it is read-only or constant.
At line:1 char:1
+ $b = 'newvalue'
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (b:String) [], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotWritable

If you’re anything like me, then you might be wondering what the difference is between ReadOnly and Constant. We’ll let the next example help explain.

PS C:\> Remove-Variable -Name f
Remove-Variable : Cannot remove variable f because it is constant or read-only. If the variable is read-only, try the
operation again specifying the Force option.
At line:1 char:1
+ Remove-Variable -Name f
+ ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (f:String) [Remove-Variable], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotRemovable,Microsoft.PowerShell.Commands.RemoveVariableCommand

PS C:\> Remove-Variable -Name f -Force # This works.
PS C:\>
PS C:\> Remove-Variable -Name b
Remove-Variable : Cannot remove variable b because it is constant or read-only. If the variable is read-only, try the
operation again specifying the Force option.
At line:1 char:1
+ Remove-Variable -Name b
+ ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (b:String) [Remove-Variable], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotRemovable,Microsoft.PowerShell.Commands.RemoveVariableCommand

PS C:\> Remove-Variable -Name b -Force # This doesn't work.
Remove-Variable : Cannot remove variable b because it is constant or read-only. If the variable is read-only, try the
operation again specifying the Force option.
At line:1 char:1
+ Remove-Variable -Name b -Force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (b:String) [Remove-Variable], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotRemovable,Microsoft.PowerShell.Commands.RemoveVariableCommand

When a variable is ReadOnly, the variable can be removed. This does, however, require the use of the -Force parameter. Consider that a safety net. The difference here, is that when a variable is a Constant, it cannot be removed, even with the use of the -Force parameter. If you want to remove a user-defined Constant variable, you’re going to have to end your PowerShell console and start another one.

Keep these options in mind if you ever want to protect the value(s) in your variables. While we’re at it, we probably should have made the array (of arrays) variable, $TeamWareServers, ReadOnly or Constant, too.

Working with an Array of Arrays

There’s a group of servers that I use for a specific project. I can never remember their names or how those correspond to their roles (web front end vs. data back end). Although I’ve updated their Active Directory (AD) descriptions, and created two, specifically named AD groups for them, I wanted an even quicker way to remind myself whose who. With that in mind, I updated my profile with a custom variable that is an array, of arrays.

In this Quick Learn, we’ll work with an example that actually uses three groups of roles — our DCs, our web servers, and our SQL servers. As you’ll soon see, our servers are named after Santa Claus’ reindeer. These names have nothing to do with the role of these servers, and since their names are all closely related, it’s difficult to remember who does what.

This first example, below, demonstrates how we create a new variable, or modify an already existing variable. When we echo the contents of our variable, we get all the computer names, regardless of what array they are in, within the base array. The term ‘base array’ is probably not something you’ll hear or read about outside this post. It’s being used here to help distinguish the array that holds all the other arrays — the container array.

PS C:\> Set-Variable -Name Computers -Value @(('dasher','vixen','cupid'),('comet','dancer','donner'),('blitzen','rudolph','prancer'))
PS C:\> $Computers
dasher
vixen
cupid
comet
dancer
donner
blitzen
rudolph
prancer

We can use an index to return one of the arrays within the base array. In the examples below, you can see how each can be accessed. This is probably a good time to review indexes: The first item in an array is index zero, the second item is index one, the third item is index two, and so on.

PS C:\> $Computers[0]
dasher
vixen
cupid
PS C:\> $Computers[1]
comet
dancer
donner
PS C:\> $Computers[2]
blitzen
rudolph
prancer

In the following example, we can use two indexes to access a specific server. The first index represents which array (within the base array) I want to return, like it did above, and the second index indicates which server I want to return.

PS C:\> $Computers[0][2]
cupid
PS C:\> $Computers[1][0]
comet
PS C:\> $Computers[2][1]
rudolph

The difficult part is going to be able to remember which index is for the DCs, the web servers, or the SQL servers. In that case, I’ll create three more variables to use in place of those index integers.

PS C:\> Set-Variable -Name DCs -Value 0
PS C:\> Set-Variable -Name Web -Value 1
PS C:\> Set-Variable -Name SQL -Value 2
PS C:\> $DCs,$Web,$SQL
0
1
2

With the combination of my $Computers variable and the three, role-specific variables, I am able to easily return the set of servers I want.

PS C:\> $Computers[$DCs]
dasher
vixen
cupid
PS C:\> $Computers[$Web]
comet
dancer
donner
PS C:\> $Computers[$SQL]
blitzen
rudolph
prancer

Now that we have this all figured out, I can use them in different commands. Here’s a couple examples:

PS C:\> $Computers[$SQL] | ForEach-Object {Test-Connection $_ -Count 1}

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms)
------        -----------     -----------      -----------                              -----    --------
TOMMYMS PC... blitzen         10.10.10.80                                               32       1
TOMMYMS PC... rudolph         10.10.10.81                                               32       1
TOMMYMS PC... prancer         10.10.10.82                                               32       1

PS C:\> Get-Service -ComputerName ($Computers[$DCs]) -Name *bit* | Select-Object MachineName,Name,Status | Format-Table -AutoSize

MachineName Name  Status
----------- ----  ------
dasher      BITS Stopped
vixen       BITS Running
cupid       BITS Stopped

The unfortunate thing about hard coding computer names in our profile, is that we’ll run into problems when new servers are added and old ones are decommissioned. Therefore, we’re going to use AD groups — something I mentioned earlier — to populate our array variable. We’ll pull our DCs from the Domain Controllers, and our web servers and SQL servers from two fictions AD groups: WebServers and SQLBoxes. Here’s the command we’ll add to our profile to ensure we always have the correct server names. While this can all be on a single line command I’ve added line breaks to give it an easier-to-read appearance.

Set-Variable -Name Computers -Value @(
    ((Get-ADDomainController -Filter *).Name),
    ((Get-ADGroupMember -Identity WebServers).Name),
    ((Get-ADGroupMember -Identity SQLBoxes).Name)
)

And, that’s it. If for some reason you’re using PowerShell 2.0 or lower (and I really hope you’re not), you’ll need to include Import-Module -Name ActiveDirectory in your profile. As well — and it should go without saying — you’ll need to be working from a computer that actually has the ActiveDirectory module installed. Although I’m using PowerShell 4.0, I still include Import-Module -Name ActiveDirectory in my profile, so I don’t have to wait for it to auto load, when I run my first AD cmdlet.

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