Imported PowerShell Sessions ErrorActionPreference Gotcha

I just bumped into something silly that I know I’ll forget about in the future. Using the function in my PowerShell profile to open an Exchange Management shell, I ran the following command as part of a script.

It’s a pretty self-explanatory command. I was trying to detect if a mailbox, in this case “doesntexist”, existed or not. Typically if the mailbox doesn’t exist, the Get-Recipient cmdlet will throw an error. My goal was to catch the error and do something productive with it but the above command doesn’t trigger the Catch block.

No problem, I thought to myself. My ErrorActionPreference is set to Continue by default so I’ll tweak it for this command.

The -ErrorAction Stop part should make the script stop executing on an error and hop into the Catch block. Wrong! The above command throws an error without triggering the Catch block, too.

It turns out I had to edit my $ErrorActionPreference variable to be Stop. Just using the flag in the command doesn’t work. I’ve run into this in other scripts where I import a PSSession, too. Now my command looks something like this.

First, I’m getting the current value of $ErrorActionPreference and storing it. Then I set the ErrorActionPreference to Stop. I run my Get-Recipient command which fails and now instead of getting an error, my Catch block is triggered. Afterwards, I set $ErrorActionPreference back to it’s previous value.

Now, because I’ve written a blog post about this, I’ll never forget again.


Quick Tip: Use PowerShell To Detect If A Location Is A Directory Or A Symlink

In PowerShell, symbolic links (symlinks) appear pretty transparently when you’re simply navigating the file system. If you’re doing other work, though, like changing ACLs, bumping into symlinks can be a pain. Here’s how to tell if a directory in question is a symlink or not.

Consider the following commands.

Here, we’re just running a Get-Item command on two locations, getting the Attributes property and converting to a string. The first item is a symlink and includes “ReparsePoint” in its attributes. The second item is a normal directory and does not include “ReparsePoint”.

So that means we can do something as easy as this.

Easy. If the above values have “ReparsePoint” in them, we know they are a symlink and not just a regular directory. In my case, my script to apply ACLs to a group of directories avoided symlinks with ease.


Bypassing PowerShell Execution Policy

Let me be absolutely clear about this post. I do not in any way encourage or support people who wish to use the below information to circumvent the controls put in place by companies and administrators. This post is strictly for academic purposes and for the sake of sharing information.

PowerShell Execution Policies control whether or not a system may run a PowerShell script based on whether the script is signed or not. See the about_Execution_Policies Technet page for more information if you are unfamiliar with execution policies or how to apply them. Execution policies do not, however, limit a user or service from running commands in a PowerShell shell (PowerShell.exe).

So what if you have an unsigned script you want to run but your execution policy is preventing it? Well, there’s a way to bypass the execution policy. And it’s run from a PowerShell shell.

Administrative users can easily bypass the execution policy with this command.

But what about limited users? Well there’s something for them, too.

That’s right, just one line. No registry hacking, no weird developer program strangeness, just a command that allows a user or service to subvert the execution policy of the machine.

Let’s break down the command. We’re launching PowerShell.exe, not exactly a puzzler. We want it with no profile and we’re telling it to run a command. The trick is that the command we’re running is effectively going to be the script that our execution policy would otherwise block.

The dot is basically an alias for “execute” and in this case, we’re telling it to execute what’s in the proceeding round brackets. The round brackets contain instructions to create a new ScriptBlock out of the contents of the .ps1 file that the execution policy would otherwise prevent from running.

I think it’s clear that this is not really something that Microsoft intends for you to do. Use (or not) wisely at your own discretion.


Find All Certificates Issued Of A Specific Template

As part of another PowerShell script I’m writing, I needed to get an array of all of the certificates issued in my Enterprise PKI environment by a specific Issuing Certificate Authority (CA) that are of a certain Certificate Template.That doesn’t sound like such a tall order. You can launch MMC.exe, add the Certification Authority module, browse the issued certificates and see for yourself the different issued certs and their template.

PowerShell is a bit trickier, though, for a couple reasons. First, you’re going to need a PowerShell module to help you with this task. I really like PSPKI (available on CodePlex). Install that module and run the command to import the module.

The next tricky thing to keep in mind is that your “CertificateTemplate” attribute on each issued cert doesn’t always present itself like you think it should. That’s pretty ambiguous so I’ll explain more.

In the Certificate Authority MMC, most of the certificates you issue should have a value in the Certificate Template column along the lines of Template Name (OID for the template) where the part in brackets is the unique object identifier (OID) for the template. In the MMC, this information is presented pretty consistently. This isn’t really the case for PowerShell.

The following command will get you a list of all the Certificate Templates that have been used to issue certs on your CA as the Certificate Templates are presented in PowerShell.

The first thing we need to do is get the CA since the Get-IssuedRequest cmdlet works with a CA. We get the issued requests (the certificates that have been issued from the CA) while making sure to include the CertificateTemplate property. Then we just select the unique Certificate Templates. Mine returns a mixed list of OIDs and more traditional names – not Name (OID) like we saw in the MMC. Keep this in mind as we continue.

Back on track, where’s my list of certs with a specific template?

With the above information in mind, we’re better armed to get a list of all certs issued by our CA with a specific template. We really only have two steps: 1. Find out how the Certificate Template we’re concerned with is represented in PowerShell and 2. Actually get the list of certs with that template.

Task 1 isn’t so hard. First, go into the Certification Authority MMC and find a cert with the template you are concerned with. Look at the Issued Common Name column and take note of the value in that column. Then in PowerShell, run this command.

Like above, we’re getting the CA we’re concerned with and getting the issued requests. This time, though, we’re not looking to return every cert issued, just the one(s) where the Common Name is the same as the value you saw in the MMC. We also need to make sure to include the CertificateTemplate property because it’s not returned by default. Use -property * to get every property back and take a detailed look at a certificate. There are some neat things you can do.

This will get you back a bit of interesting information about the certificate you identified in the MMC as being of the correct template. Specifically, you can see what the value is under the CertificateTemplate property. Maybe it’s a friendly name, maybe it’s an OID. Either way, that’s the value that PowerShell is using to identify that particular template.

Use the above value for the CertificateTemplate in this command.

We’re getting the CA, getting all the issued certs (including those certs’ CertificateTemplate property) and filtering where the CertificateTemplate property is equal to the one we found in the last command we ran.

There you go! Export that to a CSV, assign it to a variable. The rest is up to you.


Quick Tip: List All SMA Schedules That Repeat

I use a few PowerShell scripts that end up triggering Service Management Automation (SMA) runbooks. Each time you want to use PowerShell to do that, you end up creating a one-time use SMA schedule. These one-time schedules are eventually cleaned up by SMA but they can clutter your view pretty well if you have a lot of them.

Luckily, there’s an easy way to use PowerShell to list SMA schedules that aren’t one-time use. We just want a list of all the SMA schedules that are repeating. You need the SMA PowerShell tools for this.

We’re going to get all the SMA schedules on our SMA implementation and get the ones where there is a NextRun value. The question mark is an alias for the Where-Object command and so we’re looking for schedules where $_.NextRun is true (has a value, isn’t null). I like formatting the output as a table for easier reading.

If a schedule has a NextRun attribute, it’s safe to say that it’s going to run sometime in the future and is not a one-time use schedule that’s already done it’s job.


Quick Tip: Get-Random Is Weird – Doesn’t Include The Maximum Value

The PowerShell command Get-Random is kind of weird. Consider the following script:

Run it on your own computer. Every second, it should write a random number between 1 and 2 until you interrupt it (CTRL + C). You would expect a somewhat balanced output of 1’s and 2’s like if you were recording the outcomes of repeatedly flipping a coin. Right? Wrong. You will get a string of 1’s and never ever EVER get a 2. Change the Maximum to 3 and you will get 1’s and 2’s but no 3’s.

Apparently the maximum value of the Get-Random command isn’t a valid value to return, but, the minimum is. It’s possible that there is a condition where the command will work as expected but I haven’t experimented enough to know for sure.



Tricky PowerShell Pipeline Tricks – Playing With WMI

Here’s a quick task: Get the WMI object win32_bios for a computer. Using PowerShell, that’s really easy. You just run Get-WMIObject win32_bios. Now what if you wanted all the extended properties of the object (not just the five that it normally returns) and ONLY to return the properties that actually have a value assigned?

Well this question just got trickier. win32_bios isn’t very big so it’s an easy one to play with in this example. Let’s step through a couple commands so we know what we’re dealing with.

Well okay, there are the five properties that we knew the command returns by default. We know the extended properties are in there and we can prove it.

There’s everything! That’s a lot of blanks, though. Depending on the type of reporting you’re doing, that might not be so nice to look at. I know that I’d like to get them out. Luckily with PowerShell 4.0, it’s really easy if you use the -PipelineVariable parameter.

I’ve left out the output since it’s every property that has a value and none of the ones that have a blank. Let’s take a look at what’s actually happening here.

On Line 1, we’re running the same command we ran the last two times except we assigned a Pipeline Variable which will be named $bios (you omit the $ when assigning the name of the variable). We enter a foreach loop on Line 2.

On Line 3, we’re setting the value of $props and on Line 4, we’re writing out the part of the WMI object that contains it. The tricky thing here is how we get the value of $props. Look at how we use the Pipeline Variable and the .PSObject.Properties.Name property to identify the items with a value.

Well that’s great but what if I don’t have PowerShell 4.0 or found that example really confusing?

Don’t worry, this is pretty easy to do in earlier versions of PowerShell, too.

I started using some more shortcuts (gmi and % instead of Get-WMIObject and foreach).

In Line 1, I’m doing the same ol’ Get-WMIObject command that I did before and in down the pipe, I’m assigning the value to $wmi. I could have also done “$wmi = gmi win32_bios” but this strategy has benefits if you’re planning on scaling this script out.

In Line 2, I’m doing some tricky Select-Object work. The input for the command is $wmi, which isn’t so tricky, but the property that we’re selecting is pretty tricky. -Property takes an array, so we can put a command in there as long as it returns an array.

$wmi has a property of .Properties.Name which is an array of all the names of the properties attached to the WMI object that got returned in Line 1 (that we are using as our input). We don’t just want all the properties, though, so we need to select only the ones with a value (not null). We do that by piping the list of all the properties into a Where-Object command.

The Where-Object command has a tricky property called -FilterScript which basically acts as an implicit IF statement. If you wrote Where-Object -FilterScript {$true} then you would return every object in the pipe. If you wrote Where-Object -FilterScript {($num = $((Get-Random -Minimum 1 -Maximum 100) % 2) -eq 1)} you would get random properties because sometimes the statement will be true and sometimes the statement will be false. These are all silly items to filter on, though.

In my script, I’m filtering on if the current property the script is looking at has a value in $wmi. If the property is 0 or null and therefore doesn’t exist, $wmi.item($_) will return false and that line won’t be returned. It’s basically a test to see if there’s a string or not. Consider this example:

Because $var1 doesn’t have an actual value assigned to it, an if ($var1) will return false. That’s the same logic we are using all throughout the above code.

Tricky, right?


Quick Tip: When was an Exchange Online Protection Transport Rule Changed?

What if you have an Exchange Online Protection (EOP) transport rule that isn’t behaving the way you thought it should? I’ve been the victim of some strange inconsistencies with EOP since they tried to migrate us from Forefront Online Protection for Exchange (FOPE) in March (actually summer) of last year.

So did a transport rule get changed administratively by some cowboy admin colleague? Or is EOP conspiring against you? In EOP’s GUI, you can’t tell when a transport rule was changed last but you can if you make a remote connection to EOP using PowerShell.

You just need to know the name which you can find by running a Get-TransportRule command and looking for the one that you’re interested in. Then run this…

… which will give you the date and time that the rule was last changed.


Quick Tip: Opening An Exchange Online Protection Shell

There’s lots of big, exciting, non-blogable things happening at work this week so here’s a very quick tip.

Last week I wrote a post on a PowerShell function I threw in my profile to connect quickly to Exchange. That’s great, but what if you also want to manage Exchange Online Protection (EOP) from a PoweShell console? Well it turns out to be pretty easy.

This looks a lot like the function I showed you last week except it’s connecting to Office 365 and you need to use your Live ID instead of AD credentials.


Opening A Remote Exchange Management Shell

Here’s a function I stuck in my PowerShell profile. I found myself making lots of remote connections to my Exchange 2013 environment so I put together a quick function to create the connection for me. It’s far from perfect but it saves me time every single time I use it so check it out.

On Line 1, we’re declaring the function – no big deal. I’m naming mine “gimme-exchange” so once my profile loads, I can just type that to start the function.

On Lines 3 to 5 I’m setting a few variables. Line 3 is weird. I made an array of the different Exchange servers I had rather than going through some autodiscovery process. The script will try to open a connection to the first one, if it fails, try the second one, and so on. It’s inefficient but I don’t add and remove a lot of Exchange servers so I can get away with it since this function is just for me. Line 4 is going to be used to detect if we made a connection or not. Line 5 will prompt and store the administrative credentials that you will use to create the connection.

On Line 6, we start looping through all the servers I specified in Line 3. In a Try/Catch block, if we haven’t already made a successful connection to a previous Exchange server, we’re going to make a new connection and import it. You have to make sure you use the -configurationname item because we’re not just creating any old PSSession, Exchange is funny and we connect to it using some special parameters shown in Line 12. When we import the session on Line 13, we’re going to allow clobbering of other existing cmdlets and suppress the output of the import command.

If we run into an error anywhere in the Try block, the Catch block is setup to echo out the error message and continue looping through servers depending on how severe the error is.

That’s it! Yay, saving time.

Update: If you’re already logged in as the user you want to connect to Exchange as, you can skip the credential gathering part and run this instead.