Tag Archives: powershell ise


Getting Large Exchange Mailbox Folders With PowerShell

I’ve been continuing my quest to identify users who have large Exchange mailboxes. I wrote a function in my last post to find large Exchange mailboxes, but, I wanted to take this a step further and identify the large folders within user mailboxes that could stand to be cleaned out. For instance, maybe I want to find all the users who have a large Deleted Items folder or Sent Items or Calendar. You get the idea. It’s made to be run from a Remote Exchange Management Shell connection instead of by logging into an Exchange server via remote desktop and running such a shell manually. Remote administration is the future (just like my last post)!

So, let’s define the function and parameters.

My function is going to be named Get-LargeFolder and takes three parameters. $FolderScope is used in the Get-MailboxFolderStatistics cmdlet (spoiler alert) and must belong to the set of values specified. $Top is an integer used to define how many results we’re going to return and $Identity can be specified as an individual username to examine a specific mailbox, or left blank (defaulted to *) to examine the entire organization.

Now I’ve added a couple lines to get all the mailboxes in my organization (or a specific user’s mailbox) which I pipe into a Get-MailboxFolderStatistics command with the FolderScope parameter set to the same value we passed to our function. Now we need to sort the results, but, see my last post for why that’s going to be complicated.

The FolderSize parameter that comes back with a Get-MailboxFolderStatistics cmdlet is a string which I’m splitting up in order to get back only the value in bytes which I am casting to a double. Now that we have gathered our stats and put them in order, I just need to select them so they may be returned. Here is the complete script.

Now you can do this.



Getting Your Organizations Largest Exchange Mailboxes With PowerShell

In a quest to hunt down users with large mailboxes, I wrote the following PowerShell function. It’s made to be run from a Remote Exchange Management Shell connection instead of by logging into an Exchange server via remote desktop and running such a shell manually. Remote administration is the future!

My requirements were rather basic. I wanted a function that would return the top 25 (or another number of my choosing) Exchange mailboxes in my organization by total size. I also wanted the ability to specify an individual user’s mailbox to see how large the specific box is.

So, let’s get started.

All I’ve done here is declare my new function named Get-LargeMailbox and specified its parameters. $Top is the integer representing the number of mailboxes to return (defaulted to 1) and $Identity is the specific mailbox we want to return (defaulted to * which will return all mailboxes).

Now, I know I need to get my mailboxes and retrieve some statistics.

So far, so good. We haven’t narrowed down the stats we care about yet but we’re getting all the mailboxes in the organization and retrieving all the stats for them. Now we’re about to run into a problem. There’s a property returned by Get-MailboxStatistics called TotalItemSize but when you’re in a remote session, but, it’s hard to work with. Observe.

You can see it returns a property consisting of a boolean value for if my quota is unlimited, and then a value of what my total size is. Ok, so that value is probably a number, right?

Well, yeah, it is. The Value of TotalItemSize is a number but it’s a Deserialized.Microsoft.Exchange.Data.ByteQuantifiedSize and when you’re connected to a remote Exchange Management Shell, you don’t have that library loaded unless you install some tools on your workstation. Rather than do that, can’t we just fool around with it a bit and avoid installing a bunch of superfluous Exchange management tools? I bet we can, especially since this value has a ToString() method associated with it.

Back to our function. I need to sort the results of my “Get all the mailboxes, get all their stats” command by the total size of the mailboxes.

Oh boy, string manipulation is always fun, isn’t it? What I’ve done here is sorted my mailboxes by an expression. That expression is the result of converting the value of the TotalItemSize attribute to a string and manipulating it. I’m splitting it on the open bracket character, and then again on the space character. I’m taking the second last item in that array, stripping out the commas and casting it as a double (because some values are too big to be integers). That’s a lot of weird string manipulation for some of you to get your heads around, but look at the string returned by default. I need the number of bytes and that was the best way to get it.

Now all I need to do is select the properties from my sorted list of mailboxes and return the top number of results. Here’s the final function.

Now you can do things like this.

Before we end, let’s take a closer look at the last example.

First, I’m declaring an array to hold the results of users and how large their mailbox is. Then I’m getting all the members of a group, taking the SamAccountName and performing an action on each of them. That action, of course, is retrieving their mailbox size using the function I just wrote and appending the results to the array. Then I need to sort that array and display it. The Select-Object command has the formatting I included to make the mailbox sizes have commas separating every three digits.


Get All The Members Of The Distributions Lists That A User Is A Member Of

This is kind of a weird script tip but I bumped into a need for this kind of script so I thought I’d share it. In this post, I have a user and I want to get all the members of all the distribution lists that the user is a member of. That is to say, if the user is a member of DL1, DL2 and DL3 distribution lists, I want to get all the other members of all those distribution lists. You’re going to need a remote Exchange shell for this.

Here’s the code I came up with.

Line 1 is just declaring a variable to hold the DistinguishedName attribute for the user I am interested in. Line 2 is the work line. The first thing I’m doing is getting all the distribution groups which have a member equal to the DN of the user I’m interested in. Now, the weirdness happens…

When you do a Get-DistributionGroup, you do not get the members of that group back with it. Here are the properties that come back that contain the string “mem” in the name.

Nothing in there contains the members. So back to the command I wrote to accomplish my goal.

I’m piping the Distribution Groups returned into a Select-Object cmdlet to return the Name property and then a custom column. The label is Members and the content is going to just be a string of all the Distribution Group members’ names separated by semicolons. The expression for my custom column is a Get-DistributionGroupMember command for the Distribution Group piped into a Foreach-Object (alias is “%”) which returns an array of all the names of the members in the Distribution Group. I use the -join command to take the array and convert it into a string separated by semicolons.

It’s just that easy!


Quick Script Share: Get-RandomPW – Create Random Passwords

I had a need to repeatedly create random passwords of varying lengths. To satisfy this need, I wrote the following basic script.

On line 1, you can see I named my function Get-RandomPW which I did because I like following the standard Verb-Noun naming scheme that PowerShell functions and cmdlets are supposed to follow. On lines 3 through 6, I’m declaring my only parameter, $Length. $Length is an integer which will represent the length of the password we want. By default, I create a 16 character password.

On line 7, $arrChars is declared and assigned the value of all the valid characters for my password. I list all the characters in one big string and convert to a Char array because it’s easier to look at and manage, in my opinion.

On line 8, I finally build the password. For all the numbers between 1 and $Length, I’m getting a random item from $arrChars. The result of that is an array, so I use the -join method to create a string from the array. On line 9, I return the password I built.

Here’s what the script looks like in action.



Using PowerShell To Simulate A Ransomware Attack

Disclaimer: There are tons of different ransomware variants which behave in tons of different ways. This is an example of simulating just one of those behaviors – one that I’ve found to be common.


It’s a commonly held belief that there’s nothing you can do to guarantee you’ll never be hit by a ransomware attack, you can only be prepared with systems and processes to detect one, stop it, and recover from it. If you’re putting in some sort of system to detect a ransomware attack, you’d probably be wise to test it, but how? Installing ransomware is not something I’d recommend.

A common way of detecting a ransomware attack is monitoring a file system for a series of conditions. This is one such way you might configure these conditions:

  1. A user modifies more than 100 files
  2. A user renames more than 100 files
  3. 1 and 2 happen in under 60 seconds

This works nicely because ransomware will usually encrypt a file (modifying it) and append an extension (renaming it) in a short amount of time. You might have some false positives with this, or you might want to make the conditions more strict or lenient but hey, it’s my blog and this is what I am testing with.

So how do you simulate this behavior with PowerShell? Like this.

Lines 1, 2 and 3 setup the environment. $strDir is the location we’re monitoring for ransomware attacks (or a test directory in this case). Line 2 empties the test directory which you probably don’t want to do indiscriminately in a production area but I want to do in my test area.

Line 3 creates 200 txt files in $strDir. 1..200 is a slick way of writing all the numbers between 1 and 200 inclusive. Try it yourself in a PowerShell console. Then, for each of those numbers, we’re creating a file and suppressing the output.

Line 4 is the ransomware simulation. For 101 files, we’re making a variable $strPath which is an individual file we created in line 3. We’re also crafting a new path stored in $strNewPath which is the same file but with an extension. Then I’m changing the contents of the file by writing “changed” inside it. Finally, I rename the file. The whole thing is wrapped in a Measure-Command block so I can see how long it takes. On my test system, the ransomware part took 688 ms.

There you go! Try it yourself and see if you can detect this simulated ransomware attack.


Quick Tip: Create New LPR Printers Using PowerShell

There are a bunch of overloads for Add-Printer and Add-PrinterPort to accommodate different kinds of printers and ports. I found it tough, however, to find real examples of how to use these cmdlets to add LPR printers and ports. Not TCP/IP, not TCPLPR, not local ports. I figured it out, though, and now here’s how I did it.

There are no real surprises here. It’s just a matter of finding the right combinations of parameters and their values to make LPR printers and ports happen. In this example, I’m creating a bunch of them out of a list I have in a file.


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.


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.



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.