Category Archives: PowerShell ISE


Quick Script Share: Adding A Bunch Of Random Test Users To Active Directory

I recently had a need to add a bunch of random users to a specific OU in Active Directory to do some testing. I didn’t care what their names were, but, I wanted to be able to find all the users that belonged to each batch. Here’s the script I wrote to do this.



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.



Just Enough Administration (JEA) First Look

If you’re reading this, it means that Windows Server 2016 Technical Preview 4 is released (currently available on MSDN) and one of the new features that’s available is Just Enough Administration (JEA)! Until now, you could use DSC to play with JEA but now it’s baked into Windows Server 2016.

If you’re not sure what JEA is or does, check out this page published by Microsoft.

So how do you get started?

JEA gets put together like a module. There are a bunch of different ways to dive in, but for convenience, I’m just covering this one example. Build on it and learn for yourself how JEA can work for you specifically!

First things first, make a new directory in your modules folder and navigate to it.

So far, so easy. Now, we’re going to use the brand new JEA cmdlets to configure what is basically our constrained endpoint.

This PSSC is the first of two files we’re going to make. It’s a session config file that specifies the role mappings (we’ll get to roles in a second) and some other general config settings. A PSSC file looks like this.

If you’ve ever authored a PowerShell module before, this should look familiar. There’s only a few things you need to do here. The first is change the value for SessionType to RemoteRestrictedServer. You need to make it this in order to actually restrict the user connections.

You can enable RunAsVirtualAccount if you’re on an Active Directory Domain. I won’t get too deep into what virtual accounts do because my example is just on a standalone server.

The other important task to do is define the RoleDefinitions line. This is a hashtable where you set a group (in my case, local to my server) assigned to a “RoleCapability”. In this case, the role I’m assigning is just named “testers” and the local group on my server is named “test users”.

Save that and now it’s time to make a new directory. Roles must be in a “RoleCapabilities” folder within your module.

Now we are going to continue using our awesome new JEA cmdlets to create a PowerShell Role Capabilities file.

It’s very important to note here that the name of my PSRC file is the same as the RoleCapability that I assigned in the PSSC file above.

PSRC files look like this. Let’s point out some of the key areas in this file and some of the tools you now have at your disposal.

Think of a PSRC as a giant white list. If you don’t explicitly allow something, it’s not going to happen. Because PSRCs all act as white lists, if you have users who are eligible for more than one PSRC (through more than one group membership/role assignment in a PSSC), the access a user gets is everything that’s white listed by any role the user is eligible for. That is to say, PSRCs merge if users have more than one that apply.

Let’s skip ahead to line 25. What I’m doing here is white listing any cmdlet that starts with Get- or Measure- as well as Select-Object. Inherently, any of the parameters and values for the parameters are whitelisted, too. I can hear you worrying, though. “What if a Get- command contains a method that allows you to write or set data? I don’t want that!” Well, rest assured. JEA runs in No Language mode which prevents users from doing any of those shenanigans.

Also in line 25, I’m doing something more specific. I’m including a hashtable. Why? Because I want to allow the New-Item cmdlet but only certain parameters and values. I’m allowing the ItemType parameter but only if the user sets it to Directory. I’m allowing Force, which doesn’t take a value. I’m also allowing the Path attribute, but, only a specific path. If a user tries to use the New-Item cmdlet but violates these rules, the user will get an error.

On line 19, I can import specific modules without opening up the Import-Module cmdlet. These modules are automatically imported when the session starts.

On line 28, we can make specific functions available to connecting users.

Line 31 is interesting. Here I’m making an individual script available to the connecting user. The script contains a bunch of commands that I haven’t white listed, so, is the user going to be able to run it? Yes. Yes they are. The user can run that script and the script will run correctly (assuming other permissions are in place) without having the individual cmdlets white listed. It is a bad idea to allow your restricted users to write over scripts you make available to them this way. 

On line 37, you can basically configure a login script. Line 40 lets you define custom aliases and line 43 lets you define custom functions that only exist in these sessions. Line 46 is for defining custom variables (like “$myorg = ‘ThmsRynr Co.”) which can be static or dynamic.

With these tools at your disposal, you can configure absolutely anything about a user’s session and experience. Sometimes, you might have to use a little creativity, but anything is possible here.

Lastly, you need to set up the JEA endpoint. You can also overwrite the default endpoint so every connection hits your JEA config but you may want to set up another unconstrained endpoint just for admins… just in case.

That’s it. You’re done. Holy, that was way too easy for how powerful it is. Now when a user wants to connect, they just run a command like this and they’re in a session limited like you want.

If they are in my local “Test Users” group, they’ll have the “testers” role applied and their session will be constrained like I described above. You’ll need to make sure your test users have permissions to remotely connect at all, though, otherwise the connection will be rejected before a JEA config is applied.

I can think of a bunch of use cases for JEA. For instance…

1. Network Admins
I’d like my network admins to be able to administer DHCP and DNS on our Windows servers which hold these roles without having carte blanche admin rights to everything else. I think this would involve limiting the cmdlets available to those including *DHCP* or *DNS*.
2. Certificate Management
We use the PSPKI module for interacting with our Enterprise PKI environment. For this role, I’d deploy the module and give users permissions to use only the PSPKI cmdlets. I’d use the Windows CA permissions/virtual groups to allow or disallow users manage CA, manage certificates, or just request certificates.
3. Code Promotion
Allowing people connecting via JEA to read/write only certain areas of a filesystem isn’t practical. The way I’d get around this is to allow access to run only one script which performed the copy commands or prompted for additional info as required. You could mix this in with PowerShell Direct and promote code to a server in a DMZ without opening network holes or allowing admin access to a DMZ server.
4. Service Account for Patching
We have a series of scripts that apply a set of rules and logic to determine if a server needs to be patched or not. All it needs to do is perform some WMI queries, communicate with SCCM (which has the service installed to actually do the patching) and reboot the server. Instead, right now, that service account has full admin rights on the server.
5. Help Desk
Everybody’s help desk is different but one job I’d like to send to my help desk is some limited Active Directory management. I’d auto-load the AD module and then give them access to very restricted cmdlets and some parameters. For instance, Get-ADUser and allow -Properties but only allow the memberof, lockedout, enabled and passwordlastset values. I might also allow them to add users to groups but only if the group was in a certain OU or matched a certain string (ie: if the group ends in “distribution list”).
6. Print Operators
We have a group of staff on-site 24/7 that service a giant high speed print device. There are a number of servers that send it jobs and many are sensitive. I’d like to give the print operators group permissions to reach out and touch these servers only for the purposes of managing print jobs.
7. Hyper-V Admins/Host Management
These guys need the Hyper-V module and commands within it as well as some limited rights on the host, like Get WMI/CIM objects but not the ability to set WMI/CIM objects.

Get playing!

The possibilities of what you can do with JEA are endless. While the DevOps mentality is flourishing, the need to enable access to different systems is growing. With JEA, you can enable whatever kind of access you need, without enabling a whole bunch of access you don’t. That’s probably why it’s called “Just Enough Administration”.


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:

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.