Splitting Strings On Escaped Characters In PowerShell – Literal vs. Dynamic Content

Before we get into this post, here’s a little required reading: http://blogs.technet.com/b/heyscriptingguy/archive/2015/06/20/weekend-scripter-understanding-quotation-marks-in-powershell.aspx

This is a “Hey, Scripting Guy!” post by Don Walker about using single vs. double quotes to wrap strings and other items ( ‘ vs. ” ). The bottom line is that single quotes should be your default go-to and denote a literal string. Double quotes are only to be used when dynamic content is involved. It’s all explained quite clearly in the post linked above.

Awesome information, but, it doesn’t talk about escape characters. In PowerShell the backtick character ( ` ) – the one you hit along with shift to get the tilde character ( ~ ) on most keyboards – is what’s known as an escape character. Here’s some more reading on escape characters if you’re unfamiliar.

Now, what if I have something like this?

It’s just a multi-line string with blank lines in between each of the lines with content. Now, what if I wanted to keep each of the content lines on it’s own line while removing all the lines that are blank? Well, since $Body is one big multi-line string, I can split it on “new line”. Using escape characters in PowerShell, to denote a new line we just type:

So can I do this?

I’m splitting $Body on each new line, and for each line, if it is not null or white space (using some of the information from this post), I write it. I’m using single quotes to wrap the new line marker to split up $Body. Well, unfortunately, the output looks like this.

Splitting Strings 1

Well, that’s not exactly what I was hoping for. Instead of splitting $Body on a new line, it looks like it’s split it on the letters n and r. It turns out that the escape character, like variables and the output from commands, is dynamic content. To do what I’m trying to do, the command needs to look like this.

The only difference is the value in the split command. Instead of single quotes I’ve got double quotes wrapping the new line marker. Now the output looks like this.

Splitting Strings 2

Perfect! So remember, escape characters are dynamic content. They are not considered part of a literal string.


Quick Tip: Which Of These Groups Are These Users Members Of?

Here’s a quick PowerShell function I put together that you might like to use or pick pieces from. The point of the function is to take a list of usernames and a list of groups and tell you which users are members of which groups, including through nested group membership.

As you can see, this function requires the ActiveDirectory PowerShell module and the function is named Test-IsGroupMember. It takes two parameters called Usernames and Groups. Both are “object” types so they could be an array or a string. I didn’t want to make overloaded versions of a script this simple so I took this shortcut. It’s expected that the values in Usernames and Groups will be SamAccountNames.

On Line 15, I start the work. For all of the groups you pass the function, it determines the recursive group members and extracts the SamAccountName attribute of the members returned. Then to the output stream, we write that the currently evaluated group has a number of members. On Line 19, we check to see if any of the usernames in the Usernames parameter are contained within the members of the group. I could have used a Compare-Object here but I didn’t. If the user is present in both arrays, we report back.

Here are some examples of how I like using this function.

Pretty flexible.


Sharing: MVPDays YEG Presentation Material

Last week, I had the distinct pleasure of speaking twice at MVPDays in Edmonton. I did two sessions. The first was titled “PowerShell 5.0 – A Brave New World” where Sean Kearney and I introduced the tip of the iceberg that is all the new stuff in PowerShell 5.0. The other session I did was on my own, titled “Going From PowerShell Newbie to PowerShell Ninja”. In the latter session, I promised to share some things today, and I’m here to deliver.

OPML File of Blogs I Follow – This is a file that you can import into any modern RSS reader. I follow 40+ blogs on PowerShell, technology and related topics. Feel free to take a look through the blogs I’ve endorsed here and follow all of them, or just the ones that make sense to you. Among these blogs are the premier resources I mentioned in my session: Hey, Scripting Guy! and PowerShell.org.

My PowerShell People Twitter List – If you’re looking to find people on Twitter who are knowledgeable about PowerShell, take a look at this list I curate. You can follow the whole list or take a look at these people I personally follow and recommend. Remember, Twitter is a great way to get introduced to new resources and connect with like-minded people. Follow the #PowerShell hashtag and join in for #MVPHour every other Monday.

Subscribe to the EMUG Mailing List – If you live in the Edmonton area and enjoyed MVPDays, you should consider signing up for the Edmonton Microsoft User Group mailing list, if you aren’t signed up already. This is the best way to stay informed about when similar events will be occurring. In fact, EMUG hosts several events throughout the year just for our members. Check out PowerShellGroup.org to find other regional PowerShell user groups who share their content, or join the virtual group.

And, of course, you can find me on Twitter (best way to reach me) and LinkedIn.

Good luck on your journey from PowerShell Newbie to PowerShell Ninja, and happy scripting!


Quick Script Share: Tell Me Everyone With Access To This Directory

Trying something new. Here’s a quick script I threw together to satisfy a request along the lines of “tell me all the users who have access to this directory”. It’s easy to see all the groups that have access just by right-clicking a directory and going to the Security tab but it’s a pain to get all the users who belong to those groups – especially if there are nested groups (within nested groups, within nested groups). Hence, this script. In addition to the ActiveDirectory PowerShell module, you of course need to be able to read the ACL on the directory you are interested in so use your admin account.

In this experimental post, I’m not going to break down the script, but instead, I’ve quickly commented in-line most of the tricky bits. I think it’s pretty straight forward, but, I wrote it. Let me know what you think.



My September 2015 Scripting Puzzle Solution

If you haven’t heard, PowerShell.org is taking the lead on organizing the PowerShell Scripting Games. There’s a new format that involves monthly puzzles. Here’s their post on September’s puzzle: http://powershell.org/wp/2015/09/05/september-2015-scripting-games-puzzle/

Here is my solution. The summarized instructions are: “You have a CSV with one column, “machinename”, and you need to return the friendly OS name for each. They’re a mix of machines dating back to WinXP. All have PowerShell 2.0 or better and WinRM is open between you and each host. Try to limit your usage of curly braces.”

I did this.

It’s pretty verbose but I made it that way for readability. I use a grand total of one pair of curly braces in the solution, which I hope satisfies the definition of “limited”. What I’m doing is importing the CSV, which is located wherever $InputFile is, and for each of the lines in that CSV, I am performing a task on the computer indicated. That task is to get the Win32_OperatingSystem WMI Object which contains all kinds of neat info about a system’s OS. Of the data returned, I am selecting the PSComputerName, which should equal the same value as the line in the input file (but doesn’t cost me any curly braces to return) and the Caption, which is the friendly name of the OS. I export that into $OutputFile’s location.

Fun times!


PowerShell Function To Get Time Since A User’s Password Was Last Changed

Here’s a small function I put in my PowerShell profile to tell me how long it’s been since an AD user’s password was last changed. You do know how to change your PowerShell profile, don’t you? Just type the following in a PowerShell prompt.

That will open your PowerShell profile in Notepad. You might be asked to create one if you don’t have anything there yet. Then just save that and next time you open PowerShell, whatever code you have in your profile will be executed. The code I’m putting in there right now is the definition for this function.

It’s pretty straight forward. My function is named Get-TimeSinceLastPWSet and takes one parameter, the username of the user we’re interested in. On Line 10, the actual work gets done. I’m making a new TimeSpan object assigned to $tsSinceLastPWSet which is the time between the user’s Passwordlastset AD attribute and the current date/time.

Since the function returns a timespan object, you can manipulate it like this to get more friendly output. (More info on Composite Formatting from MSDN. No PowerShell examples but it looks a lot like the C#.)

This will give you output that simply looks like “10 days, 12 hours” instead of the generic list formatted output you get when you write out a timespan object. I’ve actually made that the default behavior of the function I put in my personal profile because that’s more valuable to me.

Mine looks like this.

Just a small tweak. It returns that nice-to-look-at-string instead of the timespan object.


Detecting An Exchange Management Shell Connection

You don’t log onto an Exchange server via RDP and open the Exchange Management Shell application when you want to do Exchange-PowerShell things, do you? You follow the steps in my Opening A Remote Exchange Management Shell post, right?

But how do you detect if if you have an open remote connection or not? Well there’s a bunch of different ways so here’s an easy one. First, though, we need to understand a couple things about what happens when you open a remote Exchange Management Shell connection.

Here’s what the output of my Get-Module cmdlet looks like before I do anything Exchange-y.

Get-Module before anything Exchange related

Get-Module before anything Exchange related (click for larger)

I’m in ISE, I have the AD cmdlets added. Nothing going on here is too crazy. Now here’s what it looks like after I open a remote Exchange Management Shell connection like I told you how to do in the post linked above.

Get-Module after adding Exchange Management Shell

Get-Module after adding Exchange Management Shell (click for larger)

Notice that the Exchange stuff gets added under a tmp name? And that it’s different every time? That doesn’t exactly make it easy to detect. With the ActiveDirectory cmdlets you can just run Get-Module -name ActiveDirectory and it will either return something or not. Easy. How are you supposed to do that in a predictable, repeatable fashion for Exchange, especially since any other remote shells created to other services in the same manner may also be added with a tmp_ prefix?

In order to figure out how we can determine if we have a module added that belongs to a remote Exchange Management Shell, let’s take a closer look at the tmp module that just got added.

Details of the last module added

Details of the last module added (click for larger)

At first glance, we’re obviously not going to be able to use the Name or Path attributes to identify remote Exchange Management Shell connections. ModuleType, Version, most of the others all look useless for us here. What looks useful, though, is the Description attribute which reads “Implicit remoting for http://my-exchange-server.fqdn/powershell”. That, we can work with. Here’s my code to tell me if I have a module added whose description is for a remote session to my Exchange server.

The code will either return the description of the module if it’s added, or null. You can work with it like this.

Check it out.

Code at work

Code at work (click for larger)


My August 2015 Scripting Puzzle Solution

If you haven’t heard, PowerShell.org is taking the lead on organizing the PowerShell Scripting Games. There’s a new format that involves monthly puzzles. Here’s their post on August’s puzzle: http://powershell.org/wp/2015/08/01/august-2015-scripting-games-puzzle/

Here is my solution. The instructions are to get information back from a JSON endpoint (read more about it in the link above).

First things first, here’s how I did the one-liner part.

This brings back exactly what Mr. Don Jones has asked for. I’m using the Invoke-WebRequest cmdlet to make a web request to that IP and converting what’s returned using ConvertFrom-Json. Then it’s just a matter of formatting the output and selecting only the items we care about for this puzzle.

Alright, that wasn’t so bad. How about the next challenge? I wrote the following function.They asked for an advanced function, but I skipped the comment based help and the begin/process blocks. I could clean up how I work with the $IP parameter a bit, but, this is easier to look at and explain.

I’ve declared two parameters, $Attributes and $IP. $Attributes are the attributes we want to return. In our puzzle instructions, we’re asked for Longitude, Latitude, Continent_Code and Timezone but you could use this function to get any of them. By default, the function will return all attributes. $IP is another IP address that we can get data for. If you don’t specify one, the function will retrieve data for the client’s IP. Otherwise, we can get data for an IP that isn’t the one we’re making our request from.

Here are a couple examples of the function in action.

Here, I’m just running the script with no parameters set. It gets all the data back from my IP. I’ve sanitized a lot of the data returned for the purpose of publishing this post but it was all returned correctly.

Here, I asked for the attributes from the puzzle and specified the IP address for PowerShell.org. You can see that it returned exactly what we’d expect.

Finally, the challenge asks us to hit another public JSON endpoint. I don’t have a favorite but found one that shows you your HTTP request information. Here is what it looks like in action.

Interesting user agent.


How Do You Tell If Two Directories Have The Same Permissions?

The title of this post is a bit funny. The answer is obviously “You can pop both folders open in Windows Explorer, right click, Properties and compare the security tab!” right? Well, you can, but what about folders that have a lot of complicated permissions? What if you want to compare 100 folders? I don’t know about you but I’m not opening 100 folders and comparing the permissions on them all manually. If only PowerShell could help us! Well it can.

In this example, I have three subdirectories in my c:\temp folder. They’re named test1, test2 and test3. Test1 and test2 have the same permissions but test3 has different permissions than the first two.

The first command to get familiar with is the Get-ACL command. ACL stands for Access Control List. This command may take different objects as parameters but one type of object is a path to a directory. Do a Get-ACL someDirectory | Get-Member and you’ll see the huge number of methods and properties that get returned. We’re only really interested in one property though, the Access property.

Look at that. A list of all the different permissions on the folder we care about! Now all we have to do is compare this ACL to the ACLs of other directories. For this, why not simply use the Compare-Object cmdlet? Here’s the full script to compare three folders and commands. I’ll break it all down.

The first three lines are just getting the ACLs for the three directories I care about and storing the values in variables. There’s tons of better ways to get and organize that information but this way lays it out nicely for this example.

Line 5 is our first Compare-Object command and it’s actually pretty intuitive, in my opinion. It’s taking a reference object ($ACLone) and comparing to a difference object ($ACLtwo) and it’s comparing the Access property. This will return the differences between the two ACLs which is totally our goal. The problem is it looks kind of ugly and useless so I pipe the result into a select command. I’m expanding the Access property so you can see exactly which items are different and formatting it as a table.

On lines 5 and 7 you’ll see I’m also selecting a property called SideIndicator. What’s that? Well, when you compare two objects, in addition to seeing a list of differences, don’t you also want to see which object has the different values? SideIndicator is either => or <= depending on which object has the unique value. I’ll explain.

Here is the output of line 7 (comparing two directories with different ACLs). It’s snipped and edited but you’ll see the important parts and yours won’t look too different.

4-6-2015 1-35-28 PM

Click for larger

The side indicator column points left or right. This indicates whether the unique value is on the reference object or the difference object. Arrows pointing left indicate items on the reference object only, arrows pointing to the right indicate items on the difference object only.

There you go! You can use this and scale it to programatically compare file system permissions using PowerShell.

You can download a script I published for this purpose from the TechNet Script Center.


Quick Tip: Searching Exchange Message Tracking Logs (Get Results From Every Server)

When you use the Get-MessageTrackingLog cmdlet, by default, it only searches for messages/events on the server that you’re connected to (see my post on creating connections to Exchange). That’s not great in a multi-server environment. I want results from every server.

My solution is the following.

The Get-TransportService cmdlet gets a list of all the transport servers in your infrastructure. For each of the servers we get back, I’m running the Get-MessageTrackingLog cmdlet and appending the results to a $results variable. I’m taking that results collection and sorting it chronologically.