Monthly Archives: October 2016

PSMonday #27: October 31, 2016

Topic: Introduction to the Language Constructs

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.

I’ve long had this feeling that people that learn and use PowerShell don’t really ever get  a fair opportunity, to learn the language constructs. Instead, they just learn them as necessary. In an effort to correct this, I believe we should spend some time in the coming weeks, covering each of them.

Well then, what’s a language construct, right? Well, it’s a control structure, of course. Okay, well then what’s that?

Within a language — PowerShell in our instance — we have to have a way to handle conditional situations, in order to take appropriate action(s). Language constructs are the If statement and its variations, it’s the switch statement, it’s the foreach loop and ForEach-Object, the for, the Do variations, and the While loop, too.

In the coming weeks, we’ll spend some time with each of the constructs, so that you’ve seen and used them all, or simply reviewed them, if you’ve used them before. Knowing which to use when, is a vital skill, and best left to second nature once you’ve had experience with them all. I’ll be sure to include some of the times you might choose one over the other, when you can do the same thing with more than just one of the constructs. We’ll start next Monday with If, If-Else, and If-ElseIf.

Resolve TinyURL Using PowerShell

I received a sketchy email today. As I briefly scanned it, I noticed that the email included a TinyURL, and I thought: It would be nice if Outlook could resolve that URL, so I had a better idea where it resolved (without the need to use the URL). That took me out to find such a service. Not for Outlook, so much, but you know, a service that could complete this URL resolution. After I had tested that GetLinkInfo.com gave me what I wanted, I chose to use it’s URL inside a PowerShell function, and so here we are.

I’m not spending much time on this post, but the following function will open the website in your browser, so you can see the URL resolution information. If you include the OpenSite parameter, the function will even open a browser window to the resolved site itself. You might use that one with caution. At current, this function will require you leave PowerShell to see the function’s results, since it was designed to open a web browser window, or windows, depending on how you use it. Perhaps in time I’ll come back around and change that one day.

Function Get-TinyUrlLinkInfo {
<#
.SYNOPSIS
    This function relies on GetLinkInfo.com to determine the redirection of a TinyUrl URL without the need to visit the URL.

.DESCRIPTION
    This function relies on GetLinkInfo.com to determine the redirection of a TinyUrl URL without the need to visit the URL. If GetLinkInfo.com changes how they form their URLs, then this function may no work without some code edits.

.PARAMETER Url
    This parameter name is mandatory and requires a valid URL, such as http://tinyurl.com/ol499jx.com, be provided as the parameter value.

.EXAMPLE
    PS > Get-TinyUrlLinkInfo -Url 'http://tinyurl.com/ol499jx'.
    This example will open a web browser to GetLinkInfo.com and indicate that the TinyUrl resolves to the PowerShell Gallery.

.EXAMPLE
    PS > Get-TinyUrlLinkInfo -Url 'http://tinyurl.com/ol499jx' -OpenSite
    This example will open a web browser to GetLinkInfo.com and indicate that the TinyUrl resolves to the PowerShell Gallery. It will also open the resolved link in a browser. It's not recommend to include this parameter until after the redirected site is considered safe and trusted. Use this parameter with caution.

.NOTES
    Name: Get-TinyUrlLinkInfo
    Author: Tommy Maynard
    Comments: -
    LASTEDIT: 10/31/2016
#>
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)]
        [string]$Url,

        [switch]$OpenSite
    )

    Begin {
    } # End Begin.

    Process {
        # Check link against GetLinkInfo.com.
        [void][Reflection.Assembly]::LoadWithPartialName("System.Web")
        $ConvertedUrl = [System.Web.HttpUtility]::UrlEncode($Url)
        Start-Process -FilePath "http://www.getlinkinfo.com/info?link=$ConvertedUrl&x=81&y=8"

        # Open resolved URL.
        If ($OpenSite) {
            Start-Process -FilePath $Url
        }
    } # End Process.

    End {
    } # End End.
} # End Function: Get-TinyUrlLinkInfo.

Use the Date and Time in File Names

I have functions here and there, that will at times, create files to store generated information. Part of this process is naming the file. For me, I’ll often add the date and time to my file’s name, in order to know it’s creation time, at a glance.

So what does this mean? It means that I’ll often have to jump over to my ConsoleHost, or an old function, I suppose, to be certain I’m using the same date time format. Well, that may end today, right after this post is published. Now, I’ll have another place to look — my own website — to ensure my consistency when it comes to including the same naming.

You can’t use the standard output of Get-Date in a file name, and you probably wouldn’t want to anyway. This is due to the colons included in the time; they’re invalid characters for a file name.

PS > Get-Date

Friday, October 28, 2016 9:21:28 PM

But when we put the Get-Date output in a file name, it changes the output. We loose the day of the week and month as words, and instead get a date with forward slashes, such as 10/28/2016. This conversion happens when we put the cmdlet inside a string. Take a look.

PS > New-Item -Path "$(Get-Date).txt" -ItemType File
New-Item : Cannot find drive. A drive with the name '10/28/2016 09' does not exist...
PS > "$(Get-Date).txt"
10/28/2016 09:27:04.txt

The error makes sense though, as it’s parsing 10/28/2016 as a path. Not really the point here, but good to know. Either way, those slashes and colons aren’t going in a file name. It’s not permitted.

I’ve had a consistent file naming convention that includes the date and time for awhile now. What I really like about my date format is that files are automatically sorted by year, then month, then day, and then the time.

PS > Get-Date -Format 'DyyyyMMddThhmmsstt'
D20161028T093059PM

PS > New-Item -Path "Get-Date -Format 'DyyyyMMddThhmmsstt'" -ItemType File

    Directory: C:\Users\tommymaynard

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       10/28/2016   9:32 PM              0 Get-Date -Format 'DyyyyMMddThhmmsstt'

Oops, notice the problem in that second example above? I need to ensure the command inside my string is being treated as a command, and not just standard text. In the previous example, it used my actual command, as the file name. Let’s try that again.

PS > New-Item -Path "$(Get-Date -Format 'DyyyyMMddThhmmsstt').txt" -ItemType File

    Directory: C:\Users\tommymaynard

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       10/28/2016   9:34 PM              0 D20161028T093445PM.txt

In this final example, we included some text around the date, so that I can better distinguish the reason for the file, but still have the date and time included in the name. We also used the subexpression operator —  $() — to make sure my command was treated as such. Oh, did you notice the capital D and T? I used these as separators to help better display the (D)ate and (T)ime. It makes the files name easier for me to visually parse.

PS > New-Item -Path "User_Disable_Log($(Get-Date -Format 'DyyyyMMddThhmmsstt')).txt" -ItemType File

    Directory: C:\Users\tommymaynard


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       10/28/2016   9:37 PM              0 User_Disable_Log(D20161028T095316PM).txt

That’s all for now! Enjoy the weekend.

The Unzip Time Difference

As part of an upcoming deployment, I’ve been getting intimate with AWS OpsWorks and Chef. What I mean by Chef is, using the PowerShell resource in Chef. I was recently looking for a way to save some time on a deployment, when I considered removing the unzipping of files downloaded from S3. I wanted to know if there would be a time savings in getting the files to the EC2 Instance in their decompressed format.

This brought me over to my console to compare the newer Expand-Archive cmdlet and .NET. I’ve always considered that dropping down to .NET is a time savings.

In my Chef recipe I’m using .NET for decompression, as I’m deploying to Windows Server 2012 R2 and it includes PowerShell 4.0 by default. The Compress-Archive and Expand-Archive cmdlets were introduced in PowerShell 5.0. This isn’t to say I couldn’t get PowerShell 5.0 in place, but I needed to know if it would even be necessary.

I had a little testing to do. The below command measured the time it took to expand a 133MB zip file using .NET.

Measure-Command -Expression {
    Add-Type -AssemblyName System.IO.Compression.FileSystem
    [System.IO.Compression.ZipFile]::ExtractToDirectory('C:\Users\tommymaynard\Desktop\HCM-920-UPD-018-WIN_1of10.zip','C:\Users\tommymaynard\Desktop\unzip\')
}

When the command was run five separate times, it resulted in following times: 9 seconds 393 milliseconds, 9 seconds 117 milliseconds, 9 seconds 455 milliseconds, 8 seconds 489 milliseconds, and 10 seconds 338 milliseconds. I wasn’t loosing any time by unzipping this file.

The below command does the same thing as the one above; however, it uses the Expand-Archive cmdlet introduced in PowerShell 5.0.

Measure-Command -Expression {
    Expand-Archive -Path 'C:\Users\tommymaynard\Desktop\HCM-920-UPD-018-WIN_1of10.zip' -OutputPath 'C:\Users\tommymaynard\Desktop\unzip\'
}

I executed the above command five times, too. The results were 2 minutes 11 seconds, 2 minutes 9 seconds, 2 minutes 10 seconds, 2 minutes 13 seconds, and 2 minutes 11 seconds.

This is a huge difference in time. Now, I do want to mention that I tested this on Windows 8.1 with PowerShell 5.1 (it’s in preview). The results may be better on different versions of Windows and with different versions of PowerShell. Let me know if you see different results with different configurations, and maybe I’ll do the same. The point is this, however: If you have a reason to speed up your project, you might consider .NET over a PowerShell cmdlet, or function. It seems I’m glad I did. Be sure you test different ways, to do the same thing.

PSMonday #26: October 24, 2016

Topic: PowerShell’s Importance

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.

Today is the 26th PowerShell Monday. That means I’ve been writing these for a full half year.

I want to use this morning to point some things out. If you take the time to study each of these emails, then you’re going to be better at your job, where PowerShell can be utilized, in just a year’s time. Take the time to read these whether you already know the content, or not. Now, in conjunction, it’s important to practice what you’re reading, too. Do things in the GUI and then consider how you might complete the same task at the ConsoleHost. Ask questions if you have them, as I’m always willing to help.

I learned early on that PowerShell is going to be a requirement for Windows systems administration. Microsoft keeps proving this, as do other companies that are using it in conjunction with their own products. The inventor of PowerShell is now a Microsoft Technical Fellow — that’s the highest technical title one can receive from Microsoft. He’s the lead architect for the Enterprise Cloud Group and the Microsoft Azure Stack. He presides over Windows Server and the System Center products. Don’t think for a moment that PowerShell won’t continue to play a part at Microsoft. You’re going to need this skill. Keep in mind that we’re not going to need a bunch of click-next admins, as they’re called, in the coming years.

After writing a PSMonday each week for a half of a year, I plan to place the first 26 weeks’ worth of content into a single PDF and distribute that in the coming weeks. If you haven’t read all of them, then this might be a nice way to do that.

On a final note, PowerShell was recently introduced on Linux and Mac. My first thought was, great, soon Windows administrators can support Linux, too. It was after a recent trip to Phoenix for a PowerShell Saturday event, however, where Jason Helmick — a PowerShell MVP — made an interesting point: Linux administrators are going to be able to support Windows, too. It’s time to learn PowerShell, and maybe more about both operating systems. In fact, Jason told a room full of Windows administrators, the same thing.

Compare AWSPowerShell Versions II

Series links: Part I, Part II, Part III (Coming)

I wrote a post a day or two ago that indicated how to compare your currently installed AWSPowerShell module with the offering on the PowerShell Gallery (see Part I above). Well, as I suspected, I’m back with an update.

Before we get there, however, I want to mention that Steve Roberts, at AWS, got in touch with me via Twitter about the post. I suspect we’ll be seeing some updates to Get-AWSPowerShellVersion. What’s interesting, is that I found the ListServiceVersionInfo parameter after my post. It seems that the cmdlet does create objects for some of the results it can return, just not everything. As always, I’m looking forward to Steve’s ideas and implementation.

Today, I’m going to share a quickly written advanced function. This will do the comparison for you and return the results in a custom object. Don’t be surprised if I make some more additions and/or changes to the function and post that as well. It really should have an option to download and install the new module if you want it, right?

Function Compare-AWSPowerShellVersion {
<#
.SYNOPSIS
    This advanced function compares the currently installed version of the AWSPowerShell module and the version on the PowerShell Gallery (http://powershellgallery.com).

.DESCRIPTION
    This advanced function compares the currently installed version of the AWSPowerShell module and the version on the PowerShell Gallery (http://powershellgallery.com).

.EXAMPLE
    PS > Compare-AWSPowerShellVersion
    This example compares the currently installed version of the AWSPowerShell module and the version on the PowerShell Gallery.

.NOTES 
    NAME: Compare-AWSPowerShellVersion
    AUTHOR: Tommy Maynard
    COMMENTS: --
    LASTEDIT: 10/19/2016
    VERSION 1.1:
        - Edited notes.
        - Changed Switch to -regex and made the first option an OR for both side indicators.
    VERSION 1.2:
        - Modified results to use a custom object.
    VERSION 1.3:
        - Removed Switch statement: added version determination logic inside custom object creation.
        - Only returning the highest version number from currently installed if more than one version. This is a leftover due to AWS Toolkit install vs. PowerShell Gallery install.
#>
    [CmdletBinding()]
    Param (
    )

    Begin {
        # Set continuation variable for Process block.
        $Continue = $true

        'PowerShellGet','AWSPowerShell' | ForEach-Object {
            Write-Verbose -Message "Determining if the $_ module is available."
            If (-Not(Get-Module -Name $_ -ListAvailable)) {
                Write-Warning -Message "Unable to locate the required $_ module."
                $Continue = $false
            }
        } # End Foreach.
    } # End Begin.

    Process {
        If ($Continue) {
            Write-Verbose -Message 'Collecting the current and newest AWSPowerShell module versions.'
            $CurrentAWSPSModule = ((Get-Module -Name AWSPowerShell -ListAvailable).Version |
                Sort-Object -Descending | Select-Object -First 1).ToString()
            $NewestAWSPSModule = (Find-Module -Name AWSPowerShell).Version.ToString()

            Write-Verbose -Message 'Comparing the AWSPowerShell version and creating custom results object.'
            [PSCustomObject]@{
                Match = If ($CurrentAWSPSModule -eq $NewestAWSPSModule) {$true} Else {$false}
                Current = $CurrentAWSPSModule
                Newest = $NewestAWSPSModule
            }
        } # End If.
    } # End Process.

    End {
    } # End End.
} # End Function: Compare-AWSPowerShellVersion.

Update: After updating to the newest version, I returned a System.Object[] error for my current version, due to having multiple versions and using the ToString method. I’ve modified the code above to only select the first (and highest) module version from those on my system. I think it’s important to point out that I’ve always downloaded and installed using the .msi until this version, and that when I used Install-Module, I included the Scope parameter name with the CurrentUser parameter value. I suspect this is where the problem is originating. Well, this and the fact I haven’t uninstalled the .msi version from Programs and Features.

I shouldn’t have to wait too long to be on an old build to test some more! It seems as though AWS does at least one, daily build. Here’s the full command as I ran it to install the newest version: Find-Module -Name AWSPowerShell | Install-Module -Scope CurrentUser.

Here’s the usage and results since updating to 3.3.11.0.

Compare-AWSPowerShellVersion

Match Current  Newest  
----- -------  ------  
 True 3.3.11.0 3.3.11.0

Update: As suspected, there’s a new build this evening, and it appears the comparison function is still working, as it’s correctly indicated there isn’t a match between what’s installed and what’s available to install.

Compare-AWSPowerShellVersion

Match Current  Newest
----- -------  ------
False 3.3.11.0 3.3.12.0

I updated to the newest version of the module and ran it again. It’s looking good.

Compare-AWSPowerShellVersion

Match Current  Newest
----- -------  ------
 True 3.3.12.0 3.3.12.0

Compare AWSPowerShell Versions

Series links: Part I, Part II, Part III (Coming)

Well, I wrote enough example code inside my PowerShell ConsoleHost recently, to write another post. That’s typically how these work. Find something great… write. Find something I hate… write. Most of all, just write. Put it on Twitter and help people learn—someone did it for me once.

Today’s goal was to compare my currently installed version of the AWSPowerShell module with the newest version of the AWSPowerShell module. We’ll do this a bit backward, and start with obtaining the newest version of the AWSPowerShell Module first. Because AWS has elected to put their module on the PowerShell Gallery—thanks, guys—we don’t have to parse the AWS PowerShell home page. I’m not sure if it’s even there, but luckily for us, it doesn’t need to be, and so I don’t need to try.

Find-Module -Name AWSPowerShell

Version    Name                                Repository           Description
-------    ----                                ----------           -----------
3.3.9.0    AWSPowerShell                       PSGallery            The AWS Tools for Windows PowerShell lets develo...

(Find-Module -Name AWSPowerShell).Version

Major  Minor  Build  Revision
-----  -----  -----  --------
3      3      9      0

(Find-Module -Name AWSPowerShell).Version.ToString()
3.3.9.0

Now that we can obtain the version number of the newest release, let’s work on getting the currently installed version number. My first thought was to use Get-AWSPowerShellVersion. It was a mess, but here’s what I did. This cmdlet does not return an object, unfortunately (and should be replaced and/or corrected).

Seriously, we expect that cmdlets and functions will return a usable object or objects. If we really need additional information stuffed in the results, let’s only include it with the Verbose parameter. Maybe just drop all that text in a file and have Verbose indicate the file to open. Maybe make a secondary cmdlet. Anything really, that doesn’t require that we parse text… which is exactly what I did (at first).

((Get-AWSPowerShellVersion).Split('`n')[2])[1..7] -join ''
3.3.0.0
[version](((Get-AWSPowerShellVersion).Split('`n')[2])[1..7] -join '')

Major  Minor  Build  Revision
-----  -----  -----  --------
3      3      0      0

The problem with this approach is that it’s much too exact. It’s grabbing certain characters. What happens when the version is longer than seven characters? We would’ve lost our final zero, if I was still on a previous version, such as 3.1.66.0, 3.1.71.0, or 3.1.73.0. Not good enough.

I knew the AWSPowerShell module put something somewhere; every module does. I browsed over to C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell to take a look around. Maybe there was something there that would be more reliable. I quickly spotted the module manifest file: AWSPowerShell.psd1. I opened it up in a text editor, and as suspected, there was the version… right inside that beautiful hash table. I closed up the file and used Test-ModuleManifest inside my ConsoleHost.

$Path = 'C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1'
Test-ModuleManifest -Path $Path
ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Binary     3.3.0.0    AWSPowerShell                       {Clear-AWSHistory, Set-AWSHistoryConfiguration, Initialize...
(Test-ModuleManifest -Path $Path).Version

Major  Minor  Build  Revision
-----  -----  -----  --------
3      3      0      0

(Test-ModuleManifest -Path $Path).Version.ToString()
3.3.0.0

That’s way more reliable. I’d much rather blame AWS if it doesn’t return the correct version, than my parsing against the results of Get-AWSPowerShellVersion. I mean, seriously.

If you’ve been following my writings, then it’ll come as no surprise that I started with the hardest way and overlooked the obvious. I could’ve simply just used Get-Module to return the version; it’s getting its information from the .psd1 file. As obnoxious as this is, it's keeping me sharp. I get to repeatedly practice what I know and give my mind time to sort out different resolutions to the same problem. Here's how I returned the version of the currently installed AWSPowerShell module.

Get-Module -Name AWSPowerShell
ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Binary     3.3.0.0    AWSPowerShell                       {Add-AASScalableTarget, Add-ACMCertificateTag, Add-ASAAtta...
(Get-Module -Name AWSPowerShell -ListAvailable).Version

Major  Minor  Build  Revision
-----  -----  -----  --------
3      3      0      0

(Get-Module -Name AWSPowerShell -ListAvailable).Version.ToString()
3.3.0.0

Now I can return both the currently installed version of the AWSPowerShell module and the newest version of the AWSPowerShell module from the PowerShell Gallery. Before we compare them, notice that in the above examples that I did and didn’t use the ListAvailable parameter. If you don’t use it, you better be absolutely certain the module has already been imported.

So, let’s get these version numbers into a couple of variables and compare them.

$CurrentAWSPSModule = (Get-Module -Name AWSPowerShell -ListAvailable).Version.ToString()
$CurrentAWSPSModule
3.3.0.0
$NewestAWSPSModule = (Find-Module -Name AWSPowerShell).Version.ToString()
$NewestAWSPSModule
3.3.9.0
Compare-Object -ReferenceObject $CurrentAWSPSModule -DifferenceObject $NewestAWSPSModule -IncludeEqual

InputObject SideIndicator
----------- -------------
3.3.9.0     =>
3.3.0.0     <=

As we can tell, there is a difference between my version and the one in the PowerShell Gallery. I should probably download the newest version. Watch for a follow-up to this article, as I may go ahead and write a second part, as I have some other ideas.

PSMonday #25: October 17, 2016

Topic: $PSDefaultParameterValues II

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.

To recap last week, the $PSDefaultParameterValues preference variable stores default parameter names and corresponding values for cmdlets and functions. This means we can use cmdlets and functions with modified parameters, without the need to type in the names and values each time.

Last week we used the Add and Remove methods. This week, we’ll use standard hash table syntax, since that’s all this variable holds. Hash tables were first introduced back on May 30, 2016 when we first discussed creating and splatting a parameter hash table. A hash table contains key-value pairs.

Let’s add a new entry to our empty $PSDefaultParameterValues variable.

$PSDefaultParameterValues = @{'Get-Help:ShowWindow'=$true}
$PSDefaultParameterValues

Name                           Value
----                           -----
Get-Help:ShowWindow            True

Just as we did last, when we enter the variable name after it’s populated, it’ll return the results in the standard, hash table output to include the Name and Value properties.

With the ShowWindow parameter name set to a value of True, Get-Help will always show the full help inside a GUI window and not pollute the ConsoleHost or ISE (PowerShell 3.0 and greater only), without the need to actually type the switch parameter -ShowWindow.

If your variable is already holding a value, be sure to use the += assignment operator instead of the = assignment operator, or you’ll overwrite what was already being stored in the variable.

On an entry after the first one, use this:

$PSDefaultParameterValues += @{'Get*:Verbose'=$true}

Not this:

$PSDefaultParameterValues = @{'Get*:Verbose'=$true}

Notice that in the above examples we’ve used a wildcard character. If this is added to your $PSDefaultParameterValues, then all Get-* cmdlets and functions will include the Verbose parameter.

PSMonday #24: October 10, 2016

Topic: $PSDefaultParameterValues

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.

Now that we have some understanding about commands, cmdlets, functions, and parameters, we can start to discuss the $PSDefaultParameterValues preference variable. This variable allows you to specify default parameter values for cmdlet or function parameters.

This is to say, that you can ensure a specific parameter value is always used for a specific parameter name, for a specific cmdlet or function, even when you don’t explicitly include them. Let’s say you use the Get-ADComputer cmdlet and you always want to use the DC01 Domain Controller to perform the lookup. That’s probably not the best idea, but without $PSDefaultParameterValues, you’d have to type the parameter each time.

Get-ADComputer -Identity membersrv05 -Server DC01

If we defined a default parameter value, we could drop the -Server DC01 from the command and it would still be included. There’s a couple different ways to add an entry to $PSDefaultParameterValues. We’ll use the Add method this week.

$PSDefaultParameterValues.Add('Get-ADComputer:Server','DC01')
$PSDefaultParameterValues

Name                           Value
----                           -----
Get-ADComputer:Server          DC01

Again, with this value set, the command below would still be certain to use DC01.

Get-ADComputer -Identity membersrv05

While we’re here, let’s also look at the Remove method. This is how we’d remove an already existing entry in the $PSDefaultParameterValues variable.

$PSDefaultParameterValues.Remove('Get-ADComputer:Server')

All gone, and all done. We’ll discuss this topic some more next Monday.

PSMonday #23: October 3, 2016

 Topic: Commands, Cmdlets, and Functions

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.

Before we jump into the next topic, I think it would be wise to ensure we discuss the differences between commands, cmdlets, and functions. In doing that, we’ll also learn, or clarify, the differences between parameters, parameter names, and parameter values.

As we’ve learned, in a roundabout way, cmdlets and functions have the potential to include parameters. Scripts in fact, can also include parameters. A parameter is made up of a parameter name and a parameter value, or values.

A cmdlet, such as Get-Service, Stop-Process, Get-EC2Instance, and Set-ADUser, is likely written in C#, and is compiled code. A function, which can be written in a simple text editor, isn’t compiled, as the source can be easily read. These include Get-Volume, Get-Verb, New-SmbShare, and many more, including those we might write ourselves using the ISE, or Visual Studio Code. Those products are both better alternatives to using a simple text editor.

Let’s take a look at a command, break down each part, and then call it a day.

Get-EventLog -ComputerName DC01,DC02 -LogName Application -Verbose

Get-EventLog
This is the command. The term command can be used for just the cmdlet or function, or a cmdlet or function that includes parameters. You might also just call it by its CommandType: cmdlet or function. I’m not completely sure if it’s been mentioned before or not, but cmdlet is pronounced command-let.

-ComputerName DC01,DC02
This is a parameter.

-ComputerName
This is the parameter name.

DC01,DC02
These are the parameter values.

-LogName Application
This is also a parameter.

-LogName
This is the parameter name.

Application
This is the parameter value.

-Verbose
Even this, is a parameter.

Before we wrap up, I want to quickly discuss the last parameter mentioned: Verbose. There are parameter names that don’t require any specified parameter value be included. These are called switch parameters. If they’re included, their parameter value — even though you can’t see it — is True ($true), and if they’re not included, their parameter value is False ($false). Therefore, their default value is always $false.

Alright, back with more next time.