Category Archives: Automation


Quick Tip: Using Variables In ActiveDirectory Filters

If you work with the ActiveDirectory PowerShell module, you’ve probably used the -filter parameter to search for accounts or objects in Active Directory. You’ve probably wanted to use variables in those filters, too.

Say you have a command from something like an remote Exchange management shell, that returned an object that includes a username (called Alias in this example).

And let’s use that in an ActiveDirectory command. Ignoring the fact that you could find the account that has this username without using a filter, let’s see how you would use it in a filter.

You might try this.

But you’d get errors.

That’s because the filter can’t handle your variable that way. To use a variable in an ActiveDirectory cmdlet filter, you need to wrap the filter in curly braces.

And you get your results!

Pretty easy fix for a pretty silly issue.


Quick Tip: Get All The Security Patches Installed On A Server Since A Specific Date

Recently, I needed to get a list of all the security patches I’d installed on a group of servers in the last year. It turns out that there’s a WMI class for this and it’s super easy to retrieve this info.

In the win32_quickfixengineering class, you’ll find all the security patches installed on a system. One of the properties is the InstalledOn attribute which more recent than a year ago.

If you have a list of servers to do this for, this is still really easy.

Just paste them into a here-string and execute this for each of them.


Using PowerShell To List All The Fonts In A Word Document

Recently I was challenged by a coworker to use PowerShell to list all the fonts in a Word document. It turned out to be easier than I thought it would be… but also slower than I thought it would be. Here’s what I came up with.

There could very well be a better way of doing this but this is what I came up with in a hurry. Line 1 declares a new instance of Word and line 2 opens the document we’re looking at. Then, for each word (which is handily a property of the open word document), we’re expanding the font property and selecting all the unique names of the fonts on line 3. Lines 4 and 5 close the document and quit Word.

So you can get something like this!

Get All The Fonts In A Word Document Via PowerShell


How To Send An Email Whenever A File Gets Changed

A little while ago, I fielded a question in the PowerShell Slack channel which was “How do I send an email automatically whenever a change is made to a specific file?”

Turns out it’s not too hard. You just need to set up a file watcher.

First, we create the watcher, which is just a FileSystemWatcher object. Technically the watcher watches the whole directory for changes (the path), which is why we add a filter.

Then we register an ObjectEvent, so that whenever the watcher sees a change event, it performs an action. In this case, I just have it writing output but it could easily be sending an email or performing some other task.

To get rid of the ObjectEvent, just run the following.

It’s just that easy!


Using PowerShell To Add Groups To “AcceptMessagesOnlyFromDLMembers” Exchange Attribute

Here’s a bit of an obscure task. In Exchange you can configure the AcceptMessagesOnlyFromDLMembers attribute which does what it sounds like it does: it only allows the mail recipient to accept messages from members of specific distribution lists. The problem is, there’s no built in method for appending a distribution list (DL) to an existing list of DLs. If you set AcceptMessagesOnlyFromDLMembers equal to a value, it overwrites what was there before. So, I wrote a quick script to append a value instead of overwriting it. You’ll need a remote Exchange Management Shell and the AD management module for this.

First things first, I declare the function named Add-AcceptMessagesOnlyFromDLMembers which is a bit more verbose than I’d usually like to make it, but I’m also a fan of descriptive function and cmdlet names.

Second, I need some parameters. The mail recipient whose AcceptMessagesOnlyFromDLMembers value we’re appending something to, and the DL that we’re appending.

Line 11 is where we begin doing the real work. I’ve got to get the mail contact and select just the value currently in AcceptMessagesOnlyFromDLMembers so I can append something to it. I store that data in $arr.

On line 12, I’m retrieving the CanonicalName attribute for the DL I want to append to the list of DLs that can send mail to this contact. The AcceptMessagesOnlyFromDLMembers attribute is a bit weird in that it only appears to take Canonical Names, not Distinguished names, etc.. I’m appending that value to the end of $arr.

Line 13 is pretty straight forward. I’m setting the AcceptMessagesOnlyFromDLMembers attribute to the value of $arr determined in line 12.

That’s it! If this is a task you perform regularly, please take this script and apply it. If you make it more robust, I’d love to see what your modifications are.


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.


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”.