Azure AD Role Activation

I’ve been trying to start using one of the many directory roles which Microsoft has defined for Azure AD. See https://docs.microsoft.com/en-us/azure/active-directory/active-directory-assign-admin-roles for the primary documentation on Azure AD roles.

If you’ve looked at Azure AD directory roles, you know that there are some roles which are immediately usable and others for which you have to do something to “turn them on.” I got stuck at the point of turning one on, and I figured an information post about this would be useful to others.

Behind the scenes there are two AAD objects in play. There is the DirectoryRole—which are all the roles that are usable in your tenant. And then there is the DirectoryRoleTemplate—which are all the roles which might be usable in your tenant. You “activate” a template to create a role object, which is effectively “turning it on”. I wrote a detailed blog post about this several months ago at: https://blogs.uw.edu/barkills/2017/02/28/azure-ad-roles/ if you want to learn more, but for the purposes of this post, you don’t need to know what’s in that other post.

From what I’ve been able to determine, there are three ways to turn these things on (listed in order I think they were available):

  1. MSOnline PowerShell module, via Add-MsolRoleMember, https://docs.microsoft.com/en-us/powershell/module/msonline/Add-MsolRoleMember?view=azureadps-1.0
  2. Azure AD Graph API, via REST call documented at https://msdn.microsoft.com/en-us/library/azure/ad/graph/api/directoryroles-operations#ActivateDirectoryRole
  3. AzureAD PowerShell module, via Enable-AzureADDirectoryRole cmdlet, documented https://docs.microsoft.com/en-us/powershell/module/azuread/enable-azureaddirectoryrole?view=azureadps-2.0.

I also suspect that there may be ways to silently activate a role via one of the GUI admin consoles, but I have not extensively explored this.

Speaking of silent activation, I think that’s what option #1 does—you don’t have to know anything about DirectoryRoles, DirectoryTemplates, or even be aware there is an activation. But since that module is “old”, I’ve been purposely avoiding it, and I have to believe that’s what at least some others are doing.

Option #2 is likely not an option that many try. But I happen to like the Azure AD Graph Explorer because I find I can get more low-level details from it than any other AAD tool, so this is an option I tried. However, the documentation referenced is pretty opaque to me, with a recommended call that didn’t even include the required parameter—which I have to guess is because the documentation is incomplete. I couldn’t find a way to make it work, even by adding in the required parameter and the objectId of the DirectoryRoleTemplate I wanted to activate. I’m left wondering what the right incantation is to get this option to work.

Option #3 is where I started because I’ve come to like the AzureAD module. And I followed the example in the documentation ending up with the error message:

Enable-AzureADDirectoryRole : A parameter cannot be found that matches parameter name 'DirectoryRole'.

This drove me batty for a while, especially since it is a required parameter.

Eventually, I realized that the example listed is for a prior version of the AzureAD module, and they made major changes to the parameters. This issue was masked by two things:

  • the example in the documentation is completely incorrect for the current version—it must be based on a prior version
  • the help for this cmdlet is also incorrect, and not just the example but all of the help is incorrect

Making major changes to the parameters, especially when you drop the only required parameter, and not updating the documentation is bad, and that’s what seems to have happened here.

The good news is that the steps required, which used to include instantiating a special object to pass into the cmdlet, are much less complicated. From a high-level, you grab the objectId of the DirectoryRoleTemplate you want to activate, then pass that into the cmdlet as a string. So the example *should* read this:

$InviterRole = Get-AzureADDirectoryRoleTemplate | Where-Object {$_.DisplayName -eq "Guest Inviter"}

$InviterRole

 

ObjectId                             DisplayName   Description

--------                             -----------   -----------

95e79109-95c0-4d8e-aee3-d01accf2d47b Guest Inviter Guest Inviter has access to invite guest users.

 

Enable-AzureADDirectoryRole -RoleTemplateId $InviterRole.ObjectId

 

ObjectId                             DisplayName   Description

--------                             -----------   -----------

03618579-3c16-4765-9539-86d9163ee3d9 Guest Inviter Guest Inviter has access to invite guest users.

I hope this helps save someone else time. And I hope Microsoft takes note of the mess here and the places they might improve the documentation to help others in the future.

Get-ADGroupMember and ADWS parameter MaxGroupOrMemberEntries

By default, ADWS restricts several of the AD PowerShell cmdlets, like Get-ADGroupMember, to returning a mere 5,000 member entries. Which is annoying when you have larger groups, like we do.  Back in July 2015, we were pondering bumping up that limit, as described here: https://technet.microsoft.com/en-us/library/dd391908(WS.10).aspx, but couldn’t find others who had made this change.

I ran into this annoying limitation again recently, and after a bit of fresh research found http://mctexpert.blogspot.com/2013/07/how-to-exceed-maximum-number-of-allowed.html, as someone who actually did make the limit change and had specific syntax to make the change, although there is no real report on impact.

I went ahead and changed this ADWS limit to 200,000 on one of our DCs and re-ran my PS script against that DC. One of many large groups had a timeout (as might occasionally be expected due to other load), but otherwise there was no significant impact (to the DC) and I didn’t have to use the awkward & annoying workarounds of:

$members = Get-ADGroup <groupname> -properties Member | select-object -expandproperty member

Or

(Get-ADGroup <groupname> -properties members).members | Get-ADUser -properties samAccountName | Select-Object samAccountName

Or

$group =[adsi]”LDAP://CN=Group1,OU=Groups,DC=msad”

$members = $group.psbase.invoke("Members") | foreach {$_.GetType().InvokeMember("name",'GetProperty',$null,$_,$null)}

 

As a domain which has large groups, we seem to run into quite a few Microsoft design constraints, and after trying this in a large AD at 40 times the existing limit, I’m not sure I really understand why Microsoft chose such a low number, although I guess it is because of customers which run DCs on underpowered hardware.

DCs, time event 142, w32time, and group policy

Over a year ago, we applied a fix related to this on our domain controllers because of intermittently reported client problems. This fix was the most significant finding out of Microsoft AD RAP as a service engagement that we had.

Turns out that down in the deep details of the time settings there’s a lot that can cause problems. And Microsoft deployed poor values for many of those settings for prior OSes, some of which got encoded in the default group policy values. We turned on those group policy settings back when the values were really bad, and of course, those bad values were still in place because nothing will automatically change an existing GPO setting.

 

Here’s a table summarizing the craziness:

  2008R2 Admx Defaults 2008 / 2008R2 DC Default* 2008 / 2008R2 Member Defaults 2003 Adm Defaults 2003 DC Defaults
FrequencyCorrectRate 4 4 4 4 4
HoldPeriod 5 5 5 5 5
LargePhaseOffset 50000000 50000000 50000000 128000 50000000
MaxAllowedPhaseOffset 300 300 300 300 300
MaxNegPhaseCorrection 172800 172800 4294967295 54000 4294967295
MaxPosPhaseCorrection 172800 172800 4294967295 54000 4294967295
PhaseCorrectRate 1 7 1 1 7
PollAdjustFactor 5 5 5 5 5
SpikeWatchPeriod 900 900 900 90 900
UpdateInterval 100 100 30000 30000 100
AnnounceFlags 10 10 10 10 10
EventLogFlags 2 2 2 2 3
LocalClockDispersion 10 10 10 10 10
MaxPollInterval 10 10 15 15 6
MinPollInterval 6 6 10 10 10

* These are the settings you want on you DCs as they are the OS defaults for a DC

 

On your DCs, you want to apply what’s in the column labeled “2008/2008R2 DC Default*”. To correct our problem, I turned off all the GPO time settings. Then I turned them back on. Then I fixed the only setting whose (GPO) default value doesn’t match the OS default value for a DC (PhaseCorrectRate).

 

This fixed all of the time events being raised in our domain.

 

YMMV, but I expect this will likely help quite a few folks.

Windows Firewall + PowerShell + Group Policy = Wonderful

Last year I did some work around putting together a group policy for the UWWI servers that restricts who can access them to the current definition of the UW Network.

Group policy allows you to define configuration settings once and apply them broadly. And what better application than the Windows Firewall rules that are so crazily detailed and finicky? Who likes to set local Windows Firewall rules? Yuck.

James Morris tipped me off that there were some PowerShell cmdlets that would help me. And he was absolutely right … there was one which really saved a massive amount of time in defining the rules that went in the GPO.

Here are some breadcrumbs that should allow you to put something similar together yourself.

The UW-IT NOC has this document defining the UW Networks: https://wiki.cac.washington.edu/display/UWNOC/IP+Address+Space+Usage

Note that includes both IPv4 and IPv6. And Windows Firewall handles both. 🙂

So then you do something like this:

PS C:\Windows\system32> $IPs = @(“128.208.0.0/16″,”128.95.0.0/16″,”140.142.0.0/16″,”198.48.64.0/19″,”205.175.96.0/19″,”69.91.128.0/17″,”173.250.128.0/17″,”108.179.128.0/18″,”172.16.0.0/12″,”10.0.0.0/8″,”2607:4000::/32″,”fd73:a9bd:11bb::/48”)

Then you create your group policy object. Let’s say I created mine in the Dogfood domain, with a name of “uwit: UWWI firewall test”.

You then do something like this:

PS C:\Windows\system32> set-netfirewallrule -DisplayName “Windows Remote Management – Compatibility Mode (HTTP-In)” -RemoteAddress $IPs -PolicyStore “dogfood.netid.washington.edu\uwit: uwwi firewall test”

This adds a firewall rule to the GPO for WinRm that restricts traffic to the IP networks in the $IPs variable.

If you pull up the GPO in the GUI, you’ll now see that firewall rule in the GPO. Nice! 🙂

The next trick is figuring out which rules you need to add, and that really depends on the box and how tight you want to configure it. On thing to consider: you might go with a course grain approach, restricting TCP & UDP & ICMP traffic, and skip the fine grain approach of delineating all the individual services.

Want to read up on the Windows Firewall with Advanced Security? See http://technet.microsoft.com/en-us/library/cc754274.aspx. If you do dig into it and go the more fine grain route, make sure you understand the Windows Service Hardening type of firewall rules. These are rules defined by the product team (or 3rd party apps/services) and can’t be removed easily. In other words, they are on every box that has the Windows Firewall service installed, and **regardless of whether you have the Windows Firewall on or off**, they exist and are active. And yes, you read that right–there are firewall rules which are active even with Windows Firewall disabled. These
Windows Service Hardening rules are designed to only allow the services to accept traffic from the network sources the service is designed for.