Using a gMSA account with AADConnect

If you haven’t heard of a gMSA, you haven’t lived. That’s what my Mum tells me anyway.

A gMSA is also known as a Group Managed Service Account, and it really is the future of Service Accounts. It doesn’t allow interactive logons, it recycles it’s credentials automatically and can also be tied down so it can only be used on specific hosts. Most importantly it is recommended if you use Azure AD Connect with a dedicated SQL Server.

It does require Server 2012 or above on your domain controllers (for the schema extensions) and an Azure AD Connect server, but if you aren’t using this OS or newer yet, then I think you have other priorities you need to address ūüôā

So the big question is; how do we use this magical feature? The guide below is for a new installation of AADConnect.

Firstly, if you haven’t done so already you need to enable the KDS Root Key ūüĒź required for generating the passwords¬†used by the service account. Run this PS Command from an AD Powershell prompt to enable the KDS Root Key ūüĒź. This can be done from a Domain Controller or from a server running RSAT ADDS tools.

Add-KdsRootKey ‚ÄďEffectiveImmediately

Funnily enough, even though we used -EffectiveImmediately, it is only available instantly on the DC you ran the command from. The other DC’s need to wait for replication to complete for the key to be available.

You then need to create the AAD Connect gMSA service account. Use this PS command to do this:

New-ADServiceAccount -Name AADC-gMSA -Description "AAD Connect Service Account" -DNSHostName aadc.Contoso.com -PrincipalsAllowedToRetrieveManagedPassword MGMT01$,MGMT01$ -Passthru

Replace the sections in red with your own information. MGMT01 and MGMT02 are the names of our primary and staging AAD Connect servers in this instance, and the DNSHostName parameter essentially sets a DNS name of the service we are running.

Once this is done, you need to head over to your AAD Connect server and add the account using:

Install-ADServiceAccount AADC-gMSA

Lastly, during AADConnect installation, we need to select the service account. During initial installation, choose the ‘Customise’ option as shown below:

Screenshot 2019-05-21 at 16.55.44

And then select ‘Use an existing service account’ and enter the service account name using the domain\accountname$ format.

Screenshot 2019-05-21 at 16.57.43

This process will help you automate and secure your service accounts in the future, and is a great choice whenever a service account is required and gMSA is supported.

 

 

Use PowerShell to report on Azure AD Enterprise Application Permissions

Many Microsoft customers are now taking steps to try and modernise and centralise SaaS app identity by using Enterprise Applications within Azure AD to provide authentication, provisioning and reporting services.

This can be done by Administrators by adding applications into the AzureAD tenant and assigning users to them, or by Users (if you let them) who can self-service applications (think the Log in with Facebook / Google buttons). Applications which are added will have certain permissions assigned which will allow said application to be able to access AzureAD properties via the Microsoft Graph API.

These permissions can be as simple as allowing the application to read the users displayname, all the way to having full access to all files which the user can access in Office 365. You can see these permissions in the GUI by logging onto portal.azure.com and navigating to Azure Active Directory>Enterprise Applications>Application Name>Permissions, as seen in the screenshot below. We can see that the Adobe Document Cloud application has had Admin consent to have full access to all files the user can access, and to sign in and read user profile. You can see the full range of available permissions in the Microsoft Graph, and what they all mean here.

perms

This GUI feature is great for looking at individual applications, but if you are allowing users to provide consent themselves, or you are making full use of the Enterprise Applications feature, you are likely to have many applications listed here, and checking them one by one using the GUI is not efficient.

As always, PowerShell is able to come to the rescue. If we connect to the AzureAD v2 Powershell module by using Connect-AzureAD, we can export these permissions. Unfortunately, because of the way the data is presented, we need to do a little data massaging to make this possible.

Firstly, we need to get a list of all applications, and this can be done using:

Get-AzureADServicePrincipal | Select DisplayName,Homepage,ObjectID,AppDisplayName,PublisherName,
ServicePrincipalType | Export-Csv c:\reports\azureadsp.csv

This PS command will get a list of all the Service Principals (read: applications) you have configured, however it will not list the permissions. We need another cmdlet for that. The item we are most interested in for the Service Principal is the ObjectID, as this is the value we can use to map the Service Principal to the Permissions.

The next PS command we need is:

Get-AzureADOAuth2PermissionGrant | Select ClientID,Scope,ConsentType | Export-CSV :\oaauthperms.csv

This PS command will get a list of all the permissions granted in AzureAD. The important value here is the ClientID, which refers to the application, and the Scope, which refers to the permission level as described in the Graph Permissions article.

With this data we have two .csv files, and we need to compare the ObjectID from azureadsp.csv with the ClientID from oauthperms.csv. If we find a match, we need to copy the Now I’m no Excel expert, and there are probably better ways of doing this, but this was my method.

I copied the columns from azureadsp.csv into the oauthperms.csv. Let’s say the ObjectID value from azureadsp.csv ended up on row J. I would then create a new column called Application Name, at column A. I then used the INDEX, MATCH formula to look for identical ObjectID and ClientID values, and if a match was found, populate the Application Name.

indexmatch

The formula used looks like this:

=INDEX($H$2:$H$101,MATCH($B2,$J$2:$J$101,0))

Substituting the column names for logical names looks like this:

=INDEX($DisplayName$2:$DisplayName$101,MATCH($ClientID2,$ObjectID$2:$ObjectID$101,0))

This gives us a value in Application Name which shows us the application which has been given rights to the Microsoft Graph and can enable us to easily see and filter which permissions have been given to which application. This can be used for management purposes, reporting and security auditing.

Hopefully this is useful for you, and if you think this could be improved upon please let me know in the comments!

Virtual Machine Core Count – Azure

Today is not the first time I have come across this issue, but I’m going to make sure it’s the last time I google how to find out the limits applied to an Azure subscription!

By default, different VM soft limits apply to different types of subscriptions. If you come across this issue, your error will look something like this:

New-AzureRmVM : Operation results in exceeding quota limits of Core. Maximum allowed: 10, Current in use: 10

From memory (this may not be correct), the limits are as follows for different subscription types:

  • Pay as you go – 10 cores per VM type / region
  • CSP – 30 cores per VM type / region
  • VL – 20 cores per VM type¬†/ region
  • EA – I’m not sure!

If you want to see how many cores you are allowed by default, you need to login to Azure Powershell and run the following command, substituting your region.

Get-AzureRMVMUsage -Location "West Europe"

This will give you an output similar to below:

PS C:\WINDOWS\system32> Get-AzureRmVMUsage -Location "West Europe"

Name                         Current Value Limit  Unit
----                         ------------- -----  ----
Availability Sets                        3  2000 Count
Total Regional Cores                    10    10 Count
Virtual Machines                         8 10000 Count
Virtual Machine Scale Sets               0  2000 Count
Standard Av2 Family Cores               10    10 Count
Basic A Family Cores                     0    10 Count
Standard A0-A7 Family Cores              0    10 Count
Standard A8-A11 Family Cores             0    10 Count
Standard D Family Cores                  0    10 Count
Standard Dv2 Family Cores                0    10 Count
Standard G Family Cores                  0    10 Count
Standard DS Family Cores                 0    10 Count
Standard DSv2 Family Cores               0    10 Count
Standard GS Family Cores                 0    10 Count
Standard F Family Cores                  0    10 Count
Standard FS Family Cores                 0    10 Count
Standard NV Family Cores                 0    12 Count
Standard NC Family Cores                 0    12 Count
Standard H Family Cores                  0     8 Count
Standard LS Family Cores                 0    10 Count
As you can see, for each region there is a subset of machine types. If you need to raise a core limit, you need to raise an Azure support ticket and request an increase for the required region and VM type. This does not cost anything and from my experience is usually done within 24 hours.
Hopefully this helps some folk out there who come across this issue. If you haven’t seen this yet and are planning an Azure rollout, it would be worth requesting this increase prior to starting your project!

Azure AD Powershell – Token Lifetime Configuration for MFA

The default token expiry in Azure AD for ADAL clients (using Modern Authentication) is 14 days for single factor and multi factor authentication users. This can stretch up to 90 days as long as the user does not change their password, and they do not go offline for longer than 14 days.

This means that clients using Outlook or Skype for Business can perform MFA once and then remain signed in using their access token for up to 90 days before being required to authenticate using MFA. As you can imagine, this is not an ideal situation for multi-factor authentication as a compromised account could be accessed through a rich client application with no MFA for up to 90 days.

Until recently, this could not be modified. However Microsoft released Configurable Token Lifetime as a Preview feature quite recently. This allows for various properties to be controlled, giving administrators more granular control over token refresh and enforcing a more secure MFA policy.

The Azure team have provided a solid guide here: https://docs.microsoft.com/en-us/azure/active-directory/active-directory-configurable-token-lifetimes

To do this, you need the Azure AD Preview PowerShell module. Install this by running the following from a PowerShell prompt:

Install-Module -Name AzureADPreview 

Here is a sample policy I’ve configured which will change the MFA token lifetime to 12 hours. I’ve combined this with ADFS Claim Rules which only enforce MFA if the user is on the extranet and using particular applications:

New-AzureADPolicy -Definition @("{`"TokenLifetimePolicy`":{`"Version`":1, `"MaxAgeMultiFactor`":`"12:00:00`",`"AccessTokenLifetime`":`"04:00:00`"}}") -DisplayName OrganizationDefaultPolicyScenario -IsOrganizationDefault $true -Type TokenLifetimePolicy

This is  a much needed feature from the point of view of security controls, although keep in mind it is still in Preview!

 

 

Script – control Client Access features using set-mailbox

I put together a short script recently which will enumerate all users in an Office 365 Group (Security/Distribution/O365Group) and disable certain Client Access features. In my case, I wanted to disabled IMAP, POP and MAPI connectivity. This leaves a user only able to perform Kiosk style connectivity through either OWA, EWS or ActiveSync. The users in question had E1 licenses, but the customer wanted to limit connectivity so that rich mail clients such as Outlook could not be used.

The script looks like this:

$group=Get-MsolGroup | Where {$_.DisplayName -eq "uk-dg-kiosk"}
$groupid=$group.ObjectId
$groupmembers=Get-MSOLGroupMember -GroupObjectId $groupid
ForEach ($member in $groupmembers.emailaddress)
{Set-CASMailbox $member -ImapEnabled $false -MAPIEnabled $false -PopEnabled $false}
ForEach ($member in $groupmembers.emailaddress)
{Get-CASMailbox $member}

I have also created a similar script which will apply to any user which has a particular license SKU:

$licensepack=Get-MsolUser -All | Where {$_.Licenses.AccountSKUId -ccontains "MISSTECH:ENTERPRISEPACK"}
ForEach ($user in $licensepack.userprincipalname)
{Set-CASMailbox $user -ImapEnabled $false -MAPIEnabled $false -PopEnabled $false}
ForEach ($user in $licensepack.userprincipalname)
{Get-CASMailbox $user}

This could be run on demand, or using a scheduled task. Using a scheduled task involves supplying credentials so be careful when you do this!

Have a look at my guide for setting up scheduled tasks with Office 365 to learn how to avoid using plain text passwords in your tasks: https://misstech.co.uk/2016/06/08/office-365-powershell-and-scheduled-tasks/

Till next time x

 

How many users are in my AD group?

Nice simple three liner here. I often want to check how many users are in a particular group, and find it a bit annoying that ADUC doesn’t show this in the Group Properties. So to find out, run this from a Powershell window on a DC:

Import-Module ActiveDirectory
$group = Get-ADGroupMember "group name" -recursive | Select-Object name
$group.count

The second line puts all the members into a variable called $group, and if you didn’t already know, putting .count after any variable will enumerate the objects in that variable ūüôā

Happy days!

Add X500/X400/SMTP address for a list of users

This process can be reused to add (not overwrite, just append) any type of email address to a list of users. All you need is a simple CSV file with 2 rows, SamAccountName and the new email address. The example I’ve used is an X500 address, but this could be X400: or SMTP. Remember when adding an SMTP address, case sensitivity matters!

smtp:bruce.wayne@wayneenterprises.co.uk = secondary email alias
SMTP:batman@batcave.co.uk = primary email address

SAM EMAIL
brucewa X500:/O=WAYNE ENTERPRISES/OU=First Administrative Group/cn=Recipients/cn=brucewa
harleyqu X500:/O=WAYNE ENTERPRISES/OU=First Administrative Group/cn=Recipients/cn=harleyqu
poisoniv X500:/O=WAYNE ENTERPRISES/OU=First Administrative Group/cn=Recipients/cn=poisoniv

Once you have your lovely CSV file in a location on the Exchange server, crack open the Exchange Management Shell and run this command:

Import-Csv C:\migration\x500.csv | ForEach-Object{
  $name = $_.SAM
  $proxy = $_.email
  Set-Mailbox -Identity $name -EmailAddresses @{add= $proxy}
}

Tada!