List All Users in an Organisation’s Google Workspace Account with Google Apps Script

list all users in an organisations google workpsace account with google apps script

Note! This tutorial is for Google Workspace for organisations and not the free consumer account, unfortunately. 

While the Google Apps Script docs provide a great example of how to get a list of users in a Domain on a Google Workspace account, it is not in the scope of the documentation to go into the weeds and explain all the ways we can search for all users.

Weeds sound much more like the purview of a goat. A coding goat, perhaps 🐐. Me. I’m talking about me…yeesh!

In this tutorial, we will cover how to access your Google Workspace organisation’s user data, what data you can retrieve and how it looks, who can retrieve it and a couple of ways to display what you need.

This post is intended as a resource reference that compliments the Google Docs on the Admin SDK. Links to the Google documentation are provided throughout the post. It is worth a bookmark if you intend on using the Admin SDK a lot in Google Apps Script.

Use the contents page to navigate to what you need.

Setup

To access your organisation’s user data in Google Apps Script, you will need to use the Admin SDK Directory  Service. This is an Advance Service and will need to be enabled in your Google Apps Script console and you also need to ensure that it is enabled in your domain.

My recommendation is to first check to see if you can load and run a test script in your Google Apps Script IDE before bothering your organisation’s admin. However, because you will be dealing with user account data that you can view, add or remove, I would strongly recommend getting your admin’s permissions along with presenting them your plans before diving into your project.

Enable in the Editor

To do this click on the Services button in the editor sidebar (1). Then select the Admin SDK  (2) and click Add (3).

Enable Admin SDK in Google Apps Script Advanced Services
Click to Expand!

You will know that the Advanced Services has been added correctly when you see it appear in the sidebar.

Enable Admin SDK in Google Apps Script Advanced Services
Click to Expand

Enable on the Domain

If you also are your organisation’s administrator you can follow these steps. Likewise, you could forward this section to your Google Workspace admin team to save them the hassle of searching through the docs on your behalf. They will be eternally grateful for saving them the hassle.

Don’t worry, I will add links to the official docs too.

First, head to the Google Workspace admin console and sign in.  On the left-hand side select the Security button (1). This will expand a sub-menu where you can click API controls(2).

Enable Admin SDK on Google Workspace Admin Console V2
Click to Expand!

Your main window will update, and from here you can select the blue Manager Google Services in the main window.

Enable Admin SDK on Google Workspace Admin Console Manager Google Services

Scroll down the list of APIs until you find: Google Workspace Admin

Enable Admin SDK on Google Workspace Admin Console change access

Then select the option you are most comfortable with for your project. Most likely it will be unrestricted if you need other users to access a script with the Admin SDK. Or if there has been no radio button selected, it can be left blank and you can hit cancel.

Enable Admin SDK on Google Workspace Admin Console change access options

Once you or your Google Workspace admin have completed this step, head back to your project and give it a test run.

Keep in mind that even when you select one of these options there are two different access privileges to view the user’s full admin details and then what they show to the public. You may need your admin to provide you with some limited admin access if you are working in non-public user data.

Note! The information in the Docs under Setup Your API, I believe, is outdated (Well at the time of writing this 01 Aug 2021). You can check the last update of the doc in the bottom left of the page.

On with the show…

Getting the User Data

Get all user details in your org.

If you are trying to build an updated HR list on a Google Sheet or a dropdown list of all users in your domain, you are probably going to use some version of this code.

Check it out.

Getting your list of users

I’ve put this in a function for now because we will build this out in a moment. First, let’s take a quick look at lines 3-4. We start by calling the AdminDirectory service and then the Users resource. Inside this resource, we can use the ‘list’ method.

Now you can’t simply get a general list without adding an argument to the ‘list’ method.

Minimum Code

The very minimum you will need is to provide the customer property if you want all users across all domains in your Google Workspace’s organisation account. You can use the “my_customer” alias for your own account.

Alternatively, if you only want a particular domain in your account or you only have one domain in your account, you could replace customer with domain. Like this:

The result of either of these approaches will be a JSON object containing the following:

The 'kind' property describes the type of object that we have extracted. For us, this will be "admin#directory#users".

'etag' is the unique id of the resource that you have extracted.

'users' will be your main array of users in your domain or organisation and their associated data.

'nextPageToken' will provide a token if you have limited the number of 'users' you wanted to call from the Admin SDK by amount. If you are iterating through your full list at say, ten users at a time, each time you will get a new page token ID until there are no more users to review. In which case, you will get undefined. This is important when you need to draw from a list of users that will be greater than 100.

Just the user data

So the main thing we need to look at is the 'users' data to extract the information on each user that we need. This is a simple case of adding the 'users' property extension. Our new code will look like this:

Note that we grab the 'users' property after the list() methods on line 4.

This will provide us with our array of user data. By default, it will be in ascending order by the primary email address for each user.

Each user’s details can now be accessed in an array. For example, users[0] for the first user object in the array will contain an object of key-value data pairs about that user. Alternatively, the 'users' list can be iterated by using your preferred iteration method.

What data can I see?

As a developer with administrative privileges you will see something like the following results for each  user:

You can find a great detailed explanation of each of the properties in the docs or another example from Google’s Apps Script guide.

Getting User Data for Non-Admin Accounts

You can also set up your code so that non-users can get a limited list of information about each user in a domain. This approach will show user data that is publically available. This might be useful if you are providing a custom form in a Web App or a dialogue window when your users have a prefilled ‘select’ input.

Using this approach might solve access errors if you don’t have admin privileges when you are writing your code (No 100% sure here so if anyone can confirm, I will update this part).

To get a user…well…usable list, we can need to add the 'viewType' parameter and set it to 'domain_public'.

This will result in a much more limited list of information for each user:

Let’s keep this in our code from now on so it is a little easier to read.

Users are Greater Than 100

Out of the box, your list() method query will only display a max of 100 users that can be modified to 500 users per page.

Set your max user results for each list call.

You can set the number of users to be displayed by using the 'maxResults' query parameter. Without adding this query to your query object, your max results will automatically be capped at 100 users per page (or request to the Admin SDK). You can change this by adding this query to your query object. You can provide a value anywhere between 1 and 500 users to be displayed each time you call the list method.

If you have a number of users below the 'maxResults' amount, then it will only display that amount.

Here is what it will look like in our code example:

Personally, I think it would be a good approach to stick with 100 or fewer users per page. Any more and your request will take some time and may create a call error. It’s perhaps a flakey and overly cautious opinion, but there you go, I’m a flakey and overly cautious old goat.

Alternatively, if you have 1,000 users in your organisation and decide to set maxResults to something bonkers like 2 then you may end up with some more quota limitations.

Get the next page of users in your list

If you have more users than your 'maxResults', then you will need a way to access these users. You can do this with the 'nextPageToken' .  This is one of the main object properties that is on the same level as the 'users' and 'kind' property.

The 'nextPageToken' will store a token key for you that might look like this:

You can then use this token to reference the starting point of another call using the list() method.  This will give you the next set of 100 users in your domain or organisation. If you have over 200 users, then a new 'nextPageToken' will be available for you to reference.

Let’s give a very basic example to get the hang of using this token. Imagine we have 19 users in our organisation. We want to display these users in two sets so we will create a max result of 10 for each page.

Here on line 6, we have set the max results for our first page to 10. When we make this first call to the list() method, it will display a page token for the next page that we have stored in the pageToken variable on line 12.

Now the second time we call the list() method it will remember that page token and allow us to start our list from the 11th user if we add the pageToken query to our list of queries on line 16.

Note that if there are no more users in the organisation then the page token will be undefined, or not displayed in the object.

Looping through pages of users

Of course, it is all a bit silly for us to hard-code each time we want to call our next page. We are probably going to want to loop through each page until we run out of users and store our user data somehow.

Here we are going to create a version of Eric Koleda’s excellent example in the Google Apps Script version of the docs (Also a glaring reminder that I should be using do/while for more things 😁).

We use a while loop  here because we can easily state that when there are no more page tokens, we will stop our iterations. Using Javascript’s  do will allow us to carry out our first call to the list() method to get our first pageToken before starting our loop.

First off we will set some variables that we will update throughout our loop. Lines 3-5

Next, we will commence our do statement with our list() method call, not forgetting to add in the maxResults and pageToken queries this time. Line 8-13

Once we grab each page we will concatenate the user information to our staffList array container. Line 15

Then, we need to update the pageToken item so it can be read on the first iteration of the while loop. Line 17

Once we loop through all the pages we can return our staffList to do that voodoo that you do so well on.

Getting selected data from each user

Quite often you will not want to get all the data from each user. You will only want to store some of it. Let’s say we want to get a record of all of our users’ first names, last names and primary emails.

No worries.

All we need to do is loop through each member on our page and store just the data we require in a small object and return that to our staffList variable.

For convenience and ease of reading, we will use the JavaScript map() method to create a new object for each user and store the values in the staffMemeber variable. Then we will concatenate this to our staffList. Lines 16-22

The results of this function will look a little like this:

Dealing with optional user properties (schemas) in the Organisations property

Businesses can store a lot of useful information in the 'organizations' property – like the user’s job title, their department, their physical work location and even custom information fields that your admin has added for the organisation.

Single organisations

If your Google Workspace is set up with a single organisation then there will be only one item in the array of 'organizations'. However, sometimes not all users have been assigned to this one organisation. This is often the case for external consultants.

If we started searching for an item in the organisation then we will end up with an error.

Likewise, organisation information is not mandatory, so there may be some users who don’t have a property in their organisation and this will end up with an ugly undefined result.

We can fix all of this up with a bit of conditional handling.

Let’s say in addition to our first name, last name and email, we want to add the user’s job title… if they have one. We can find the job title in the users organisations under 'title'.

We will use some JavaScript ternary operators to hand any errors or undefined titles inline. Here is our updated code.

First, on line 22, we check that our user property contains the organizations child property. If it does, then we check the zeroeth item of the organisations list to see if it has the 'title' property (Line 23) if it does, then we want to grab that title. Otherwise, we want to return a blank string (Line 24).

User with multiple organisations

Sometimes large Google Workspace groups have multiple organisations assigned to them or the admin will separate the company into organisations by office location or child company. In some of these cases, a user might have a position under a number of these organisations.

If a user is assigned to multiple organisations they will always retain a primary organisation. This can be found, within the organisation’s property under 'primary'.

The primary organisation may not always be the first organisations in the users organisations list. In this case, we need too filter through our list of organisations and display only the primary organisation.

We could probably use an inline function here, but I think it will start to look a little messy and confusing. Let’s go ahead and reference a method inside our function instead.

It’s also gives us a good opportunity to create a universal organisation lookup tool.

Let’s say we want to access the job title for each user in their primary organisation. On line 22, we reference our newly built getUserOrgItem() method that takes two arguments, the currently iterated user object for each user and the property in the organisation list that we want to select. For us, this is the ‘title’ property.

Line 33-48. We kick off the function by changing out the ternary operator with a simple ‘if’ statement and check first if the user has an object property (Line 42).

If they do, then we can use JavaScript’s fairly recent addition to their awesome list of functional iterators the flatMap(). The flatMap() method can basically map through a set of data and then flatten it by one level. However, one of the benefits of this is that it can also be used like a map().filter() combo in one hit. Pretty cool, hey?

On line 42, our goal is to get the primary organisation object and store it in our primaryOrg variable. To do this we access our organisations’ list and apply the flatMap() method. This method takes a callback function that we have created in the form of an arrow function.

Next, we use a ternary operator to check if there primary property in each of the organisation objects in the list contains true. If it is true then we store that object. Finally, we extract it from the array it is in by accessing the zeroeth value.

On line 44, we then check to see if the title exists in the primary organisation object and if it does we return the title otherwise we return an empty string.

Finally, if no organisation property exists in the user object, then we just return an empty string.

Our result will then look like this:

Accessing Custom Fields (Schema)

Sometimes your administrator will add custom field attributes  (schema) into your user’s profiles. These schema parent categories have their  own fields. These schemas are not always visible when you call the list() method.

You can display ALL (full) or partial custom fields by using the projection query. 

Display all (FULL) custom fields

To display a full list of all your custom fields you apply the 'full' value.

Display Partial custom fields

You can also display a partial list of custom fields. You will need to call an additional query, customFieldMaskand set projection to custom. In the customFieldMask, you can provide a comma-separated (no spaces) list of all the schemas that you want to be displayed. Let’s  say we have two fields  that we want to access in the staffTraining schema hasCompletedInduction, coursesAttended. Here is what it would look like:

Note that using viewType:'domain_public' may also prevent you from seeing all the custom fields. So if you aren’t finding what you are looking for, try removing this option.

Accessing the custom field data

Your custom schema and associate field data will be found in your user’s object. You access it by calling the custom schema key name followed by the custom field.

Ordering and Sorting your Users Data

The Google Apps Script Admin Directory API allows you to use the query object to sort and order your data before you receive it.

By default, Google will sort your users alphabetically by primary email address.

You can change this behaviour with the ‘orderBy’ and ‘sortOrder’ queries. Here are your options:

  • orderBy:
    • ’email’
    • ‘familyName’
    • ‘givenName’
  • sortOrder:
    • ‘ascending’ (default behaviour)
    • ‘descending’

Note that the Admin Directory documentation displays capitalisation but in Google Apps Script, things are a little different.

Here is an example of the inclusion of these two queries:

Searching for Users using Parameters

The Google Admin Directory API provides an extensive tool for you to search for lists of users based on specific parameters.

You can use the 'query' parameter of the list query objects. Yeah…confusing. I know. Essentially, the object inside your list() method’s curly braces is a query parameter. Within this, is the 'query' parameter (It’s turtles all the way down 🤣).

The 'query' parameter takes one or more sets of searches. The docs on this are really extensive and clear here so I won’t go into too much detail except for providing a few Google Apps Script specific examples so that you can start experimenting on your own.

A successful query will return a list containing only those users that successfully met your search criteria. An unsuccessful query will result in an object with just the kind and etag properties.

A search query consists of three elements:

  1. Field: These are the searchable properties available to you. Note, that they don’t always match the property name in the users’ JSON object. It is best to find the corresponding field name in the docs. For example, if you  want to search by the first name then you would use the field givenName. Likewise, if you wanted to search by job title you would use the field orgTitle.
  2. Operator: This is how you want to query the field. You can use the following operators:
    1. =  (Equal to) Strings, numbers, dates and booleans.
    2. : (Contains text) Strings.
    3. :{PREFIX}* (Text starts with) String.
    4. :[{MIN,MAX}] (Field within a range) Numbers, dates.
    5. > (Greater than) Number date.
    6. >= (Greater than or equal to) Numbers and dates.
    7. < (Less than) Numbers and dates.
    8. <= (Less than or equal to) Numbers and dates.
  3. Value: These are the values you will use to search either as a complete value on its own or part of a range or a partial value, depending on the operator that you choose and the value type. Values can be strings, booleans, numbers or dates.

Writing a Query in Google Apps Script

A basic example of applying a query to your Admin Directory List method would be something like this:

In this example, we have run a search for anyone in our Google Workspace account with the title ‘Goat’.  You can still also apply other queries to the list object like orderBy or viewType.

Searching Custom Fields in Custom Schema

To search a custom field in a custom schema you can reference the schema followed by the field ID. For example:

 

Let’s go into more detail for each of the value types.

Text (String)

Any of our user properties that have a string value like text, email or phone numbers can be searched if they have a corresponding field reference or custom schema found in the search docs.

Search equals

Let’s say we want a list of everyone in the same “Finance” department then we could run the following query:

There are a couple of things to note here. First, the entire query is encapsulated in a text string. You can use single quotation marks, double quotation marks or backticks for this.

Spaces count. If you don’t have any leading spaces in our search, do not add them. Ensure there are no spaces between your query field, your operator and your query.

Queries are not case sensitive. You can use upper or lowercase (like in the example) to get the same result.

Spaces and Apostrophies (‘)

Let’s say you have a search query to find all of your organisation’s staff who are in a particular location. Here we will use the addressLocality field to search for the same town or city. We will call our town, ‘Tragos Landing’.

Spaces in the query announce a new query so we will need to find a way around this.

There are generally three approaches:

  • Replace your spaces with a”+” symbol.

  • Change your string encapsulator from a single quotation (') to double quotations (") or backticks (`).

  • Escaped single quotation marks. If you are a devout single quotation acolyte and simply must use them (weirdo), you can escape them.

You can also use the escape method to escape apostrophes. Let say our location is now ‘Yagi’s Place’. Our query would look like this.

Search contains

The Search contains (:) query allows you to search a selected field in each of your users for a set of text that contains a certain value.

Let’s say we want to query all the users with ‘Manager’ or ‘Managing’ in their job title.

This might result in a list containing titles like this:

  • Managing Director
  • Feed Manager
  • Manager
  • Management Relations

Note that the search text can appear anywhere in the user’s field value.

Starts with

We can modify the text contains operator by appending some text with the wildcard symbol (*), :{PREFIX}*.  Let’s say we want to search to all the names of our users that start with ‘La’:

This may result in a list of users like:

  • Lauren
  • Lance
  • Larry

…but not, Blake, because the ‘la’ contained in the name is not at the start.

Boolean

Boolean values (true or false) can be found in the following fields:

  • isAdmin
  • isDelegatedAdmin
  • isSuspended
  • isEnrolledIn2Sv
  • isEnforcedIn2Sv
  • or any custom schema that your admin has assigned a boolean value.

We can only apply the equal to (=) operator to boolean fields. A boolean query would look like this:

Number

There are no number values in the standard user fields. However, your administrator may have created a custom user field with a value.

Equals

You can search for the exact number in a field by user with the equals (=) operator:

As you can see, you can add fractions of numbers but must use a decimal (.) indicator (sorry half of Europe). Also, make sure you leave out the thousand separators. For example, 1,234 is bad, but 1234 is good.

greater and less than (or equal to) number

You can use standard greater than (>) and less than (<) symbols and include optional (=) to search for a range above (and or equal to) or below a value.

Between two numbers

You can also search for numbers between two values by using the min-max operator, :[{MIN},{MAX}].

Date

Dates use the same greater than, less than, equal to and between operators as numbers.

When running a search by date you should write your dates as follows:

Year-Month-day

YYYY-MM-DD

For example,

2020-07-11

greater and less than (or equal to) Date

You can use standard greater than (>) and less than (<) symbols and include optional (=) to search for a range above (and or equal to) or below a date.

Between two Dates

You can also search for numbers between two values by using the min-max operator, :[{MIN},{MAX}].

Query Limitations

Query search field items are pretty extensive, but there might be one or two that cannot be searched in this way. For example, you can’t search for the account creation date using this approach. You may have to first grab all the users and run a query with Google Apps Script.

Query also does not support OR conditional queries. So in this instance, you would be better off collecting all the user data and running your own iterative search in Google Apps Script and not from the Admin SDK.

Multiple Conditions (AND)

You can add multiple search fields to a query by separating them with a space.

Let’s say we want to search for all user accounts that are suspended from the location Tragos Landing.

Or, how about we query all users whose surname start with ‘Mu’ who have completed on-site safety training (Custom field:date) after Sep 19 2019.

Getting details on one user

While you could definitely use the query approach to get specific information from a single user, the Admin Directory SDK has a specific method for getting data from a single user.

You can use the ‘get’ method on the Users resource to access an individual user by the user’s primary or alias email addresses or their primary user ID. Ironically, you would probably use the ‘get’ or ‘list’ method to get the user’s ID. So we will just stick with emails in this example.

Here is what our Google Apps Script Admin Directory call would look like:

Pretty simple.

The ‘get’ method also takes an optional second query object that we can add some familiar parameters to:

  • customFieldMask
  • projection
  • viewType

Let’s get a little wild here and use all three in one go.

via GIPHY

 

Here we are getting the user’s details that are available to the public. If the project’s custom schema is public then we should be able to see the data for the ‘releaseparty’ and ‘dancers’ custom schemas.

Who says we never have any fun.

Conclusion

The goal of this article was to provide a reference tool for Google Apps Script users who are accessing users with the Admin Directory SDK.

To be honest, this post was going to be a short one, but then I realised the benefit of having a full breakdown of how to use the list() method. While the Google Docs on the Admin SDK are detailed, they appear to be more focused on other runtimes and external access within Python, Java or node.js.

Hopefully, this tutorial will clear up some of the confusion for the Google Apps Script user and can be used as a reference tool in conjunction with the approved Google Docs.

Let me know if I missed anything out that is important or if something has changed in a recent update and I will try and keep this page as relevant as possible.

Looking to learn more about Google Apps Scripts in a more structured format? Udemy has some great courses that can get you from the basics to a real Google Apps Script pro!

Got a more specific problem you need help with, but don’t have the time to develop the skills? Make an enquiry on my ‘Hire me!’ page. I occasionally pick up projects. Alternatively, Fiverr’s your best bet to find a skilled Google Apps Script developer to solve your problem quickly and professionally. *

*The above affiliate links have been carefully researched to get you to what you specifically need. If you decide to click on one of these links it will cost you just the same as going to the site. If you decide to sign up, I just get a little pocket money to help pay for the costs of running this website.

Leave a Reply