Using -match and the $matches variable in PowerShell

iLovePowerShell Logo

iLovePowerShell LogoI’ve been rereading the Windows PowerShell Cookbook and I came across a variable I hadn’t noticed before…

It turns out to be related to the -match comparison operator. -Match performs a regular expression comparison. A simple way of thinking about regular expressions is that they “describe” the patterns of characters. Another way of thinking of regular expressions is “Wildcards on steroids.”

For these examples, I’m going to keep things very simple as far as regular expressions go:

.   <– means “anything”
*  <– means “zero or more of it”
so
.* <– means “zero or more of anything”

<#####################
 -Match and $Matches 
#####################> 

<# Like -eq, -match will evaluate True/False 
   when compared against one object #>
"One" -eq "One"
"One" -match ".*"

<# Also like -eq, -match passes objects that evaluate to 
  TRUE through the pipeline when compared against multiple objects#>
"One","Two","Three" -eq "Two"
"One","Two","Three" -match "T.*"

An interesting thing about using the -match comparison operator is that when matches are evaluated, the result is stored in a unique variable, $matches.

The $matches variable takes a little getting used to.

#1 - $Matches doesn't work with -eq
"One", "Two", "Three" -eq "One" | Foreach {$Matches[0]}
<# Surprised? If you've dropped these 
  examples into the ISE, it looks like it works. #>

#2 - $Matches really doesn't work with -eq
"One", "Two", "Three" -eq "Two" | Foreach {$Matches[0]}
<# See? I tricked you! The reason it looked like it worked on #1 was because
   it was still set from the last time -match was used. #>

#3 - $Matches isn't set when evaluating multiple objects 
"One" -match ".*"
"One", "Two", "Three" -match "T.*"
$Matches

#4 - $Matches CAN be used with multiple items, but evaluate each item individually
"One" -match ".*"
"One","Two","Three" | Where-Object {$_ -match "T.*"} | Foreach {$Matches[0]}
$Matches
<#Notice how $matches now equals "Three"? What happened to "Two"? 
  Since I used the pipeline to break the list into three items, 
  the -match comparison in the Where cmdlet does update the 
  $Matches variable. But immediately after evaluating TRUE for "Two", 
  it updates with "Three" and Two returns to the ether. #>

#5 - Don't be fooled by trying to -match on multiples
"One","Two","Three" -match "T.*" | Foreach {$Matches[0]}
<#See? It's tricky.#>

Finally, you’ll just want to notice that I keep switching between $Matches and $Matches[0]. $Matches is a variable that contains a hashtable. The hashtable (a key-pair) has a key and a value. The key is the index and the value is “what was returned as the match.” Since there is only one value in the $Matches variable, you can get to the value of the match by referencing the key-pair by its name.

Alright, so you’ve seen how $Matches works. But why use it?

In the examples that I’ve shown here, you probably aren’t that impressed. I promise I kept it simple so it wouldn’t be too intimidating with the crazy looking regular expressions. Regex can look really nuts.

Let’s use another example that is equally as useless but at least serves as a better example of why we might like $Matches.

#Let's make a little list of words
$words = "The quick brown fox jumped over the lazy dog".Split()

#Now show only words that start with a letter between "a" and "l" and also have an "o" somewhere in the word.
$Words | Where {$_ -match "[A-L,a-l].*o.*"} | Foreach {$Matches[0]}

That really can’t be done with using a -like comparison operator and normal wildcards. Still not sure if you’d have a use case for having the matches of a regular expression displayed? Here’s when you want to use it.

Grab a list of strings. Pipe them into a Where-Object or Select-String to perform a -match against them. If what you want is the whole string when it has the match, then you just use the standard output. But if what you want is only the resulting match, then you can pipe it to Foreach-Object {$matches[0]}

Did this help? Have something to add? Leave a comment below.

Windows PowerShell Cookbook

The Windows PowerShell Cookbook by Lee Holmes is an incredible reference. It’s filled with useful scripts, and they are explained so that you don’t just get a cookie cutter script resource but you learn why the scripts work and how they can be applied to other scripts that you’re working on. If you don’t own this book, you’re missing out. Buy it now!

Looking at Installed Certificates with PowerShell

Look at Certificates

Q. How can I see what certificates are installed on a Windows computer with PowerShell?

A. Using PowerShell to view certificates is easy. PowerShell has a provider that exposes the certificates store which is part of the pki and security modules, which are loaded automatically as long as you’re on version 3 or greater. You do not need to manually load the modules, they auto-load from PowerShell v3 and above.

To view the certificates in the local users personal certificate store I would use the following:

#Change to the location of the personal certificates
Set-Location Cert:\CurrentUser\My

#Change to the location of the local machine certificates
Set-Location Cert:\LocalMachine\My

#Get the installed certificates in that location
Get-ChildItem | Format-Table Subject, FriendlyName, Thumbprint -AutoSize

#Get the installed certificates from a remote machine
$Srv = "SERVER-HOSTNAME"
$Certs = Invoke-Command -Computername $Srv -Scriptblock {Get-ChildItem "Cert:\LocalMachine\My"}

There is also a cmdlet called Get-Certificate, but don’t be fooled – it’s for requesting and installing certificates, not listing the certificates already installed.

H/T: http://windowsitpro.com/powershell/browse-certificate-store-using-powershell

Easiest way to Shuffle an Array with PowerShell

I was going nuts trying to sort an array into a random order. I was hoping for something in PowerShell that would be along the lines of Shuffle() in PHP or Ruby.Shuffle an Array in PowerShell (The Easy Way!)

In fact, after looking at it I was a little surprised at all of the things that an array can’t do in PowerShell.

But that’s ok – it turns out to be really easy and if you’re thinking that you need to learn a differentlanguage to shuffle an array in PowerShell you’re dead wrong.

It’s super easy to randomize the order of an array in PowerShell – you just have to simplify and think about it in a different way.

#Give me a list - any list will do. Here's 26 numbers.
$MyList = 0..25

#Shuffle your array content but keep them in the same array

$MyList = $MyList | Sort-Object {Get-Random}

#Randomize the contents of your array and save them into a new array

$MyShuffledList = $MyList | Sort-Object {Get-Random}

This is so easy it defies belief. Why does it work?

Since the Sort-Object can accept pipeline input, it’s often used to organize the contents of a list based on one property or another. You’ve probably used it for sorting by names, or for sorting files by their size. But a magical thing happens when you tell it to not sort by a specific property but instead pass it a scriptblock.

For each object that is passed into Sort-Object through the pipeline the scriptblock is called. And since Get-Random evaluates to a rather large random number – the objects in the array are sorted based on all of those random integers.

I know this was an eye-opener for me, and I really like doing it this way. Before coming across the sort method I tried going through each item in the array and adding a noteproperty to it.  Which worked since I was using an array of objects anyway but was way clunkier than doing it this way.

Leave any questions or feedback in the comments and do me a favor and hit the like button on my facebook page for me, ok? Thanks!

News about the PowerShell North America Summit 2015

The North American PowerShell Summit 2015 will be taking place on April 20 through 22, 2015, at the Microsoft offices in Charlotte, North Carolina, USA.

The PowerShell North American Summit is put on by PowerShell.org and will be a small “deep-dive”/convention with an attendance limited to approximately 100 attendees.

Registration is beginning on 30 October 2014 and since the reservations are limited they are likely to go very quickly.  Cost of the registration is $800 and it includes membership in the Association for Windows PowerShell Professionals .

More Info:

Create a PSEdit Function to Open a File in a New Tab in PowerShell ISE

Have you used PSEdit to open a file in a new tab in your PowerShell ISE session?

PSEditFunctionShitGotReal

PSEdit is a built-in function that runs only on PowerShell ISE.  It’s simple and easy to use.  Enter in a filename and *poof*, it opens in a new tab of the ISE.  What a great idea! But wait! There’s more! I’m going to share a function that you can use to put PSEdit on your PowerShell console, (not on the ISE), and since you’re not going to be editing in the console, it opens your files in the ISE.

Here’s an example of how PSEdit is used:

#Declare the file you want to edit into a variable (optional)
$FilePath = "C:\Scripts\MyProfile.ps1"

#Run the file
PSEdit $FilePath

This is all because of the function “PSEdit” that leverages the $PSIse system variable. Here’s the code for the function.

param([Parameter(Mandatory=$true)]$filenames)

    foreach ($filename in $filenames)
    {
        dir $filename | where {!$_.PSIsContainer} | %{
            $psISE.CurrentPowerShellTab.Files.Add($_.FullName) > $null
        }
    }

The only problem is that it’s only available in ISE.  Of course, you don’t really have an editor in a PowerShell console session, and I’m almost always in ISE when I’m wanting to edit… But it might be nice to include that function in a PowerShell console.

If you’d like to add a PSEdit function to your console, begin with opening your PowerShell Profile.  You can even do this from PowerShell ISE, but the PowerShell ISE and the PowerShell regular console do have different profiles.

From the PowerShellISE, this will give you the location of your PowerShell ISE profile.

$profile

While this sneaky trick will give you the path to your PowerShell profile.

$Profile.Replace("PowerShellISE","PowerShell")

Most of you could also get that result with Replace(“ISE”,””), but it would fail if your user profile on your computer is in a directory with “ISE” in it.  Maybe your computer account is called “Promise” or something. It could happen.

Next, load up your regular PowerShell profile instead of your ISE profile for editing using the exact same PSEdit command that we covet!

PSEdit $Profile.Replace("PowerShellISE","PowerShell")

Sweet!

Next, drop this function into your profile to create a PSEdit that will accept pipeline input, due some basic error checking. Through luck, I’ve found that using this will not open the same file if it’s already open. I didn’t even have to get fancy, it just already worked.

function PSEdit {
[CmdletBinding()]
param([Parameter(Mandatory=$true,ValueFromPipeline=$true)]$filename
)

Process {
	if (test-path $filename -PathType Leaf) {
        $file = Get-ChildItem $filename
        if ($file.PSProvider.Name -eq "Filesystem") {
            Start-Process PowerShell_ISE -ArgumentList $file
        }
        else {Write-Error "Wrong PSProvider: $($File.PSProvider.Name)" }
    }
    else {write-error "Bad path: $filename"}   
}

<# .SYNOPSIS Opens a file in PowerShell ISE for editing. .DESCRIPTION Accepts one or more file (as paths) and then checks them to make sure the path exists and it's a file. If any of the files are not already open in PowerShell ISE, the file is opened in a new tab. .EXAMPLE PSEdit $Filename Opens the file at $filename in the PowerShell ISE .EXAMPLE Get-ChildItem C:\Scripts\ProjectGenesis\*.ps1 | PSEdit Opens all PS1 files in the Project Genesis folder for editing. .LINK http://www.ilovepowershell.com/ #>
}

I got this idea from Mike Robbins, who wrote a nice post about PSEdit on his blog. http://mikefrobbins.com/2014/05/19/open-scripts-in-a-new-tab-in-the-powershell-ise-using-psedit/

EDIT:  Or, you could have just used the ISE function from the PowerShell console.

Microsoft Virtual Academy on PowerShell 3 with Jeffrey Snover Available

Microsoft Virtual Academy has a course on PowerShell 3 that you just can’t miss. This is part one of a series, so don’t fall behind.  The first course is “Getting Started with PowerShell 3.0 Jump Start” and it’s available now.

Microsoft Virtual Academy Course: Getting Started with PowerShell 3

Getting Started with PowerShell 3.0 is presented by Jason Helmick (@TheJasonHelmick) and Jeffrey Snover (@JSnover), who invented PowerShell.

It’s available now as a free course that you can start watching.

The course includes these modules, and provides almost 6 hours of material:

  1. “Don’t Fear the Shell” (39 minutes)
  2. The Help System (55 minutes)
  3. The pipeline: getting connected & extending the shell (28 minutes)
  4. Objects for the admin (42 minutes)
  5. The pipeline: deeper (43 minutes)
  6. The PowerShell in the shell: Remoting (55 minutes)
  7. Getting prepared for automation (26 minutes)
  8. Automation in scale: Remoting (27 minutes)
  9. Introducing scripting and toolmaking (51 minutes)

I’m going through this training now, and though I have a pretty good handle on PowerShell I can still learn a lot in the little details, and it’s great to hear some of the stories from Jeffrey Snover about how PowerShell came out. Stories like:

  • How the pipeline in PowerShell differs from the pipeline in Unix (in Unix the pipeline only passes text, in PowerShell you pass whole objects, with properties and methods included)
  • How the verb-noun command structure came from VMS.
  • Why commands in PowerShell are called cmdlets (searching for “command” returned millions of results, searching for “cmdlet” returned only thousands, and they were all about PowerShell)
  • Why Unix commands work in PowerShell (it’s all because of their great use of aliases)

If you are so inclined, you can download each of the sessions to browse offline, or you can stream them from MVA.  Microsoft Virtual Academy also has a ton of courses on all kinds of Microsoft products and technologies.  You can also accumulate points and try and beat your friends at achieving some kind of status or something.  I don’t know – I tried that for a while but mostly I just want the content, not the points.

This is definitely share-worthy, so spread the word and help get your friends up to speed on PowerShell 3.

Learn PowerShell 3 in a Month of Lunches

If you’re looking to expand your knowledge of PowerShell and start working it like a pro, you should check out this book from some of the premier PowerShell trainers and gurus.  Written by Don Jones and Jeff Hicks, Learn PowerShell 3 in a Month of Lunches takes you through the basics of PowerShell in a series of one hour training sessions. (These links take you to Amazon to buy the book. If you buy from these links, I’ll get a small commission but it won’t cost you any extra)

Each training session ends with a simple practice session to get you actually putting into practice the lesson of the day and turning it into some PowerShell code.

This is the second version of this book. But you don’t need the first, which was written for earlier versions of PowerShell.

If you’re wondering if you know enough about PowerShell to get started with Learn PowerShell 3 in a Month of Lunchesyou do. This first chapters and lessons start out just right for the person that’s wanting to learn PowerShell and it doesn’t assume that you have any knowledge coming in.

The later chapters guide you through some great techniques and principles that will help you to take your PowerShelling to new heights, both from an interactive shell and your written out scripts.

Don Jones is probably the most experienced PowerShell trainer out there.  He’s a multi-year recipient of the Microsoft MVP in PowerShell, and if you take a pre or post conference training session on PowerShell, it’s probably taught by Don. I’ve taken a training session from him before. I went into it thinking I knew a lot more than I actually did.  By the end of the training a couple of hours later, I had crazy new PowerShell-jitsu moves.

Jeff Hicks is a great PowerShell blogger, author and speaker.  He is also a Microsoft MVP for his work advocating PowerShell. He’s written training material for PowerShell and is an all-around cool guy.

I recommend this book as a great resource for getting up to speed with PowerShell.  We’ve been saying for years how important PowerShell is to system administrators, and if you’re ready to take the plunge this is an excellent way to start on the right foot.

PowerShell 3 Workflow Tutorial Video by Bruce Payette

This video features a PowerShell 3 workflow overview and tutorial from Bruce Payette.  Bruce is the Principal Developer in Windows Manageability for Microsoft.  This means that he is the main developer for PowerShell 3.0 and is one of the highest authorities on Windows management and scripting with PowerShell.

PowerShell 3 WorkFlow Tutorial

If you’ve heard that Power Shell 3 uses workflows, but you haven’t yet had an opportunity to learn about what it is and how to use it, this video is going to be time well spent.

It’s a ton on information packed into a 45 minute session from the PowerShell Deep Dive 2011 in Frankfurt.
Start the video when you’re ready to begin.  And if you just want the highlights then keep reading because I hit the key points for you.

What is Workflow and When Will You Use It?

Workflow is not another way to script, instead it’s orchestration of large, long-running scripts.  As Bruce puts it, workflow is intended for “reliably executing long running tasks.”

Workflows take advantage of state persistence:  everything in a workflow state can be saved to disk. The example given is a long running task finished processing one part of the script, and then human intervention is required. Once the human intervention is completed, the workflow can be resumed. If a system failure occurs on the machine running the workflow, it’s not going to affect the workflow. You can pick up and resume the workflow process on a different machine and it picks up right where it left off.

The main differences you’ll encounter when working with PowerShell workflows are:
• In a workflow, individual activities are isolated.  This is different than a typical power shell session or script where all of the activities take place more or less sequentially and all share the same environment and state.
Workflows include persistence, so that they are more robust.  This allows workflows to stop, pause, restart and recover.  Typical PowerShell scripting doesn’t include these state persistent features.
• Data flows through very specific channels when running through a workflow.  Everything is very well defined with data that comes in and data that goes out of each part of the workflow.  By contrast, scripts are allowed more flexibility with moving data from one part to another, and there can be “implicit” coupling of data.
Workflows are precise in how the language is typed.  A workflow is strongly typed, early bound, and is a compiled language.  Scripts can be more loose and forgiving with how the language is typed.
In short – workflows are planned, and scripts are ad hoc.

Overview of the PowerShell Workflow Architecture

There is a PowerShell Workflow Service (not a real windows service, unless you create a service to run the workflow).  The PowerShell workflow service is run on a computer which is actually running the workflow.  The client is the computer that is initiating the workflow.  The client and workflow service computers are usually the same computer, but could technically be two different computers.  Finally, the management nodes are the individual management items being processed by the workflow.  This could be as many computers as is required, and connections can be made through filesystems, WMI, and many other methods.
Example of a workflow code
Bruce showed this example of workflow code that checks for a required version of a system BIOS that will run on multiple machines.  It uses very little new programming syntax changes.  I typed in the code so that you can view it and copy paste it for your own education.

workflow Test-MachineBios
{
param ([parameter(mandatory=$true)][string]$RequiredBiosVersion )
parallel {
$workflow:bios = Get-CimInstance -ClassName Win32_Bios |
Foreach -MemberName Version

sequence {
$os = Get-CimInstance -Classname Win32_ComputerSystem
if ($os.Manufacturer -match “dell”) | { $workflow:RebootNeeded = $false }
}
}

inlinescript {

$bstr = “$bios”
$len = $bstr.Length + 15
“*” * $len + “`nBIOS version is $bstr`n” + “*” * $len | Write-Output
}

if ($bios -notmatch $RequiredBiosVersion) {
“Update Required”
if ($workflow:rebootNeeded -eq $true) {
“Reboot needed”
Restart-Computer -wait -for PowerShell -force
}
else {
“Reboot not needed”
}
}
else {
“BIOS is up to date”
}

}

Notes about the code:

  • If you want to create a workflow you start it with the workflow keyword. Once used, it enables some other new keywords.
    In a workflow, you can use parallel keyword to define tasks that run in isolation but at the same time. That is to say, each statement inside the parallel block runs on its own and at the same time on each system.
  • If you want to be sure to run one command first, and then another command after, you will want to use the sequence keyword. So even if you’re in a parallel block, the sequence block identifies a group of command that will be run one first, then the next; and that whole group of items being run in sequence will be processed in parallel with any other statements in the parallel group.
  • $workflow:bios shows a subset of the PowerShell language that only works in workflows. The data language makes it so you can only perform operations that make sense when working with data. Bruce puts it like this: “It prevents you from doing things that would prevent workflows from having the ability to persist.”
  • Since the things you can do in the data language is more restricted, you can use the inlinescript keyword to set aside a scriptblock that has the full PowerShell language available to it. Everything in the inlinescript block processes as one line in the workflow.

Other notes about this workflow, and designing and running workflows:

    If you restart your own computer, the workflow is saved by creating a checkpoint. After the computer restarts, you can resume the workflow.

  • As each step of the workflow is processed, progress bars are displayed by default throughout.
  • Commands now have a property called “capability” which identifies what type of command it is. Workflows are identified with the capability “workflow”.
  • Workflow commands are actually acting as proxies to the Microsoft Workflow version 4 engine.
  • The PowerShell text you enter into the PowerShell script is converted into XAML to be consumed by the the workflow engine.
  • It’s possible to edit the XAML directly, but not necessary and not recommended.
  • If you want to edit the XAML, using the workflow editor from Visual Studio is a good option.
  • You can do some basic debugging of workflows with Windows Tracing and Event logs.
  • Take advantage of tracing by loading the PSDiagnostics module, then running the Enable-PSWSManCombinedTrace command.
  • The Register-PSSessionConfiguration cmdlet can be used to help enable “second hop” connections by configuring remote endpoints to always be run as a specific user.

I can say that after watching this PowerShell tutorial I’m ready to start playing with workflows in PowerShell version 3.  I immediately started downloading and installing Visual Studio 2012 so I can get my hands on a decent workflow editor.
Do you know somebody that wants to learn one of the hottest new techniques for working with PowerShell?  Be sure to tell the people that need to know that you’ve got a really fast way to get them familiar with PowerShell workflows.

How to Find Enum Values in PowerShell

WindowsPowerShellCookbook
Windows PowerShell Cookbook Volume 3 by Lee Holmes

 

There are a couple of very easy ways to get a find enum values in PowerShell.  Enums are often used when choosing an option as a parameter in a PowerShell command.  This article shows you exactly how to get those values for any enumerated list type (called “enum”).

The easiest way to find enum values in PowerShell is to use Get-Help, but that doesn’t always work

The easiest way is by using the Get-Help command on a PowerShell cmdlet or function.  All of the built in PowerShell cmdlets have great help that is painstakingly created and maintained. Some of the functions that are included with PowerShell modules or a PSSnapin will also have documented parameters.

So the number one most simple way to check out the possible accepted values for an enum is to check with the get-help documentation.

It looks like this:


Get-Help Set-ExecutionPolicy –full

usingGetHelp_thumb

In the results, you can see in the values displayed inline with the parameter that accepts the type

 

Start by using Get-Help to try finding enum values. It is very fast, and the enum values are often in the help documentation.

That’s pretty good.  Unfortunately, the help for a function that was developed in house does not usually include such great documentation.

The best way to find enum values with PowerShell is to use a static method.

I’ll continue to use the Set-ExecutionPolicy cmdlet as my example, but these will work for any class that is an enum.

There are two approaches to this, and each one does the same thing.

First, you can use a static method from the base enum class, [system.enum].  Secondly, you can use a static method of the class (the enum) that you’re trying to identify the values for.

And before you can do either one, you need to identify the type that the enum represents.

How to find out the type of an enum

Consider the “Set-ExecutionPolicy” cmdlet, which uses a parameter “ExecutionPolicyScope” to specify at what level you want to apply the execution policy that you’re setting.

So if you want to know what options can go in

Set-ExecutionPolicy –ExecutionPolicy RemoteSigned –Scope  ???

You can find out what class the “Scope” parameter accepts by using Get-Help to interrogate the parameter.

Get-Help Set-ExecutionPolicy –Parameter Scope

Which returns just the information about the “Scope” parameter.

usingGetHelp-FindParameterType_thumb

 

This shows that what you put into the Scope parameter is an object of type ExecutionPolicyScope.

That’s half the battle.  Actually, it’s way more than half the battle:  you’re almost done.

Finding out the names in an enumerated list (enum) when you know the type.

So now that we know the type, we need to be able to reference it.

To do this, I’m going to use a static method from the Enumeration class, SYSTEM.ENUM, called GetNames().  Use it like this:

[Enum]::GetNames(“Microsoft.PowerShell.ExecutionPolicyScope”)

ListEnum_thumb

And you will get all of the possible options for your enumerated list.  It might look like I took some liberties with the class name, because when it was listed in the Get-Help –Parameter output from above it was listed as “ExecutionPolicyScope” but when I entered it into the GetNames static method I used “Microsoft.PowerShell.ExecutionPolicy”.  When I first tried it with just “ExecutionPolicyScope” it returned an error.  So I made a guess that it was part of the standard PowerShell namespace, and it turned out to be correct.

By the way, the default PowerShell namespace is Microsoft.PowerShell and many PowerShell objects that are listed as only a class name actually belong to it, so it can be worth a try.

Many other enums listed as types in parameters for a command will list out the full namespace with the object.

Ok – so you’ve read the article.  I hope that you’ve gotten something great out of it.  I love helping people get more out of PowerShell, because I know PowerShell can help people do more work, faster, and with fewer mistakes than ever.

I’m committed to sharing great PowerShell advice and tips, so how’s about subscribing or spreading the word by sharing this article with a fellow that would benefit from it.