Filtering users and groups with the Azure AD (Graph) ODATA syntax

Regardless of the fact that the Azure AD PowerShell module hasn’t gotten any love from Microsoft in the past few months, Office 365 administrators should start embracing it and replacing their old MSOL-based scripts. It is the only module Microsoft will support in the future, so there’s no way going around that.

One of the biggest issues with the Azure AD module however is it’s poor ‘usability’ or ‘friendliness’. The module is not designed with the regular Joe in mind, it’s more of a simple exercise of wrapping up some Graph API queries with PowerShell syntax. Thus, we are forced to live with GUIDs, JSON formatting and most importantly, the lack of  proper filter syntax.

Yes, the Graph does offer filtering capabilities. Yes, they suck. No other way of putting that. Still, they do exist and can be used in some cases, with mixed results. In this article I will provide few examples, for future references.

First of all, there is some documentation on the filtering syntax here. Only a handful of examples are provided however, and no detailed explanations are given.

Let’s start with some simple examples. To list all users from a particular department or country, use the following syntax:

Get-AzureADUser -Filter "Department eq 'HP'"
Get-AzureADUser -Filter "Country eq 'BG'"

The eq operator was used for string comparison, and the corresponding string was enclosed in single quotes. If you want to compare against a Boolean property, no quotes should be specified, instead use true or false. For example, to list all disabled accounts:

Get-AzureADUser -Filter "AccountEnabled eq false"


Note that while property names (such as AccountEnabled) and string values are NOT case-sensitive, the Booleans are, so make sure to enter them exactly as lowercase true or false. Null values are NOT supported, which is a very unfortunate limitation. Neither is the not equal statement. All those lovely limitations make impossible to simply filter out any synchronized accounts or similar. Annoying!

But wait, it gets even better. The startswith operator can be used to do a wildcard searches, so for example list all accounts that have Vasil in their display name:

Get-AzureADUser -Filter "startswith(displayName,'vasil')"

Cool. Now try any of the below:

Get-AzureADUser -Filter "startswith(DisplayName,'vasil')"
Get-AzureADUser -Filter "Startswith(displayName,'vasil')"

Yes, now things are starting to get case-sensitive. Don’t you just LOVE programmers? 🙂 Oh, and moreover, endswith is NOT supported.

Anyway, off to some more useful examples. We can combine filters using the and and or operators. For example, list all groups that are both mail-enabled and security-enabled:

Get-AzureADGroup -Filter "SecurityEnabled eq true and MailEnabled eq true"
Get-AzureADUser -Filter "Department eq 'Finance' or Department eq 'Marketing'"

Lastly, there’s the any of operator, which is used to compare against multi-valued properties. For example, if I want to check which user has a particular proxyaddress configured, I could use:

Get-AzureADUser -Filter "proxyAddresses/any(c:c eq '')"

In case you are wondering about the funky capitalization of proxyAddresses – you’ve guessed it, it’s the only way it will actually work. As another example, we can list any proxy addresses starting with particular string:

Get-AzureADUser -Filter "proxyAddresses/any(y:startswith(y,'smtp:gosho'))"

This query will return all users that have any of their proxyaddresses starting with ‘gosho’. The next logical thing to try is to filter them by domain. Not possible sadly, as we don’t yet have support for the endswith operator…

While the “lambda” operators any/all are certainly useful, there are other limitations of the Graph that make them irrelevant:

Code: Request_UnsupportedQuery
Message: Complex query on property provisionedPlans is not supported.
Message: Complex query on property assignedPlans is not supported.

Anyway, I think I had enough of crappy syntaxes for now. Let me know if this was useful and if you have worked out some fancier examples.

Additional information about the OData syntax can be found here.

Posted in Azure AD, Office 365, PowerShell | Leave a comment

Access Reviews for group membership and assigned applications in Azure AD

The Access Reviews feature was recently introduced over at the EMS blog, and is now available in Preview. It’s an easy to use feature that allows for self-service management of group membership across distribution groups, security groups and Office 365 Groups, as well as application access. Well, self-service perhaps isn’t the correct word here, as the review needs to be triggered and the results applied by an administrator, but still, major parts of the process can be offloaded to the actual members of the group, thus there is no need for the admin to chase each of them individually.

In the future, Microsoft is planning to expand this feature to cover the full Guest user lifecycle, provide scheduling capabilities and programmatic access. Perhaps they might also address some of the shortcomings of the feature, such as the lack of support for dynamic groups and some of the “first-party” apps, and most importantly, the heavy price tag of the Azure AD Premium P2 license.

Read the full article here.

Posted in Azure AD, Office 365 | Leave a comment

Client Access Rules for Exchange Online

The wait is over – one of the most requested features has finally hit my tenant. Namely, Client Access Rules, or the functionality that allows us to control access to Exchange Online based on location, protocol and authentication type.

Sadly I still don’t have CARs across all my tenants, but it’s enough to give the feature a quick test. Let’s go.

First of all, managing of Client Access Rules is all done via PowerShell. This in turn means you need to be very careful not to block PowerShell access, or you will be forced to place an awkward support call 🙂 I would strongly advise you to review the documentation before creating any Client Access Rule!

Assuming you’ve familiarized yourself with the process, you can fire up a connection to Exchange Online PowerShell and create your first CAR. The example I used was to block access to OWA externally – something that was not possible until now, even in federated scenarios, unless you were willing to sacrifice some other functionalities, or to use Azure AD Conditional access. Here’s how the rule looks like:

New-ClientAccessRule -Name "BlockOWAExternal" -AnyOfProtocols OutlookWebApp -ExceptAnyOfClientIPAddressesOrRanges DenyAccess

Once you have created the rule, you will have to wait for a while for it to take effect. Both the documentation and the actual PowerShell cmdlet will warn you about this, however in my case the rule started working almost immediately. Here’s how the experience looked like for any external attempt to open OWA:

The message shown above can use some improvements, but it should give the user and admin enough information to understand what the cause is. Now, because I’ve only blocked external access to OWA (in other words I used an exception in the CAR above), I can work with it just fine when I’m using an “internal” device.

The Test-ClientAccessRule cmdlet can be used to verify that the rule you created works as expected. Here’s an example:

Test-ClientAccessRule -User -AuthenticationType BasicAuthentication -Protocol OutlookWebApp -RemoteAddress -RemotePort 443

Identity         Name             Action
--------         ----             ------
BlockOWAExternal BlockOWAExternal DenyAccess

Another important thing to note is that while multiple rules can exist in the tenant, rule processing stops once a match occurs. That means that you need to carefully manage the rule priority in order to make sure the set of rules you have created will have the desired effect, and the Test-ClientAccessRule cmdlet proves invaluable here. Make sure to set the allow rules with higher priority and also add exceptions as necessary!

Other examples of things you can do with Client Access Rules include:

  • Blocking access to protocols such as IMAP or POP
  • Blocking access based on the IP address of the client
  • Blocking access based on authentication type – yes, you can block Basic auth!
  • Blocking access based on group membership
  • Blocking access based on recipient filter – for example all users in the HR department
  • Adding Exceptions for all the above (except the filter one)

For additional examples, refer to the cmdlet help here:

Posted in Exchange Online, Office 365, PowerShell | Leave a comment

First version of Microsoft Teams PowerShell module is now available

Today, the good folks at Microsoft released (an early preview version of) the Teams PowerShell module. The module has been one of the common asks from Office 365 admins, as PowerShell is the tool of choice when it comes to automation.

Do not get overexcited though, this is an initial release, not even in GA status. There are not many cmdlets available (23 to be precise) and lots of issues. Still, if you want to give it a try, you can download the module from the PowerShell Gallery here:

Here’s the full list of cmdlets:

[20:03:22][O365]# Get-Command -Module MicrosoftTeams

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Add-TeamUser                                       0.9.0      MicrosoftTeams
Cmdlet          Connect-MicrosoftTeams                             0.9.0      MicrosoftTeams
Cmdlet          Disconnect-MicrosoftTeams                          0.9.0      MicrosoftTeams
Cmdlet          Get-Team                                           0.9.0      MicrosoftTeams
Cmdlet          Get-TeamChannel                                    0.9.0      MicrosoftTeams
Cmdlet          Get-TeamFunSettings                                0.9.0      MicrosoftTeams
Cmdlet          Get-TeamGuestSettings                              0.9.0      MicrosoftTeams
Cmdlet          Get-TeamHelp                                       0.9.0      MicrosoftTeams
Cmdlet          Get-TeamMemberSettings                             0.9.0      MicrosoftTeams
Cmdlet          Get-TeamMessagingSettings                          0.9.0      MicrosoftTeams
Cmdlet          Get-TeamUser                                       0.9.0      MicrosoftTeams
Cmdlet          New-Team                                           0.9.0      MicrosoftTeams
Cmdlet          New-TeamChannel                                    0.9.0      MicrosoftTeams
Cmdlet          Remove-Team                                        0.9.0      MicrosoftTeams
Cmdlet          Remove-TeamChannel                                 0.9.0      MicrosoftTeams
Cmdlet          Remove-TeamUser                                    0.9.0      MicrosoftTeams
Cmdlet          Set-Team                                           0.9.0      MicrosoftTeams
Cmdlet          Set-TeamChannel                                    0.9.0      MicrosoftTeams
Cmdlet          Set-TeamFunSettings                                0.9.0      MicrosoftTeams
Cmdlet          Set-TeamGuestSettings                              0.9.0      MicrosoftTeams
Cmdlet          Set-TeamMemberSettings                             0.9.0      MicrosoftTeams
Cmdlet          Set-TeamMessagingSettings                          0.9.0      MicrosoftTeams
Cmdlet          Set-TeamPicture                                    0.9.0      MicrosoftTeams

Unfortunately, many of the cmdlets don’t seem to work as expected, and the ones that do require you to use GUIDs in order to reference the TeamID, so the experience can definitely be improved. But hey, it’s a first step, and it does allow some cool stuff even in this crippled state.

For example, here’s how to view and change some of the Team settings.

[20:16:11][O365]# Get-TeamMemberSettings -GroupId c7442983-e654-40b1-a73b-fef16f6a88e6

AllowCreateUpdateChannels         : True
AllowDeleteChannels               : True
AllowAddRemoveApps                : True
AllowCreateUpdateRemoveTabs       : True
AllowCreateUpdateRemoveConnectors : True

In case you don’t want to type in GUIDs, this variation will do:

[20:16:17][O365]# Get-TeamMemberSettings -GroupId (Get-MsolGroup -SearchString TeamOne).ObjectId

AllowCreateUpdateChannels         : True
AllowDeleteChannels               : True
AllowAddRemoveApps                : True
AllowCreateUpdateRemoveTabs       : True
AllowCreateUpdateRemoveConnectors : True

To prevent users from adding or removing connectors, use:

[20:17:08][O365]# Set-TeamMemberSettings -GroupId (Get-MsolGroup -SearchString TeamOne).ObjectId -AllowCreateUpdateRemoveConnectors $false
[20:17:51][O365]# Get-TeamMemberSettings -GroupId (Get-MsolGroup -SearchString TeamOne).ObjectId

AllowCreateUpdateChannels         : True
AllowDeleteChannels               : True
AllowAddRemoveApps                : True
AllowCreateUpdateRemoveTabs       : True
AllowCreateUpdateRemoveConnectors : False

We can confirm that the changes are made via the UI as well:

Expect additional examples and more details as the module matures 🙂

Posted in Office 365, PowerShell | Leave a comment

Connecting to both ExO and SCC using the MFA-enabled PowerShell module

There seems to be an unfortunate issue with the recently updated Exchange Online PowerShell module that brings support for Modern authentication for the Security and Compliance Center cmdlets. Namely, the script’s Connect-EXOPSSession function, used to establish the connectivity for both the ExO and SCC parts, clears out every remote session upon execution.

In effect, this means that you cannot use the module to connect to both ExO and SCC remote PowerShell sessions at the same time. Any existing sessions are simply removed upon connecting to a new one. Or illustrated with a picture:

As the Connect-IPPSSession cmdlet calls the Connect-EXOPSSession one upon execution, the order in which you connect to both will not matter. If you want to connect to both session, you will have to use separate PowerShell instances. Or, make some changes to the underlying script (edit/comment line 173).

Alternatively, you can load the necessary module functions in your scripts and bypass the execution of the Connect-EXOPSSession cmdlet. I’ve alerted the corresponding teams at Microsoft so hopefully this hiccup will get looked at soon.

Posted in Exchange Online, Office 365, PowerShell | 2 Comments