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!

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!

How To Update Configuration Manager Site Code With PowerShell

Did you move domains recently or reconfigure your System Center Configuration Manager (SCCM)?  Maybe you’ve found your Config Manager site code broken.  Here’s a one-liner that shows you How to update a sitecode for SCCM with PowerShell.

This assumes that you’ve got SCCM running, and installed on the client.  I found this problem hanging around on our machines after a migration from an old domain into the new domain.  Each domain had Microsoft Configuration Manager installed on it, and each domain had a different site code.  A domain wide group policy was used to install the client in each domain, but I had problems with the site code for the old domain still on the Configuration Manager client after domain migration was complete.

Luckily, we can use PowerShell to change the site code, and we can even use PowerShell to discover published site codes. 

Advertisement

 

First we need to grab hold of our SMS client.  In PowerShell, it couldn’t be easier:

$sms = new-object –comobject “Microsoft.SMS.Client”

We can use the methods of the Microsoft.SMS.Client class by using PowerShell to directly work with the SMS client object:

$sms.SetAssignedSite(“ABC”)

or find out what the site code is currently set to:

$sms.GetAssignedSite()       # This returns a string value

Since the GetAssignedSite() method returns a string, it can be used in scripts to verify the site code is correct.  I use this on scripts (pushed via Group Policy on the domain roots) to verify the site code is correct, and correct the site code automatically if it is wrong.

Since I know the site code, let’s say “ABC” is the new domain and “XYZ” is the old domain, I would use this:

$sms = new-object –comobject “Microsoft.SMS.Client”

if ($sms.GetAssignedSite() –ne “ABC”) { $sms.SetAssignedSite(“ABC”) }

Finally, I’ll call attention to another method of the SMS Client object:  AutoDiscoverSite()

AutoDiscoverSite returns a site code for the Active Directory Domain (if published)

$sms = new-object –comobject “Microsoft.SMS.Client”

if ($sms.GetAssignedSite() –ne $sms.AutoDiscoverSite() ) { $sms.SetAssignedSite($sms.AutoDiscoverSite()) }

Now just a little clean up here…

Write-host “Thanks for reading.  Subscribe! Or, connect via Twitter  or Facebook.  Ask questions to twitter using #poshhelp or #powershell to get q’s answered fast!”

$null = $thisBlogPost

Frequently Used PowerShell Oneliner(s) – Kill All Internet Explorer Windows

Because of my self-appointed title as an Ultimate Microsoft Fanman, it really pains me to disclose this One-Liner.  That’s because saying it is a commonly used suggests that Internet Explorer locks up frequently.

Ouch!  That hurt to type!

Truthfully, it could have been said of Firefox if I used it as much as I use IE.  And to be fair, Internet Explorer might not lock up as much if I didn’t abuse it by keeping 25 windows open all the time, and continue to upgrade to the most recent beta version I can get my PowerShell-scripting hands on.

So when I get stuck, I dropped this One-Liner out there.  It works great, even if the IE window is not responding to close requests through the taskbar, or through the close button on the application itself.  This kills every Internet Explorer window

get-process iexplore | stop-process

You can exercise more surgical precision by going for only the top processor intensive process (or processes if you change “–First 1” to “-First 2”)

get-process iexplore | sort –descending cpu | select –First 1 | stop-process

Or by going for only the Internet Explorer windows with active threads

get-process iexplore | ? {$_.threads | ? {$_.threadstate –eq “Running”} } | stop-process

I really like this method the most.  The thing that gives it an extra edge over the other methods is that if it kills open tabs but not all the tabs on a window, then the tab is reopened automatically.  Hopefully it’s enough of a kick in the pants to get the window open.

Have I overlooked something?  How can it be done better?

Automate Dell Support With PowerShell: Open Dell’s Site With System Tag Automatically

Are you tired of entering the system tag information by hand on Dell’s support web site?  You want a fast and easy way to automate Dell support with PowerShell.  I’ll show you how to Automate Dell Support With PowerShell in this life changing series!

This week, we’re learning how to open Dell’s support site with the system tag filled in automatically.

If you previously read my post on getting the Dell System Tag from WMI you may have, like me, come away from it with one big problem.  In the article, I say that you can enter the system tag into Dell’s support page.  That is a little lame, don’t you think?  Audacious, in fact, to suggest that a PowerShell user should have to do anything!

So, with my apologies, here is a very quick improvement to help you get to your Dell Support Page that much faster.

How To Open Dell’s Support Page with the System Tag Already Filled In

function popup-Dellinfo

{
$systemtag = (gwmi win32_bios).serialnumber      

#Thanks to Jeffrey Snover for pointing out the Win32_BIOS class

$ie = new-object -com "InternetExplorer.Application"

$webaddress= [string]::Format("

http://support.dell.com/support/DPP/Index.aspx?c=us&cs=RC956904&l=en&s=hied&ServiceTag={0}",$systemtag)

$ie.Navigate($webaddress)

$ie.visible=$true
}

Drop that function into PowerShell, or add it to your PowerShell profile.

That’s pretty good, but I think it can be better.

To see it go from this rudimentary function to something more robust come back next week.  Or subscribe to this blog and read it the day it comes out in your RSS reader!

How To Find Dell System Tag Using PowerShell

I administer a lot of computer brands, and support a wide ecosystem.  But I see a lot of Dell Laptops, Desktops, and Servers in my normal day-to-day.  A common task is to rebuild a system, or to update a driver after troubleshooting blue screens.

When it’s time to download drivers, there’s one sequence of events that I don’t want to do anymore:

  1. Turn over laptop
  2. Read the serial number
  3. Tell myself “I got this”
  4. Stare at the serial number
  5. Memorize the serial number
  6. Turn the laptop back over, and enter the serial number onto the support webpage
  7. Forget the stupid serial number halfway through (cause it’s the serial number that’s stupid, not me, right?)
  8. Repeat steps 1-7 again (do step 8 only one time.  If today is Monday and you have not had coffee yet, do step 8 two times)
  9. Fine!  Write down the stupid serial number
  10. Tell myself “No problem – I told you I got this”

Now that I’m more refined in my technique, I can show you my simple way to find the serial number or system tag of a Dell computer by using PowerShell:

get-wmiobject Win32_ComputerSystem | select SerialNumber

That actually returns a PSCustomObject.  Now, you might want to get right at the string value instead.  If you’re putting the computers serial number or system tag through the pipeline, or saving it to a file, then you should use this instead – it will return just the string value stored in WMI.

(gwmi Win32_ComputerSystem).SerialNumber

Here, we invoke the alias for get-wmiObject, gwmi.  It is exactly the same, just fewer keystrokes.  Then, we use the parenthesis to turn it into an object, and put the “.” (dot) there to get access to the properties.

This can also be used to get the system tag for a remote system by using the –computername parameter on the get-wmiobject cmdlet

gwmi Win32_ComputerSystem –computername remotesystem-pc

This is the best way that I’ve found to get the information from a Dell computer.  You can use the Service Tag on their website to get up to date drivers and warranty information.

PowerShell Profile Trick – Change Background Color On Administrative Shell

Here’s a great piece of profile customization: Make your PowerShell session have a dark red background each time it starts a session running as an administrator.

To do this, I look the built in $host variable, which has several properties in it, such as the foreground color and the background color of the shell.  Here’s the difference between a PowerShell session running in normal mode (blue screen) vs. administrator mode (red screen)

Advertisement

Standard PowerShell Session
Blue background on regular session
Administrative Powershell Session
Red background on an administrative session

 

Continue reading “PowerShell Profile Trick – Change Background Color On Administrative Shell”

Holy Profile Trick! Add a Daily Bible Verse to Your PowerShell Console

Excellent profile customization.  I use this one myself, and honestly it’s my favorite one.  Keeps my head in the right place.

This PowerShell profile customization is simple and sweet:  Go grab a webpage source; parse the lines to get to the juice; display a daily bible verse on my PowerShell console.

Continue reading “Holy Profile Trick! Add a Daily Bible Verse to Your PowerShell Console”

How to Identify Uninstaller Information From Registry Keys

If you want a fast way to get information about the uninstallers that are listed in the registry, then check out this simple script to parse out some information for you.


$searchterm = read-host "Enter search term for uninstallers"
$uninstallers = get-childitem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
$founditems = $uninstallers | ? {(Get-ItemProperty -path ("HKLM:\"+$_.name) -name Displayname -erroraction silentlycontinue) -match $searchterm}
write-host "Searched registry for uninstall information on $searchterm"
write-host "------------------------------------------"
if ($founditems -eq $null) {"None found"} else {
write-host "Found "($founditems | measure-object).count" item(s):`n"
$founditems | % {
Write-host "Displayname: "$_.getvalue("Displayname")
Write-host "Displayversion: "$_.getvalue("Displayversion")
Write-host "InstallDate: "$_.getvalue("InstallDate")
Write-host "InstallSource: "$_.getvalue("InstallSource")
Write-host "UninstallString: "$_.getvalue("UninstallString")
Write-host "`n"
}
}

This little baby asks you for a search term, then grabs the pertinent software uninstall information out of the HKey Local Machine registry hive.

It’s simple and effective,  and I put it together in just a couple of minutes.  It could stand to have some polish on it, but it does the job and it does it like now!

Would you improve it?  How?  Comments are open.

Continue reading “How to Identify Uninstaller Information From Registry Keys”