7.08.01

Added option `shareddrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))` to
`gam print shareddriveorganizers` that displays organizers for a specific list of Shared Drive IDs.

7.08.00

Added the following command that can be used instead of the `GetTeamDriveOrganizers.py` script.

```
gam [<UserTypeEntity>] print shareddriveorganizers [todrive <ToDriveAttribute>*]
        [adminaccess|asadmin] [shareddriveadminquery|query <QuerySharedDrive>]
        [orgunit|org|ou <OrgUnitPath>]
        [matchname <REMatchPattern>]
        [domainlist <DomainList>]
        [includetypes <OrganizerTypeList>]
        [oneorganizer [<Boolean>]]
        [shownorganizerdrives [false|true|only]]
        [includefileorganizers [<Boolean>]]
        [delimiter <Character>]
```
The command defaults match the script defaults:
* `domainlist` - All domains
* `includetypes` - user,group
* `oneorganizer` - False
* `shownoorganizerdrives` - True
* `includefileorganizers` - False

For example, to get a single organizer from your domain for all Shared Drives including no organizer drives:
```
gam redirect csv ./TeamDriveOrganizers.csv print shareddriveorganizers domainlist mydomain.com includetypes user oneorganizer shownoorganizerdrives
```

7.07.17

Added option `oneuserperrow` to `gam print devices` to have each of a
device's users displayed on a separate row with all of the other device fields.

7.07.16

Added `chromeostype`, `diskspaceusage` and `faninfo` to `<CrOSFieldName>` for use in `gam info|print cros`.

Fixed bugs/cleaned output in  `gam info|print cros`.

7.07.15

Added option `shareddrivesoption included|included_if_account_is_not_a_member|not_included` to `gam create vaultexport`.

The previous option `includeshareddrives <Boolean>` is mapped as follows:
* `includeshareddrives false` - `shareddrivesoption included_if_account_is_not_a_member`
* `includeshareddrives true` - `shareddrivesoption included`

7.07.14

Update `gam setup chat` output to include the following that shows the actual Cloud Pub/Sub Topic Name.
```
You'll use projects/<ProjectID>/topics/no-topic in Connection settings Cloud Pub/Sub Topic Name
```

7.07.13

Added option `showitemcountonly` to `gam [<UserTypeEntity>] print|show shareddrives` that causes GAM to display the
number of Shared Drives on stdout; no CSV file is written.

7.07.12

Fixed bug in `gam print|show oushareddrives` that caused a trap.

Improved getting Shared Drive names from IDs when accessing Shared Drives in external workspaces.

7.07.11

Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`
to handle the following error:
```
ERROR: 400: badRequest - Bad Request
```

Updated `gam <UserTypeEntity> move drivefile` to handle the following error:
```
ERROR: 400: shareOutNotPermitted
```

7.07.10

Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`
to handle the following error:
```
ERROR: 400: eventTypeRestriction - Attendees cannot be added to 'fromGmail' event with this visibility setting.
```

7.07.09

Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`
to handle the following error:
```
gamlib.glgapi.serviceNotAvailable: Authentication backend unavailable.
```

7.07.08

Fixed bug in `gam <UserTypeEntity> print filelist ... countsonly` that issued an
incorrect warning message like the following when `redirect csv <FileName> multiprocess` was specified.
```
WARNING: csv_output_row_filter column "^name$" does not match any output columns
```

7.07.07

Fixed bug in `gam report <ActivityApplictionName> ... countsonly eventrowfilter` that issued an
incorrect warning message like the following when `redirect csv <FileName> multiprocess` was specified.
```
WARNING: csv_output_row_filter column "^doc_title$" does not match any output columns
```

7.07.06

Added option `eventrowfilter` to `gam calendars <CalendarEntity> print events ... countsonly`
and `gam <UserTypeEntity> print events <UserCalendarEntity> ... countsonly` that causes
GAM to apply `config csv_output_row_filter` to the event details rather than the event counts.
This will be useful when `<EventSelectProperty>` and `<EventMatchProperty>` do not have the
capabilty to select the events of interest; e.g., you want to filter based on the event `created` property.

Dropped the extraneous `id` column for `gam calendars <CalendarEntity> print events ... countsonly`
and `gam <UserTypeEntity> print events <UserCalendarEntity> ... countsonly`.

7.07.05

Updated `gam <UserTypeEntity> move drivefile` to recognize the API error: `ERROR: 400: shareOutWarning`.

7.07.04

Updated `gam create vaultexport ... rooms <ChatSpaceList>` to strip `spaces/` from the Chat Space IDs.

Updated `gam <UserTypeEntity> copy drivefile` to recognize the API error: `ERROR: 400: shareOutWarning`.

7.07.03

Updated `gam create vaultexport` to allow allow specifying a list of items in a search method
with `shareddrives|rooms|sitesurl select <FileSelector>|<CSVFileSelector>`.

7.07.02

Fixed bug in `redirect csv ... transpose` where a CSV file with multiple rows was not properly transposed.

7.07.01

Fixed bug in `gam print|show chromepolicies` that caused a trap. Made additional
updates to handle changes in the Chrome Policy API.

7.07.00

As of mid-October 2024, Google deprecated the API that retrieved the Global Address List.

The following commands have been eliminated.
```
gam info gal
gam print gal
gam show gal
```

These commands are a work-around for `gam print gal`.
```
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:true" redirect csv ./UserGAL.csv print users fields name,gal
gam config csv_output_row_filter "includeInGlobalAddressList:boolean:true" batch_size 25 redirect csv ./GroupGAL.csv print groups fields name,gal
```

7.06.14

Updated `gam create|update adminrole` to allow specifying a collection of privileges
with `privileges select <FileSelector>|<CSVFileSelector>` which makes copying roles much simpler.

Added option `role <RoleItem>` to `gam print|show adminroles` to allow display of information
for a specific role.

7.06.13

Updated `gam print group-members ... recursive` and `gam print cigroup-members ... recursive`
to expand groups representing chat spaces.

7.06.12

Deleted commands to display Analytic UA properties; the API has been deprecated.
```
gam <UserTypeEntity> print|show analyticuaproperties
```

7.06.11

Improved `gam checkconn`.

Updated `gam print group-members` and `gam print cigroup-members` to recognize members
that are groups representing chat spaces. For now, these groups are not expanded when
`recursive` is specified.

7.06.10

Added the following license SKU.
```
1010020034 - Google Workspace Frontline Plus
```

7.06.09

Added `gemini` and `geminiforworkspace` to `<ActivityApplicationName>` for use in
`gam report <ActivityApplicationName>`.

7.06.08

Fixed problem where Yubikeys caused a trap.

7.06.07

Updated private key rotation progress messages in `gam create|use|update project`
and `gam upload sakey`.

Updated `gam use project` to display the following error message when the specifed project
already has a service account.
```
Re-run the command specify a new service account name with: saname <ServiceAccountName>'
```

7.06.06

Native support for Windows 11 Arm-based devices.

Renamed some MacOS and Linux binary installer files to align on terminology. Everything is "arm64" now, no "aarch64".

7.06.05

Updated code in `gam delete|update chromepolicy` to handle the `policyTargetKey[additionalTargetKeys]`
field in a more general manner for future use.

7.06.04

Fixed bug in `gam report <ActivityApplictionName>` where a report with no activities
was not displaying any output.

7.06.03

Fixed bug in `gam <UserTypeEntity> print|show drivelastmodification` that caused a trap
when an empty drive was specified.

7.06.02

Updated `gam <UserTypeEntity> print|show filecounts ... showlastmodification` to include
file mimetype and path information for the last modified file.

Added simple commands to get information about the last modified file on a drive.
By default, a user's My Drive is processed; optionally, a Shared Drive can be processed.
```
gam <UserTypeEntity> print drivelastmodification [todrive <ToDriveAttribute>*]
        [select <SharedDriveEntity>]
        [pathdelimiter <Character>]
        (addcsvdata <FieldName> <String>)*
gam <UserTypeEntity> show drivelastmodification
        [select <SharedDriveEntity>]
        [pathdelimiter <Character>]
```

7.06.01

Updated `gam <UserTypeEntity> create|update drivefileacl ... expiration <Time>`
to handle additional API errors.

Updated to Python 3.13.3.

7.06.00

Upgraded to OpenSSL 3.5.0.

Fixed bug in `gam print cigroups` where `createTime`, `updateTime` and `statusTime`
were not converted according to `gam.cfg timezone`.

7.05.22

Updated progress messages for  `gam <UserTypeEntity> print filelist|filecounts|filesharecounts|filetree select shareddriveid <SharedDriveID>`
to display the ID of the SharedDrive that is being accessed.
```
Getting all Drive Files/Folders for user@domain.com on Shared Drive ID: <SharedDriveID
Got 33 Drive Files/Folders for user@domain.com on Shared Drive ID: <SharedDriveID>...
```

7.05.21

Fixed bug in `gam update chromepolicy` that generated an error like the following
when JSON data was read from a file.
```
ERROR:  JSON: {'error': {'code': 400, 'message': 'Invalid enum value: {prefix}{value} for enum type: chrome.policy.api.v1.devicepolicy.AllowNewUsersEnum', 'status': 'INVALID_ARGUMENT'}}
```

Fixed bug in `gam create chromepolicyimage` that caused a trap.

7.05.20

Updated code to validate both `<RegularExpression>` and `<ReplacementString>`
in the following command line options; this will expose errors when the command
is being parsed rather than at run-time.
```
replaceregex <RegularExpression> <ReplacementString>
replacedescription <RegularExpression> <ReplacementString>
replacefilename <RegularExpression> <ReplacementString>
```

7.05.19

Added `replaceregex <RegularExpression> <ReplacementString> <Tag> <String>` to the following commands:
```
gam sendemail subject <String> <MessageContent>
gam <UserTypeEntity> sendemail subject <String> <MessageContent>
```

The `<RegularExpression>` is used as a match pattern against `<String>` to produce `<ReplacementString>`.
Instances of `{Tag}` will be replaced by `<ReplacementString>` in the message subject and body.

Added `replaceregex <RegularExpression> <ReplacementString> <Tag> <UserReplacement>` to the following commands:
```
gam create user <NotifyMessageContent>
gam update user <NotifyMessageContent>
gam update users <NotifyMessageContent>
gam <UserTypeEntity> update users <NotifyMessageContent>
gam <UserTypeEntity> draft message <MessageContent>
gam <UserTypeEntity> import message <MessageContent>
gam <UserTypeEntity> insert messageo <MessageContent>
gam <UserTypeEntity> create sendas <SendAsContent>
gam <UserTypeEntity> update sendas <SendAsContent>
gam <UserTypeEntity> signature <SignatureContent>
gam <UserTypeEntity> vacation subject <String> <VacationMessageContent>
```

The `<RegularExpression>` is used as a match pattern against `<UserReplacement>` to produce `<ReplacementString>`.
Instances of `{Tag}` will be replaced by `<ReplacementString>` in the indicated items.

For example, when adding a phone number to a signature, an unformatted number can be formatted:
```
replaceregex "(\d{3})(\d{3})(\d{4})" "(\1) \2-\3" Phone "9876543210"
replaces 9876543210 with (987) 654-3210

replaceregex "(\+\d{2})(\d{3})(\d{3})(\d{3})" "\1 \2 \3 \4" Phone "+61987654321"
replaces +61421221506 with +61 987 654 321
```

7.05.18

Updated `gam calendars <CalendarEntity> show events` and `gam <UserTypeEntity> show events`
to display the event description according to `show_convert_cr_nl` in `gam.cfg`;
previously, GAM assumed `show_convert_cr_nl = true`.
```
show_convert_cr_nl = false
description:
  Line 1
  Line 2
  Line 3

show_convert_cr_nl = true
description: Line 1\nLine 2\nLine 3\n
```

7.05.17

Updated commands that delete drive ACLs to handle the following error:
```
ERROR: 403: cannotDeletePermission - The authenticated user does not have the required access to delete the permission.
```

7.05.16

Added option `transpose [<Boolean>]` to `redirect csv` that causes
GAM to transpose CSV output rows and columns. This will most useful
when a `countsonly` option is used in a `print` or `report` command.

7.05.15

Updated `gam <UserTypeEntity> get drivefile` and `gam <UserTypeEntity> create drivefile`
to allow downloading and uploading of Google Apps Scripts.
```
$ gam user user1@domain.com get drivefile 1ZY-YkS3E0OKipALra_XzfIh9cvxoILSbb8TRdHBFCpyB_mXI_J8FmjHv format json
User: user1@domain.com, Download 1 Drive File
  User: user1@domain.com, Drive File: Test Project, Downloaded to: /Users/gamteam/GamWork/Test Project.json, Type: Google Doc
$ gam user user2@domain.com create drivefile localfile "Test Project.json" mimetype application/vnd.google-apps.script+json drivefilename "Test Project"
User: user2@domain.com, Drive File: Test Project(1Ok_svw55VTreZ5CzcViJDLfEzVRi-Un8D9eG6I5pIeVyRl2YsmNiy3C_), Created with content from: Test Project.json
```

7.05.14

Added the following License SKU:
```
ProductId SKUId Display Name
101039 1010390002 Assured Controls Plus
```

7.05.13

Updated license product names to match Google.

7.05.12

Fixed bug in `gam update chromepolicy` where `appid` was misinterpreted for `chrome.devices.kiosk` policies
and an error was generated.
```
ERROR: Chrome Policy Schema: customers/C123abc456/policySchemas/<Field>, Does not exist
```

7.05.11

Added the following License SKUs:
```
ProductId SKUId Display Name
Google-Apps 1010070001 Google Workspace for Education Fundamentals
Google-Apps 1010070004 Google Workspace for Education Gmail Only
101034 1010340007 Google Workspace for Education Fundamentals - Archived User
```

7.05.10

Updated various chat space commands to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable
```

7.05.09

Fixed bug in `gam calendars <CalendarEntity> print events matchfield attendeesstatus required accepted resource_calendar@resource.calendar.google.com`
that caused a trap.

7.05.08

Added error message to `gam report` commands to indicate forbidden access;
previously, no error message was displayed.
```
ERROR: Customer ID: C012abc34, Caller does not have access to the customers reporting data.
```

7.05.07

Fixed bug in `gam calendars <CalendarEntity> info events` and `gam <UserTypeEntity> info events`
where option `showdayofweek` was not recognized.

7.05.06

Improve message displayed when a command is issued that requires Google Chat Bot setup;
display a link to the Wiki `Set up a Chat Bot` instructions.

7.05.05

Added options `password prompt` and `password uniqueprompt` to `gam create user <EmailAddress>`
and `gam update users <UserTypeEntity>` that prompt you to enter a password from stdin.

See [User Passwords](https://github.com/GAM-team/GAM/wiki/Users#passwords)

7.05.04

Updated `gam calendars <CalendarEntity> update events` and `gam <UserTypeEntity> update events`
to handle the following error:
```
ERROR 400: malformedWorkingLocationEvent - A working location event must have a visibility setting of public.
```

7.05.03

Fixed bug in `gam all users print users issuspended false allfields` that caused a trap.

7.05.02

Chat usage reports are now available. Added `chat` to `<CustomerServiceName>` and `<UserServiceName>`
for use in `gam report customer|user`.

* https://workspaceupdates.googleblog.com/2025/02/chat-usage-analytics-updates.html

7.05.01

Updated from `v1beta1` to `v1` for `Cloud Identity - Policy`.

* See: https://workspaceupdates.googleblog.com/2025/02/policy-api-general-availability.html

7.05.00

Enabled support for Limited Access as described here:
* https://workspaceupdates.googleblog.com/2025/02/updating-access-experience-in-google-drive.html

Note that the rollout may take 15 days.

Added option `inheritedpermissionsdisabled [<Boolean>]` to `<DriveFileAttribute>`; this
attribute can be set on folders.

Added `inheritedpermissionsdisabled` to `<DriveFieldName>`.

Added `capabilities.candisableinheritedpermissions` and `capabilities.canenableinheritedpermissions`
to `<DriveCapabilitiesSubfieldName>`.

Added option `enforceexpansiveaccess [<Boolean>]` to all commands that delete or update
drive file ACLs/permissions.
```
gam <UserTypeEntity> delete permissions
gam <UserTypeEntity> delete drivefileacl
gam <UserTypeEntity> update drivefileacl
gam <UserTypeEntity> copy drivefile
gam <UserTypeEntity> move drivefile
gam <UserTypeEntity> transfer ownership
gam <UserTypeEntity> claim ownership
gam <UserTypeEntity> transfer drive
```

7.04.05

Added initial support for Meet API v2beta; you must be in the Developer Preview program
for this to be effective.
* https://developers.google.com/meet/api/guides/beta/configuration-beta#auto-artifacts

Added `meet_v2_beta` Boolean variable to `gam.cfg`. When this variable is true,
the following options are added to `<MeetSpaceOptions>` used in `gam <UserTypeEntity> create|update meetspace`.
```
        moderation <Boolean> |
        chatrestriction hostsonly|norestriction |
        reactionrestriction hostsonly|norestriction |
        presentrestriction hostsonly|norestriction |
        defaultjoinasviewer <Boolean> |
        recording <Boolean> |
        transcription <Boolean> |
        smartnotes <Boolean>
```

This isn't called beta for nothing, I have found problems and reported them.

7.04.04

Updated `gam print group-members|cigroup-members` to include the `email` column
when `fields <MembersFieldNameList>` did not include `email`.

7.04.03

Added option `minimal|basic|full` to `gam print cigroup-members`:
* `minimal` - Fields displayed: group, id, role, email
* `basic` - Fields displayed: group, type, id, role, email
* `full` - Fields displayed: group, type, id, role, email, createTime, updateTime; this is the default

Added option `minimal|basic|full` to `gam show cigroup-members`:
* `minimal` - Fields displayed: role, email
* `basic` - Fields displayed: type, role, email
* `full` - Fields displayed: type, role, email, createTime, updateTime; this is the default

Upgraded `gam print cigroup-members ... recursive` to display sub-group email addresses rather than IDs.

7.04.02

Improved output formatting for the following commands:
```
gam info peoplecontact
gam show peoplecontacts
gam info peopleprofile
gam show peopleprofile
gam <UserTypeEntity> info contacts
gam <UserTypeEntity> show contacts
gam <UserTypeEntity> show peopleprofile
```

7.04.01

Fixed bug where multiple `querytime<String>` values in a query were not properly processed;
only the last `querytime<String>` was processed.
```
Command line: query "sync:#querytime1#..#querytime2# status:provisioned" querytime1 -2y querytime2 -40w
Query: (sync:#querytime1#..2024-05-09T00:00:00 status:provisioned) Invalid
```

7.04.00

The Classic Sites API no longer functions, the following commands are deprecated:
```
gam [<UserTypeEntity>] create site
gam [<UserTypeEntity>] update site
gam [<UserTypeEntity>] info site
gam [<UserTypeEntity>] print sites
gam [<UserTypeEntity>] show sites
gam [<UserTypeEntity>] create siteacls
gam [<UserTypeEntity>] update siteacls
gam [<UserTypeEntity>] delete siteacls
gam [<UserTypeEntity>] info siteacls
gam [<UserTypeEntity>] show siteacls
gam [<UserTypeEntity>] print siteacls
gam [<UserTypeEntity>] print siteactivity
```

7.03.09

Added option `maxmessagesperthread <Number>` to `gam <UserTypeEntity> print|show threads`
that limits the number of messages displayed per thread. The default is 0, there is no limit.
For example, this can be used if you only want to see the first message of each thread.
```
gam user user@domain.com print|show threads maxmessagesperthread 1
```

Fixed bug in `gam <UserTypeEntity> print filelist countsonly` where extraneous columns
were displayed.

Fixed bug in `gam <UserTypeEntity> print filelist countsonly showsize` where sizes were
all shown as 0 unless`sizefield size` was specified.

7.03.08

Improved pip install.

Yubikey as optional should now be working also. So:

pip install --upgrade gam7

skips Yubikey.

To install with yubikey support (assuming you have installed the necessary swig and libpcsclite-dev packages already) run:

pip install --upgrade gam7[yubikey]

7.03.07

Updated `gam create vaultexport` to include `corpus gemini`.

* See: https://workspaceupdates.googleblog.com/2025/02/google-vault-now-supports-gemini.html

7.03.06

Added option `rawfields "<BrowserFieldNameList>"` to `gam info|print|show browsers` that allows
specification of complex field lists with selected subfields.

* See: https://github.com/GAM-team/GAM/wiki/Chrome-Browser-Cloud-Management#raw-fields

7.03.05

Make GAM pip-installable: "pip install gam7"

7.03.04

Added option `security` to `gam create cigroup` that allows creation of a security group
in a single command.

Updated to Python 3.13.2.

7.03.03

Fixed bug in `gam update resoldcustomer` that caused the following error:
```
ERROR: Got an unexpected keyword argument customerAuthToken
```

7.03.02

Updated `gam <UserTypeEntity> show labels nested` to properly display label nesting
when labels have embedded `/` characters in their names.

7.03.01

Updated `gam create project` to retry the following unexpected error:
```
ERROR: 400 - invalidArgument - Service account gam-project-a1b2c@gam-project-a1b2c.iam.gserviceaccount.com does not exist.
```

7.03.00

Updated `gam create|use project` to discontinue use of the `Identity-Aware Proxy (IAP) OAuth Admin APIs`
that are being deprecated by Google. You will see a set of instructions detailing how to
configure the Oauth Consent screen and create the Oauth client.

Added options `copypermissionroles <DriveFileACLRoleList>` and `copypermissiontypes <DriveFileACLTypeList>`
to `gam <UserTypeEntity> copy drivefile` that provide more control over what permissions are copied
from the source files/folders to the destination files/folders.

7.02.11

Updated `gam report <ActivityApplicationName>` to display `id:<actor.profileId>` in the `emailAddress` column
when `actor.email` is empty. This typically occurs when the actor is not in your workspace.

Updated `gam <UserTypeEntity> copy drivefile` to ignore ACLs referencing deleted user/groups.

7.02.10

Added option `bydate` to `gam report <ActivityApplicationName> ... countsonly` that provides an additional display option.
* `countsonly` - Display a row per user across all dates with all event counts on one row
* `countsonly bydate` - Display a row per user per date for all dates with any events with all events counts on the row
* `countsonly summary` - Display a row per event with counts for each event summarized across users and dates

7.02.09

Added option `clearresources` to `<EventUpdateAttribute>` for use in `gam <UserTypeEntity> update events`
that allows clearing all resources from a user's calendar events. For example, to clear all resources from a user's future events:
```
gam user user@domain.com update events primary matchfield attendeespattern @resource.calendar.google.com after now clearresources
```

Added option `resource <ResourceID>` to `<EventAttribute>` for use in `gam <UserTypeEntity> create|update events`
that adds a resource to an event.

Added option `removeresource <ResourceID>` to `<EventUpdateAttribute>` for use in `gam <UserTypeEntity> update events`
that removes a resource from an event.

7.02.08

Fixed bug in `gam print|show chromepolicies` that caused a trap when neither
`ou|orgunit <OrgUnitItem>` nor `group <GroupItem>` was specified.

7.02.07

Updated `gam delete|update chromepolicy` to display the `<AppID>` or `<PrinterID>` (if specified)
in the command status messages.

7.02.06

Added option `<JSONData>` to `gam <UserTypeEntity> create|update form` that allows for
creation/modification of all fields in a form. `<JSONData>` is a list of form update requests.

* See: https://developers.google.com/forms/api/reference/rest/v1/forms/batchUpdate

7.02.05

Updated `gam [<UserTypeEntity>] show shareddriveacls ... formatjson` to not display this line
which interferes with the JSON output.
```
User: user@domain.com, Show N Shared Drives
```

7.02.04

Updated code to eliminate trap caused by bug introduced in 7.02.00 that occurs when an invalid domain or OU is specified.

7.02.03

Added option `archive` to `gam <UserTypeEntity> update license <NewSKUID> from <OldSKUID>` that causes GAM
to archive `<UserTypeEntity>` after updating their license to `<NewSKUID>`. This will be used when you want to
archive a user with a non-archivable license. The `<NewSKUID>` license is assigned to the user and it then converts
to the equivalent Archived User license when the user is archived.

`<NewSKUID>` must be one of the following SKUs:
```
Google-Apps-Unlimited - G Suite Business
1010020020 - Google Workspace Enterprise Plus
1010020025 - Google Workspace Business Plus
1010020026 - Google Workspace Enterprise Standard
1010020027 - Google Workspace Business Starter
1010020028 - Google Workspace Business Standard
```

7.02.02

Updated `gam <UserTypeEntity> archive messages <GroupItem>` to retry the following unexpected error
that occurs after many messages have been successfully archived.
`ERROR: 404: notFound - Unable to lookup group`

7.02.01

Added options `locked` and `unlocked` to `gam update cigroups` that allow locking/unlocking groups.

* See: https://workspaceupdates.googleblog.com/2024/12/locked-groups-open-beta.html

You'll have to do a `gam oauth create` and enable the following scope to use these options:
```
[*] 22)  Cloud Identity Groups API Beta (Enables group locking/unlocking)
```

7.02.00

Improved the error message displayed for user service account access commands when:
* The API is not enabled
* The user does not exist
* The user exists but is in a OU where the service is disabled

7.01.04

Admin role assignments are now in the v1 stable API, use that and remove custom local workaround for the beta. #1724

Remove duplicate local JSON discovery files. #1724

Suppress "UserWarning: Attribute's length must be..." messages on service accounts with long emails. #1725

Added options `internal`, `internaldomains <DomainNameList>` and `external` to these commands
that expand the options for viewing group members:
```
gam info group
gam print groups
gam print|show group-members
gam info cigroup
gam print cigroups
gam print|show cigroup-members
```
By default, when listing group members, GAM does not take the domain of the member into account.
* `internal internaldomains <DomainNameList>` - Display members whose domain is in `<DomainNameList>`
* `external internaldomains <DomainNameList>` - Display members whose domain is not in `<DomainNameList>`
* `internal external internaldomains <DomainNameList>` - Display all members, indicate their category: internal or external
* `internaldomains <DomainNameList>` - Defaults to value of `domain` in `gam.cfg`

Members without an email address, e.g. `customer`, `chromeosdevice` and `cbcmbrowser` are considered internal.

Updated to Python 3.13.1.

7.01.03

Fixed bug in `gam update cigroups <GroupEntity> delete|sync|update` where `cbcmbrowser` and `chromeosdevice`
addresses were not properly handled.

7.01.02

Added option `positivecountsonly` to `gam <UserTypeEntity> print|show filecomments` that causes
GAM to display the number of comments and replies only for files that have comments.

Added `my_commentable_items` to `<DriveFileQueryShortcut>` that can be used with
`gam <UserTypeEntity> print|show filecomments my_commentable_items` to speed up processing.

Updated code that uses the Domain Shared Contacts API with an HTTPS proxy to avoid a trap:
```
Traceback (most recent call last):
...
File "atom/http.py", line 250, in _prepare_connection
AttributeError: module 'ssl' has no attribute 'wrap_socket'
```

7.01.01

Fixed bug in `gam <UserTypeEntity> print|show filetree` where no error message was generated
if a user had Drive disabled.

7.01.00

Fixed bug in `gam update chromepolicy` that caused some policy updates to fail.

Added option `showhtml` to `gam <UserTypeEntity> print|show messages` that, when used with `showbody`,
will display message body content of type HTML.

Added support for managing/displaying Chrome profiles.

* See: https://github.com/GAM-team/GAM/wiki/Chrome-Profile-Management

7.00.40

Updated `gam <UserTypeEntity> update serviceaccount` to properly set the readonly scope
for `[R] 35)  Meet API (supports readonly)` as it is a special case.

7.00.39

Supported MacOS versions are now in the download filename.

Minor code fixes.

7.00.38

Fixed logic flaw in `gam print|show policies` where non-matching policies were displayed.

7.00.37

Added options `group <RegularExpression>` and `ou|org|orgunit <RegularExpression>`
to `gam print|show policies` that causes GAM to only display policies whose group email address
or OU path match the `<RegularExpression>`.

Updated `gam get|update|delete contactphotos` to use the People API for domain shared contact photos
as Google has deprecated the Domain Shared Contacts API for these commands. Unfortunately,
the People API fails with `gam update|delete contactphotos`.

7.00.36

Updated `gam print chromeapps` to correct a trap caused by an API change.

7.00.35

Classification labels are now available for Gmail in addition to Drive.

* See: https://workspaceupdates.googleblog.com/2024/11/open-beta-data-classification-labels-gmail.html

The following command synonyms are available, there is no change in functionality:
```
gam [<UserTypeEntity>] info classificationlabels|drivelabels
gam [<UserTypeEntity>] print classificationlabels|drivelabels
gam [<UserTypeEntity>] show classificationlabels|drivelabels
gam [<UserTypeEntity>] create classificationlabelpermission|drivelabelpermission
gam [<UserTypeEntity>] delete classificationlabelpermission|drivelabelpermission
gam [<UserTypeEntity>] remove classificationlabelpermission|drivelabelpermission
gam [<UserTypeEntity>] print classificationlabelpermissions|drivelabelpermission
gam [<UserTypeEntity>] show classificationlabelpermissions|drivelabelpermission
```

7.00.34

Fixed bug introduced in 7.00.33 in `gam print group-members` that caused a trap.

7.00.33

Fixed bug in `gam print group-members ... cachememberinfo` that caused a trap.

7.00.32

Updated `gam info policies` to accept different policy specifications:
* `polices/<String>` - A policy name, `policies/ahv4hg7qc24kvaghb7zihwf4riid4`
* `settings/<String>` - A policy setting type, `settings/workspace_marketplace.apps_allowlist`
* `<String>` - A policy setting type, `workspace_marketplace.apps_allowlist`

7.00.31

Updated `gam info|print|show policies` to make additional API calls for `settings/workspace_marketplace.apps_allowlist`
to get the application name for the application ID. Use option `noappnames` to suppress these calls.

7.00.30

Added command to display selected Cloud Identity policies.
```
gam info policies <CIPolicyNameEntity>
        [nowarnings]
        [formatjson]
```

Removed option `name <CIPolicyName>` from `gam print|show policies`; use `info policies`.

7.00.29

Added option `name <CIPolicyName>` to `gam print|show policies` that displays
information about a specific policy.

7.00.28

Fixed issue that caused `gam print/show policies` to fail on some group policies.

7.00.27

Updated `gam <UserTypeEntity> collect orphans` and all commands that print file paths to recognize
that a file owned by a user that has no parents is not an orphan if `sharedWithMeTime` is set.
This occurs when user A creates a file in a shared folder owned by user B and user B then removes
user A's access to the folder.

Added commands to display Cloud Identity policies.
```
gam print policies [todrive <ToDriveAttribute>*]
        (filter <String>) [nowarnings]
        [formatjson [quotechar <Character>]]
gam show policies (filter <String>) [nowarnings]
        [formatjson]
```

7.00.26

Updated `drive_dir` in `gam.cfg` to allow the value `.` that causes `redirect csv|stdout|stderr <FileName>`
to write `<FileName>` in the current directory without having to prefix `<FileName>` with `./`.

Upgraded to OpenSSL 3.4.0 where possible.

7.00.25

Updated authentication process for `gam print|show projects`.

7.00.24

Updated `gam print|show projects ... showiampolicies 0|1|3` to use non-service account authentication.

7.00.23

Updated `gam <UserTypeEntity> create|delete chatmember` to accept external (non-domain) email addresses.

7.00.22

Fixed bug in `gam create vaultmatter ... showdetails` that caused a trap.

7.00.21

Added `csv_output_header_order` variable to `gam.cfg` that is a list of `<Strings>`
that are used to specify the order of column headers in the CSV file written by a gam print command.
Any headers in the file but not in the list will appear after the headers in the list.

This might be used when the CSV file data is to be processed by another program
that requires that the headers be in a particular order.

7.00.20

Fix Windows MSI installer issues on version upgrade. If you are having issues upgrading from a version older than 7.00.20 to this version or newer you may need to do a one time uninstall of GAM7 and then reinstall the new version.
No configuration files will be lost during the uninstall / reinstall.

7.00.19

Updated `gam update shareddrive <SharedDriveEntity> ou <OrgUnitItem>` to handle the following error
that occurs when an invalid `<SharedDriveEntity>` is specified.
```
ERROR: 400: invalidArgument - Invalid org membership name 0AJ3b2FTPakToUk9PVAxx.~
```

Updated `gam print browsers` to properly format the time field `deviceIdentifiersHistory.records.0.firstRecordTime`.

7.00.18

Updated `gam create project` to use a default project name of `gam-project-a1b2c` (`a1b2c` is a random string of 5 characters)
instead of `gam-project-abc-123-xyz` to avoid the following warning:
```
Project: gam-project-abc-123-xyz, Service Account: gam-project-abc-123-xyz@gam-project-abc-123-xyz.iam.gserviceaccount.com, Extracting public certificate
init.py:12382: UserWarning: Attribute's length must be >= 1 and <= 64, but it was 70
init.py:12383: UserWarning: Attribute's length must be >= 1 and <= 64, but it was 70
Project: gam-project-abc-123-xyz, Service Account: gam-project-abc-123-xyz@gam-project-abc-123-xyz.iam.gserviceaccount.com, Done generating private key and public certificate
```

7.00.17

Update all user calendar commands to disable falling back to client access if service account
authorization has never been performed. Previously, in this circumstance, the admin's calendars
rather than the user's calendars were processed.

7.00.16

Updated `gam <UserTypeEntity> claim|transfer ownership` to show `Got N Drive Files/Folders that matched query` messages
as files/folders are being identified for processing.

Added option `<JSONData>` to `gam create|update caalevel`.

Updated to Python 3.13.0.

7.00.15

Added options `timestamp [<Boolean>]` and `timeformat <String>` to `gam <UserTypeEntity> create|update drivefile` that allow
adding a timestamp to a created/updated file name.

7.00.14

Retry the following unexpected errors in `gam print users`.
```
ERROR: 400: failedPrecondition - Precondition check failed.
ERROR: 500: unknownError - Unknown Error.
```

7.00.13

Version bump in order to confirm MSI installs are operating properly

7.00.12

Updated option `showlastmodification` to `gam <UserTypeEntity> print|show filecounts` to handle
the case where all users owning files are suspended. In this case the `lastModifyingUser` column
will show the user's display name as the API doesn't return the user's email address.

Updated support for `Folders with limited access`; this is a work in progress.

Windows builds now use PyInstaller's onedir config for improved performance. You may notice a lib
folder now exists underneath the GAM install path. GAM commands should start significantly faster.

7.00.11

Updated to Python 3.12.7 where possible.

7.00.10

Handled the following error that occurs when `gam create user` is immediateley followed by `gam update user`.
```
ERROR: 412: conditionNotMet - User creation is not complete.
```

Updated support for `Folders with limited access`; this is a work in progress.

7.00.09

Added initial support for `Folders with limited access`; you must be enrolled in the Beta preview.

Updated `api_call_tries_limit` variable to `gam.cfg` that limits the number of tries
for Google API calls that return an error that indicates a retry should be performed.
The default value is 10 and the range of allowable values is 3-30.

7.00.08

Fixed bug in `gam <UserTypeEntity> delete groups` that caused the command to fail when `enable_dasa = true` in `gam.cfg`.

7.00.07

Updated `<PeopleContactAttribute>` fields `address,email,phone,url` to allow an empty type field.
```
address "" formatted "My Address" primary
email "" user@gmail.com primary
phone "" "510-555-1212" primary
url "" "https://www.domain.com" primary
```

7.00.06

Updated `gam <UserTypeEntity> create|update chatspace` to support the new permissions settings
for Chat spaces that are in Developer Preview.

* See: https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces#Space.FIELDS.predefined_permission_settings

7.00.05

Fixed bug that caused an error when creating a calendar birthday event.

7.00.04

Improved performance of `gam report users orgunit <OrgUnitPath>` when `showorgunit` is not specified.

Added option `birthday <Date>` to `gam <UserTypeEntity> create event <UserCalendarEntity>` that adds
an annual recurring event to the calendar.

Added `birthday` to `<EventType>` for use in various calendar event commands.

7.00.03

Updated `gam delete ou` and `gam print admins` to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

7.00.02

Added option `showlastmodification` to `gam <UserTypeEntity> print|show filecounts` that adds
the following fields to the output: `lastModifiedFileId,lastModifiedFileName,lastModifyingUser,lastModifiedTime`;
these are for the most recently modified file.

Added option `keepforever [<Boolean>]` to `gam <UserTypeEntity> update filerevisions` that allows setting
`Keep forever` in revisions.

Upgraded to Python 3.12.6 where possible.

7.00.01

Added option `shownames` to `gam <UserTypeEntity> print|show sheet` that causes GAM
to make an additional API call to get and display the sheet file name that is not supplied by the Sheets API.

7.00.00

Merged GAM-Team version

6.81.02

Updated `gam update group postmaster@domain.com` to handle the error that is generated.

6.81.01

Fixed bug in `gam <UserTypeEntity> create meetspace` that caused errors
due to Developer Preview options being included.

6.81.00

Added support for groups when defining Chrome policies.

Added support for the Meet API.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Meet

Added option `countsonly` to the following course commands that displays
the number of items in a course but not the details of the items.
```
gam print course-announcements
gam print course-materials
gam print course-submissions
gam print course-topics
gam print course-work
```

6.80.21

Updated `gam <UserTypeEntity> archive messages` to handle the following error:
```
googleapiclient.errors.MediaUploadSizeError: Media larger than: 26214400
```

6.80.20

Updated `gam report usage user` and `gam report users` to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.80.19

Fixed bug in `gam create inboundssoprofile` that caused a trap due to
an unexpected API result.

Updated `gam create inboundssoprofile ... returnnameonly` to return `inProgress` if the API
does not return a complete result.

Upgraded to OpenSSL 3.3.2 where possible.

6.80.18

Updated `gam print|show admins` to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.80.17

Updated `gam <UserTypeEntity> modify messages` to improve error handling.

6.80.16

Fixed bug in `gam print vaultcounts` that caused a trap.

6.80.15

Fixed bug in `gam <UserTypeEntity> print filelist ... countsrowfilter` that caused a trap.

Added option `continueoninvalidquery [<Boolean>]` to `gam <UserTypeEntity> print filelist|filecounts` that can be used
in special cases where a query  of the form `query "'labels/mRoha85IbwCRl490E00xGLvBsSbkwIiuZ6PRNNEbwxyz' in labels"
causes Google to issue an error saying that the query is invalid when, in fact, it is but the user does not have a
license that suppprts drive file labels. When `continueoninvalidquery` is true, GAM prints an error message and
proceeds to the next user rather that terminating as it does now. Of course, if the query really is invalid, you will
get the message for every user.

6.80.14

Updated `gam <UserTypeEntity> print messages|threads` to display all default headers
even if no messages are to be displayed. This eliminates error messages of the following form
that occurred because only the headers `User,threadId,id` were displayed.
```
WARNING: csv_output_row_filter column "^Date$" does not match any output columns
```

6.80.13

Added `my_publishable_items` to `<DriveFileQueryShortcut>` that can be used in
`gam <UserTypeEntity> print filerevisions` to select only those items that can be
published to the web: documents, forms, presentations(slides), spreadsheets. With row filtering,
this allows identification of files that have been published outside your domain.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#display-files-published-to-the-web

6.80.12

Updated `gam print vaultcounts` to correctly display accounts with errors.

6.80.11

Updated `gam <UserTypeEntity> delete|purge|trash|untrash <DriveFileEntity> shortcutandtarget`
that when `<DriveFileEntity` is a shortcut, to have GAM validate that the shortcut and target can be
successfully processed before proceeding.

6.80.10

Added option `followshortcuts [<Boolean>]` to `gam <UserTypeEntity> print|show fileinfo|filepath <DriveFileEntity>`
that when true and `<DriveFileEntity` is a shortcut, causes GAM to display information about the target of the shortcut rather than the shortcut itself.

Added option `shortcutandtarget [<Boolean>]` to `gam <UserTypeEntity> delete|purge|trash|untrash <DriveFileEntity>`
that when true and `<DriveFileEntity` is a shortcut, causes GAM to process the shortcut and the target of the shortcut.

6.80.09

Added options `allschemas|(schemas|custom|customschemas <SchemaNameList>)` to `gam print group-members`
that display any custom schema values for the group members.

6.80.08

Updated `gam print|show oushareddrives` to display the Shared Drive ID, name and orgUnitPath as
individual, separate entities in the output.

6.80.07

Updated `dateheaderformat iso` in `gam <UserTypeEntity> info|print|show messages` to include a colon
between the hours and minutes in the timezone portion of the string as in all other time strings.

6.80.06

Added option `tdreturnidonly [<Boolean>]` to `<ToDriveAttribute>` that when true (the default), causes GAM to display
only the uploaded file ID to stdout. This can be captured and used in subsequent commands, `tdfileid <DriveFileID>` that will update the same file.

6.80.05

Added  option `individualstudentcoursework copy|delete|maptoall` to `gam create|update course ... copyfrom`
that controls how individual student coursework in the `copyfrom` course is processed.
* `individualstudentcoursework copy` - Copy individual student coursework; this is the default. You will get an error if a student is not a member of the course
* `individualstudentcoursework delete` - Delete individual student coursework
* `individualstudentcoursework maptoall` - Map individual student coursework to all student coursework

For convenience, setting `individualstudentassignments` sets all of the following to the same value:
*`individualstudentannouncements`
*`individualstudentmaterials`
*`individualstudentcoursework`

6.80.04

Cleaned up progress messages in `gam create|update course ... copyfrom`.

6.80.03

Added option `stripcrsfromname` to `gam <UserTypeEntity> print driveactivity` that causes carriage returns,
linefeeds and nulls to be stripped from file names.

6.80.02

Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print filecounts` that adds
additional columns of data to the CSV file output.

Added  options `individualstudentannouncements copy|delete|maptoall` and `individualstudentmaterials copy|delete|maptoall`
to `gam create|update course ... copyfrom` that controls how individual student announcements and materials in the `copyfrom` course are processed.
* `individualstudentannouncements copy` - Copy individual student announcements; this is the default. You will get an error if a student is not a member of the course
* `individualstudentannouncements delete` - Delete individual student announcements
* `individualstudentannouncements maptoall` - Map individual student announcements to all student announcements
* `individualstudentmaterials copy` - Copy individual student materials; this is the default. You will get an error if a student is not a member of the course
* `individualstudentmaterials delete` - Delete individual student materials
* `individualstudentmaterials maptoall` - Map individual student materials to all student materials

6.80.01

Added options `showstudentsaslist [<Boolean>]` and `delimiter <Character>` to `gam print course-work`.
By default, when course work is assigned to individual students, the student IDs are displayed in multiple indexed columns.
Use these options to display the student IDs in a single column as a delimited list.

Updated `gam <UserTypeEntity> vacation [<Boolean>]` to make `<Boolean>` optional; this allows changes
to other fields without affecting the current responder state.

Updated `gam <UserTypeEntity> print|show vacation` to avoid a trap when invalid start or end dates
have been entered in the Gmail user interface. Invalid dates are represented as `1970-01-01`.

6.80.00

Fixed bug in `gam <UserTypeEntity> print users ... license ... formatjson` that caused a trap.

Upgraded to Python 3.12.5 where possible.

6.79.12

Fixed bug in `gam user admin@domain.com print chatspaces asadmin` that caused the following error:
```
Chat Admin: admin@domain.com(asadmin), Print Failed: This method doesn't support non-admin user authentication. Authenticate with an admin account.
```

6.79.11

Fixed bug in `gam <UserItem> print|show chatmembers` where the `filter <String>` was not applied.

6.79.10

Updated commands to handle a trap that occurs when oauth2service.json specifies a YubiKey but the YubiKey is not inserted.

6.79.09

Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print teamdriveacls` that adds
additional columns of data to the CSV file output. This can be used when ACLs for selected users are to be
replaced with a different user email address.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Shared-Drives#bulk-change-user1-shared-drive-access-to-user2

6.79.08

Clarified action to perform messages when creating/deleting/updating licenses.

6.79.07

Added option `totalonly` to `gam <UserTypeEntity> print|show groups` that displays
the user email address and the total number of groups to which it belongs. This is in
contrast to `countsonly` that has to make an additional API call per group per user to get the user's role.
When `countsonly` is specified, an additional column `Total` is displayed that is the sum
of the role counts.

6.79.06

Fixed bug in `gam calendars <CalendarEntity> update event ... removeattendee <EmailAddress>` that caused a trap
if the event had no attendees.

6.79.05

Updated `gam <UserTypeEntity> empty drivetrash <SharedDriveEntity>` to handle this error that
occurs when the user is not a Manager of the Shared Drive.
```
ERROR: 403: insufficientFilePermissions - The user does not have sufficient permissions for this file.
```

6.79.04

Added options `filename <FileName>` and `movetoou <OrgUnitItem>` to `gam check ou <OrgUnitItem>`
that causes GAM to create a batch file of GAM commands that will move any remaining items
in `ou <OrgUnitItem>` to `movetoou <OrgUnitItem>`; executing the batch file will then allow
`ou <OrgUnitItem>` to be deleted if desired.

6.79.03

Added column|field `assignedToUnknown` to `gam print|show admins` that will be True when
the API `assignedTo` value can not be converted to an email address; it will be False when
the email address is determinable.

6.79.02

Updated `gam print admins` to handle the following error that occurs when a service account admin no longer exists.
```
ERROR: 404: notFound - Requested entity was not found.
```

6.79.01

Updated commands that take `<RoleItem>` as an argument to take the value in any case,
e.g., _SEED_ADMIN_ROLE or _seed_admin_role.

6.79.00

Updated code to work around a Cryptography library change that caused service account private key creation to fail.

6.78.00

Added command to check if an OU contains items; this is useful when tryng to delete an OU
as it must not contain any items in order to be deleted.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Organizational-Units#check-organizational-unit-for-contained-items

6.77.18

Added option `showitemcountonly` to `gam print domainaliases` that causes GAM to display the
number of domain aliasess on stdout; no CSV file is written.

6.77.17

Added option `showitemcountonly` to `gam print domains` that causes GAM to display the
number of domains on stdout; no CSV file is written.

6.77.16

Fixed bug in `gam <UserTypeEntity> print filelist` that caused a trap.

6.77.15

Updated `gam calendars <CalendarEntity> import event icaluid <iCalUID> json <JSONdata>` to handle API
constraints on recurring events.

6.77.14

Fixed bug in `gam calendars <CalendarEntity> import event icaluid <iCalUID> json <JSONdata>` that caused an error.

6.77.13

Updated `gam <UserTypeEntity> print|show filecounts` to reflect that Shared Drives now
have a capacity of 500000 files/folders/shortcuts.

6.77.12

Fixed bug in `gam <UserTypeEntity> print chatspaces todrive` that caused an error.

6.77.11

Added option `convertmbtogb` to `gam report usage customer|user` and
`gam report customer|user` that causes GAM to convert parameters expressed in megabytes
(name ends with _in_mb) to gigabytes (name converted to _in_gb) with two decimal places.

6.77.10

Fixed bug in `gam <UserTypeEntity> get profilephoto` where data written to stdout, e.g. `> filename`,
was not properly base64 encoded.

6.77.09

Added option `usertokencounts` to `gam <UserTypeEntity> print|show tokens` that causes GAM to display
each user and their number of access tokens; there are no details.

6.77.08

Fixed bugs in `gam <UserTypeEntity> delete chatmember <ChatSpace> ... group <GroupItem>`
and `gam <UserTypeEntity> sync chatmember <ChatSpace> ... groups <GroupEntity>` that caused an error.

6.77.07

Fixed bug in `gam <UserTypeEntity> create chatmember <ChatSpace> ... group <GroupItem>` that caused an error.

6.77.06

Updated `gam update ou <OrgUnitItem> ... parent <OrgUnitItem>` to handle the following error
that occurs when `parent <OrgUnitItem>` is the same as or a sub-OU of `ou <OrgUnitItem>`.
```
ERROR: 412: conditionNotMet - OrgUnit hierarchy has cycle
```

6.77.05

Added option `onlyusers <UserTypeEntity>` to `gam <UserTypeEntity> claim ownership <DriveFileEntity>`
that causes GAM to only claim ownership of files/folders owned by `onlyusers <UserTypeEntity>`.
This option is multually exclusive with `skipusers <UserTypeEntity>`.

6.77.04

Fixed bug in `gam report users ... range <Date> <Date>` where an extraneous API call
was made if a date was reached where no API data was available.

6.77.03

Thanks to jay, added the following Colab License SKUs:
```
1010500001 - Colab Pro
1010500002 - Colab Pro+
```

Thanks to Jay, updated `gam print|show admins` to properly display addresses
of service accounts with admin role assignments.

Added option `limitdatechanges <Integer>` to `gam report users|customers`.

If no report is available for the specified date, can an earlier date be used?
* `limitdatechanges -1' - Back up to earlier dates to find report data; this is the default.
* `limitdatechanges 0 | nodatechange' - Do not report on an earlier date if no report data is available for the specified date.
* `limitdatechanges N' - Back up to earlier dates to find report data; do not back up more than N times.

By default, when `gam report user user <UserItem>` is specified and no report data is available, there is no output.
If `csv_output_users_audit = true` in `gam.cfg`, then a row with columns `email,date` will be displayed
where `date` is the earliest date for which report data was requested.

6.77.02

Cleaned up problems with some of the new Chat API asadmin commands.
Some remaining problems may require a Google fix.

6.77.01

Thanks to Jay, added column `verificationCodesCount` to `gam <UserTypeEntity> print backupcodes`
that displays the number of available backup codes in addtion to the codes.

Added option `countsonly` that displays only the number of available backup codes but not the codes themselves.

Thanks to Jay, added option `nokey` to `gam create project` that creates a project with no service account key, `oauth2service.json`.

6.77.00

Added option `individualstudentassignments copy|delete|maptoall` to `gam create|update course ... copyfrom`
that controls how individual student assignments in the `copyfrom` course are processed.
* `individualstudentassignments copy` - Copy individual student assignments; this is the default. You will get an error if a student is not a member of the course
* `individualstudentassignments delete` - Delete individual student assignments
* `individualstudentassignments maptoall` - Map individual student assignments to all student assignments

Upgraded to Python 3.12.4 where possible.

Added option `asadmin` to the following Chat commands that allows admin access.
These commands are in Developer Preview, your project must have Developer Preview enabled for the Chat API
in order to use these commands.
```
gam <UserItem> delete chatspace asadmin
gam <UserItem> update chatspace asadmin
gam <UserItem> info chatspace asadmin
gam <UserItem> print|show chatspaces asadmin
gam <UserItem> create chatmember asadmin
gam <UserItem> delete|remove chatmember asadmin
gam <UserItem> update|modify chatmember asadmin
gam <UserItem> sync chatmembers asadmin
gam <UserItem> info chatmember asadmin
gam <UserItem> print|show chatmembers|asadmin
```

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Chat#developer-preview-admin-access

Added `use_chat_admin_access` Boolean variable to `gam.cfg`. 
```
* When False, GAM uses user access when making all Chat API calls. For calls that support admin access,
    this can be overridden with the asadmin command line option.
* When True, GAM uses admin access for Chat API calls that support admin access; other calls will use user access.
* Default: False
```

6.76.15

Fixed bug in `gam <UserTypeEntity> print|show filesharecounts summary only summaryuser <String>`
that printed an erroneous row if `<UserTypeEntity>` specified a single user and `<String>` matched
the user's email address.

6.76.14

Added the following Gemini License SKUs:
```
1010470004 - Gemini Education
1010470005 - Gemini Education Premium
```

6.76.13

Updated `gam <UserTypeEntity> show fileinfo ... showlabels` and `gam <UserTypeEntity> print filelist ... showlabels`
to retry these errors that occur when trying to get the drive labels for a file/folder.
```
ERROR: 500: unknownError - Unknown Error.
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

Upgraded to OpenSSL 3.3.1 where possible.

6.76.12

Fixed bug in `gam <UserTypeEntity> print|show chatspaces` that caused the following error:
```
ERROR: Got an unexpected keyword argument orderBy
```

6.76.11

Thanks to Jay, added `gam report vault`.

Thanks to Jay, added the following Gemini License SKUs:
```
1010470006 - AI Security
1010470007 - AI Meetings and Messaging
```

Updated `gam <UserTypeEntity> print filelist ... showshareddrivepermissions` to display
progress messages to stderr as a separate API call must be made for every file/folder on the Shared Drive
to get its permissions. As this can take a long time, the progress messages indicate that progress is being made.

6.76.10

Added `fromgmail` to `<EventType>` that can be used in `gam calendars <CalendarEntity> print|show events ... eventtype fromgmail`.

* See: https://workspaceupdates.googleblog.com/2024/05/google-calendar-api-event-type-fromgmail.html

6.76.09

Updated `gam update|delete|info adminrole` to handle the following error:
```
ERROR: 400: failedPrecondition - Precondition check failed.
```

6.76.08

Updated `<SchemaNameList>` to `"<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"`
that allows `schemas <SchemaNameList>` in `gam info user` and `gam print users` to display all fields or selected fields
of the specified custom schemas.

6.76.07

Fixed bug where control-C was not recognized when GAM had processed all rows in a CSV file
and was `Waiting for N running processes to finish before terminating`.

6.76.06

Fixed bug in `gam <UserTypeEntity> print messages ... positivecountsonly` where message counts with value 0 were deiplayed.

Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print messages` that adds
additional columns of data to the CSV file output.

Added option `showusagebytes` to `gam <UserTypeEntity> print|show drivesettings` that displays
the following fields in bytes ```usageBytes,usageInDriveBytes,usageInDriveTrashBytes```
in addition to the fields in their formatted form with units: ```usage,usageInDrive,usageInDriveTrash```.
This will be most useful with `print` as the rows can be sorted based on the `usagexxxBytes` columns.

6.76.05

Added options `deletefromoldowner`, `addtonewowner <CalendarAttribute>*` and `nolistmessages`
to `gam <UserTypeEntity> transfer calendars <UserItem>` that allow manipulation of the
old and new owners's calendar lists.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Access#transfer-calendar-ownership

6.76.04

Added the following fields to `<CrOSFieldName>`:
```
autoupdatethrough
extendedsupporteligible
extendedsupportstart
extendedsupportenabled
```

6.76.03

Added option `folderpathonly [<Boolean>]` to the following commands that causes GAM
to display only the folder names when displaying the path to a file. This folder only path
an be used in  `gam <UserTypeEntity> create drivefolderpath` to recreate the folder hierarchy.
```
gam <UserTypeEntity> info drivefile ... filepath|fullpath
gam <UserTypeEntity> show fileinfo ... filepath|fullpath
gam <UserTypeEntity> print|show filepath
gam <UserTypeEntity> print filelist ... filepath|fullpath
```

6.76.02

Updated `gam update group` to handle the following error:
```
ERROR: 400: invalidArgument - Failed request validation in update settings: WHO_CAN_VIEW_MEMBERSHIP_CANNOT_BE_BROADER_THAN_WHO_CAN_SEE_GROUP
```

6.76.01

Fixed bug in `gam create vaulthold matter <MatterItem> ... corpus calendar` that caused a trap.

6.76.00

Updated versions of `gam create|use project` that use keyword options to also accept the following options
to define non-default Service Account key characteristics.
```
(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|
(localkeysize 1024|2048|4096 [validityhours <Number>])|
(yubikey yubikey_pin yubikey_slot AUTHENTICATION yubikey_serialnumber <String>)
```

6.75.05

Added option `csv [todrive <ToDriveAttribute>*]` to `gam <UserTypeEntity> archive|delete|modify|spam|trash|untrash messages|threads`
that causes GAM to display the command results in CSV form.

6.75.04

Added a command to print user counts by OrgUnit. By default, all users in the workspace are counted;
you can specify a domain to only count users in that domain.
```
gam print usercountsbyorgunit [todrive <ToDriveAttribute>*]
        [domain <String>]
```

Added option `uploadattachments [<DriveFileParentAttribute>]` to `gam <UserTypeEntity> show messages|threads` that
causes GAM to upload all message attachments to the user's `My Drive`, the default, or to a specific folder.
The existing option `attachmentnamepattern <RegularExpression>` can be used to select attachments to upload.

6.75.03

Fixed bug in `gam batch|tbatch` where the line `sleep <Integer>` in the batch file caused the error:
```
ERROR: Invalid argument: Expected <gam|commit-batch|print>
```

6.75.02

Updated `gam report  <ActivityApplictionName>` to retry/handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.75.01

Added option `admin <EmailAddress>` to  `gam upload sakey`.

6.75.00

Updated `gam create project` to simplify handling the situation where your workspace is configured to disable service account private key uploads.

Added command `gam upload sakey` to aid in this process.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#upload-a-service-account-key-to-a-service-account-with-no-keys

6.74.02

Fixed bug in `gam <UserTypeEntity> print shareddrives ... formatjson` that caused a trap.

6.74.01

Updated `gam create|update drivefileacl <DriveFileEntity> ... expiration <Time>` to handle
the following error caused by tryig to add an expiration time to a member of a Shared Drive.
```
ERROR: 403: expirationDateNotAllowedForSharedDriveMembers - Expiration dates are not allowed for shared drive members.
```

6.74.00

Added `truncate_client_id` Boolean variable to `gam.cfg`. Prior to version 6.74.00, GAM stripped
'.apps.googleusercontent.com' from `client_id` in `oauth2.txt` and passed the truncated value in API calls.
At Jay's suggestion this is no longer performed by default; setting `truncate_client_id = true` restores the previous behavior.

Do `gam oauth delete` and `gam oauth create` to set the untruncated value of `client_id` in `oauth2.txt`.

6.73.00

The Google Chat API has been updated so that chat members can now have their role set to manager.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Chat#manage-chat-members

6.72.16

Updated `emailaddressList <EmailAddressList>` and `domainlist|notdomainlist <DomainNameList>`
in `<PermissionMatch>` to perform case-insensitive matches as the API is returning mixed case
ACL email addresses in some cases.

6.72.15

Updated all commands that display tasks to display the due date in GMT as the time portion
is not supported by the API and converting the due date to local time may display the wrong date.

Renamed license SKU `1010400001` from `Beyond Corp Enterprise` to `Chrome Enterprise Premium`.

6.72.14

Upgraded to Python 3.12.3 where possible.

6.72.13

Added the following option to `<EventMatchProperty>` that can be used to select
events based on the domains of the attendees.
```
matchfield attendeesonlydomainlist <DomainNameList>
```
This returns true if all attendee's email addresses are in a domain in `<DomainNameList>`;
for example this lets you look for events with attendees only in your internal domains.

6.72.12

Added the following options to `<EventMatchProperty>` that can be used to select
events based on the domains of the attendees.
```
matchfield attendeesdomainlist <DomainNameList>
matchfield attendeesnotdomainlist <DomainNameList>
```
The first returns true if any attendee's email address is in a domain in `<DomainNameList>`;
for example this lets you look for events with attendees in specific external domains.

The second returns true if any attendee's email address is in a domain other than those in `<DomainNameList>`;
for example this lets you look for events with attendees not in your internal domains.

6.72.11

Added option `oneitemperrow` to 'gam print vaultholds` to have each of a
hold's accounts displayed on a separate row with all of the other hold fields.

6.72.10

Added `timeofdayrange=<HH:MM>/<HH:MM>` and `timeofdayrange!=<HH:MM>/<HH:MM>` to `<RowValueFilter>` that allows
CSV row filtering based on time-of-day.

6.72.09

Updated `countsonly` option of `gam <UserTypeEntity> print|show notes` to additionally display the total number of notes.

6.72.08

Added option `countsonly` to `gam <UserTypeEntity> print|show notes` that displays
the number of notes a user owns and the number of notes a user can edit.

6.72.07

Updated commands that send emails to not downshift `'First Last<firstlast@domain.com>'` to `'first last<firstlast@domain.com>'`.

6.72.06

Updated the following commands to properly handle emailaddress lists containing addresses of the form: `'First Last<firstlast@domain.com>'`.
```
gam <UserTypeEntity> sendemail recipient|to <RecipientEntity> [cc <RecipientEntity>] [bcc <RecipientEntity>] [singlemessage]
gam create|update user ... notify <EmailAddressList>
```

6.72.05

Cleaned up code for all commands that display Chat objects.

6.72.04

Added commands to display Chat events.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Chat#display-chat-events

6.72.03

Fixed bug in `gam <UserTypeEntity> create chatspace` that caused a trap.

6.72.02

Updated `gam delete admin <RoleAssignmentId>` to handle the following error that
occurs when `<RoleAssignmentId>` references a user that has been deleted.
```
ERROR: 404: resourceNotFound - Does not exist
```

6.72.01

Improved commands to display drive file comments.

6.72.00

Added commands to display drive file comments.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Comments

6.71.18

Updated `<CrOSFieldName>` to include `cpuinfo` and `backlightinfo`.

6.71.17

Added `depth` column to output of `gam <UserTypeEntity> print diskusage <DriveFileEntity>` that can
be used to filter the depth of the folders displayed. Depth `-1` is the top level folder, depth `0`
are its immediate children, depth `2` are the children of depth `1` and so forth.
```
gam config csv_output_row_filter "depth:count<1" user organizer@domain.com  print diskusage teamdriveid <TeamDriveID>
```

6.71.16

Updated `gam <UserTypeEntity> create|update sendas <EmailAddress> ... replyto <EmailAddress>`
to allow uppercase letters in `sendas <EmailAddress>` and `replyto <EmailAddress>`.

6.71.15

Updated `gam create project` to handle the following error:
```
ERROR: 403: permissionDenied - Authentication error: 7; Error Details: User not allowed to access GCP services.
```
This error occurs when the Google Workspace admin or GCP project manager email address used in the command
is in an OU where Google Cloud Platform is not enabled in Apps/Additional Google services.

6.71.14

Added a command to update a Gmail label's settings by specifying it's ID rather than it's name.
```
gam <UserTypeEntity> update labelid <LabelID> [name <String>]
        [messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
        [backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"]
        [textcolor "<LabelColorHex>|<LabelTextColorHex>|custom:<ColorHex>"]
```

6.71.13

Updated `<UserMultiAttribute>.location.buildingid <String>` to allow non-validated building IDs
by specifying `nv:` at the beginning of `<String>`; e.g., `nv:Building X' sets the building ID to `Building X`.

6.71.12

Added option `showmimetype category <MimeTypeNameList>` to `gam <UserTypeEntity> print|show filecounts|filelist|filetree`
```
<MimeTypeName> ::= application|audio|font|image|message|model|multipart|text|video
<MimeTypeNameList> ::= "<MimeTypeName>(,<MimeTypeName>)*"

gam user user@domain.com print filelist fields id,name,mimetype showmimetype prefixes audio,video
```

Fix bug in `gam <UserTypeEntity> info|show sheet <DriveFileEntity>` that caused a trap.

6.71.11

Added option `addcsvdata <FieldName> <String>` to `gam print cros` that adds
additional columns of data to the CSV file output. Typically, you would read CSV file of device IDs/serial numbers
to generate a CSV file of results and copy data from the input CSV to the outout CSV.

6.71.10

Reverted change made in 6.71.09 to `gam <UserTypeEntity> print filelist` when `showmimetype` and `filepath|fullpath`
were both specified. The change improved the performance when `showmimetype` selected a small number of files;
the information for just those files was downloaded and then additional API calls were made to construct the file paths.
However, if a large number of files were selected, the additional APIs calls decreased performance.

Added option `mimetypeinquery` can be used when you expect the query to return a small number of files
relative to the total number of files.

6.71.09

Improved the performance of `gam <UserTypeEntity> print filelist` when `showmimetype` and `filepath|fullpath`
are both specified.

6.71.08

Added option `oneitemperrow` to 'gam print admins|adminroles` to have each of a
roles privileges displayed on a separate row with all of the other admin/role fields.
This produces a CSV file that can be used in subsequent commands without further script processing.

6.71.07

Added command to upload changes to Google Docs.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Manage#upload-changes-to-google-documents

6.71.06

Added additional error handling to Gmail Client Side Encryption commands.

Added license product Education Endpoint Management
* ProductID - 101049

Added license SKU Endpoint Education Upgrade
* ProductID - 101049
* SKUID - 1010490001 | eeu

6.71.05

Fixed a bug introduced in 6.71.00 that caused a trap in `gam <UserTypeEntity> print filelist`.

Added option `tdfrom <EmailAddress>` to  `<ToDriveAttribute>` that causes GAM to use `<EmailAddress>` as the from address
in all emails sent. By default, the from address is the Google Workspace Admin in `gam oauth info`.o

6.71.04

Updated `gam <UserTypeEntity> create|update cseidentity` to accept either of the following key pair options:
* `primarykeypairid <KeyPairID>` - The configuration of a CSE identity that uses the same key pair for signing and encryption.
* `signingkeypairid <KeyPairID> encryptionkeypairid <KeyPairID>` - The configuration of a CSE identity that uses different key pairs for signing and encryption.

Updated CSV output row sorting to avoid a trap that occurred when a row was missing one of the sort fields.

6.71.03

Added option `tdalert <EmailAddress>` to `<ToDriveAttribute>`. When a todrive file is created or updated,
GAM will send notification emails to all `tdalert <EmailAddress>` users if `tdnotify` is true.
`<EmailAddress>` must be valid within your Google Workspace.

6.71.02

Added additional error handling to Gmail Client Side Encryption commands.

6.71.01

Fixed bug in `gam audit monitor create` that caused a trap.

6.71.00

Added `csv_output_sort_headers` string list variable to `gam.cfg` that causes GAM to sort CSV output
rows by the column headers specified in the variable. The column headers are case insensitive and
if column header does not appear in the CSV output, it is ignored.

Added `sortheaders <StringList>` to `redirect csv <FileName>` that has the same effect as above.

The sort keys specified in `redirect csv ... sortheaders <StringList>` take precedence over the values from `gam.cfg`.

Added option `tdsubject <String>` to  `<ToDriveAttribute>` that causes GAM to use `<String>` as the subject
in all emails sent. In `<String>`, `#file#` will, be replaced by the file title and `#sheet#` will be replaced
by the sheet/tab title. By default, the subject is the file title.

6.70.09

Added additional error handling to Gmail Client Side Encryption commands.

Added options `showpem` and `showkaclsdata` to all Gmail CSE commands that process/display
CSE key pairs. By default, the `pem` and `kaclsdata` fields will not be displayed unless
the corresponding `show` option is specified.

6.70.08

Fixed bug in `gam <UserTypeEntity> create cseidentity <KeyPairID>` that caused an error.

6.70.07

Updated user instructions in `gam oauth create` and `gam <UserTypeEntity> update serviceaccount`
and changed `s` from selecting all scopes to selecting default scopes.

6.70.06

Updated `gam info users <UserTypeEntity>` to not include group tree infornation unless option `grouptree` is specified.

6.70.05

Added commands to create|delete|display Drive Label permissions.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Labels

6.70.04

Added option `showvalidcolumn` to `gam print users` that can be used to identify whether
users are defined in the domain. Typically, you would read CSV file of email addresses
to verify as domain members.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users#verify-domain-membership

Added option `addcsvdata <FieldName> <String>` to `gam print users` that adds
additional columns of data to the CSV file output. Typically, you would read CSV file of email addresses
to generate a CSV file of results and copy data from the input CSV to the outout CSV.

6.70.03

Renamed license product DuetAI to Gemini
* ProductID - 101047

Renamed license SKU DuetAI for Google Workspace to Gemini Enterprise
* ProductID - 101047
* SKUID - 1010470001 | geminient | duetai 

Added support for license SKU Gemini Business
* ProductID - 101047
* SKUID - 1010470003 | geminibiz

6.70.02

In 6.69.00, GAM starting using course owner access when using `copyfrom` in `gam create|update course`
regardless of the value of `gam.cfg/use_course_owner_access`. This prevents copying from courses
with a deleted user. GAM now uses the value of `gam.cfg/use_course_owner_access` when `copyfrom` is used.

6.70.01

Added `gmail_cse_incert_dir` and `gmail_cse_inkey_dir` path variables to `gam.cfg` that provide
default values for the `incertdir <FilePath>` and `inkeydir <FilePath>` options in `gam <UserTypeEntity> create csekeypair`.

6.70.00

Added support for Gmail Client Side Encryption.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-CSE

This is an initial, minimally tested release; proceed with care and report all issues.

6.69.00

Added `use_course_owner_access` Boolean variable to `gam.cfg` that controls how GAM gets
classroom member information and removes students/teachers. Client/admin access does not provide
complete information about non-domain students/teachers.
* `False` - Use client/admin access; this is the default. Use if you don't have non-domain members in your courses.
* `True` - Use service account access as the classroom owner. An extra API call is required per course to authenticate the owner; this will affect performance

Added the following command which must be used to delete classroom invitations for non-domain students/teachers.
```
gam delete classroominvitation courses <CourseEntity> (ids <ClassroomInvitationIDEntity>)|(role all|owner|student|teacher)
```
You can obtain the classroom invitation IDs with these commands:
```
gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [role all|owner|student|teacher] [formatjson]
gam print classroominvitations [todrive <ToDriveAttribute>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [role all|owner|student|teacher] [formatjson [quotechar <Character>]]
```

6.68.08

Updated `gam <UserTypeEntity> print filelist|drivefileacls|shareddriveacls ... oneitemperrow` to print
ACLs with multiple permission details on separate rows for each basic permission/permission detail combination.
This case occurs when a member of a Shared Drive has access to a file and also has explicitly granted access to the same file.

Added `permtype member|file` to `<PermissionMatch>` that allows determining whether an ACL on a Shared Drive file was
derived from membership or explicitly granted.

6.68.07

Updated `gam info user ... locations formatjson` to include the `buildingName` field in the
`locations` entries. If `gam.cfg` contains `quick_info_user = true` or the `quick` option
is included on the command line, add the option `buildingnames` to the command line.

6.68.06

Fixed bug in `gam <UserTypeEntity> copy drivefile <DriveFileID> ... mergewithparent` that incorrectly named
the copied file with the name of the parent folder.

Updated `gam <UserTypeEntity> copy|move drivefile` to avoid copying/moving the same file twice.

6.68.05

Updated `gam print groups ... ciallfields|(cifields <CIGroupFieldNameList>)` to account for an
API shortcoming that failed to get all of the Cloud Identity fields.

6.68.04

Added option `skiprows <Integer>` to `gam csv|loop` that causes GAM to skip processing the first `<Integer>` filtered rows.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Bulk-Processing#csv-files

6.68.03

Fixed bug in `gam <UserTypeEntity> create drivefileacl` that caused a trap.

6.68.02

Upgraded to Python 3.12.2 where possible.

Added options `restricted|(audience <String>)` to `gam <UserTypeEntity> create|update chatspace` that
sets the access options for the chat space. These options are in Developer Preview and will not be generally available.

6.68.01

Fixed `<PermissionMatch>` bug for real.

6.68.00

Fixed `<PermissionMatch>` bug introduced in 6.67.35 that caused a command error like the following or would
not properly match `type|nottype <DriveFileACLType>` and `role|notrole <DriveFileACLRole>`.

```
ERROR: permission attribute allowfilediscovery/withlink not allowed with type {'a', 'y', 'e', 'o', 'n'}
```

My sincere apologies.

6.67.39

Added option `wait <Integer> <Integer>` to `gam create datatransfer` that causes GAM to wait
for the transfer to complete. The first `<Integer>` must be in the range 5-60 and is the number
of seconds between checks to see if the transfer has completed. The second `<Integer>` is the maximum
number of checks to perform. By default, GAM does not wait for the transfer to complete.

6.67.38

Added option `tdnotify [<Boolean>]` to `<ToDriveAttribute>` that causes GAM to send notification
emails to all `tdshare <EmailAddress>` users when the file is uploaded/updated.

6.67.37

Fixed bug in `gam <UserTypeEntity> show messages ... showattachments` to avoid a trap when `text/plain` attachments
in character sets other than `UTF-8` are displayed.

6.67.36

Updated `gam batch <BatchContent>` and `gam tbatch <BatchContent>` commands to accept lines with the following form:
```
sleep <Integer>
```
Batch processing will suspend for `<Integer>` seconds before the next command line is processed.

6.67.35

Added the following options to `<PermissionMatch>` that allow more powerful matching.
```
nottype <DriveFileACLType>
typelist <DriveFileACLTypeList>
nottypelist <DriveFileACLTypeList>
rolelist <DriveFileACLRoleList>
notrolelist <DriveFileACLRoleList>
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Permission-Matches#define-a-match

6.67.34

Added option `movetoorgunitdelay <Integer>` to `gam <UserTypeEntity> create shareddrive <Name> ... ou|org|orgunit <OrgUnitItem>`.
GAM creates the Shared Drive, verifies that it has been created and then tries to move it to `<OrgUnitItem>`. Google seems to
require a delay or the following error is generated.
```
ERROR: 409: 409 - The operation was aborted.
```
`movetoorgunitdelay` defaults to 20 seconds which seems to work; `<Integer>` can range from 0 to 60.

6.67.33

Upgraded to OpenSSL 3.2.1 where possible.

Fixed bug in `gam <UserTypeEntity> print shareddrives` where `role` was improperly displayed as `fileOrganizer`
rather than `writer`.

Added option `guiroles [<Boolean>]` to `gam <UserTypeEntity> info|print|show shareddrive` that maps
the Drive API role names to the Google Drive GUI role names.
```
API: GUI
commenter: Commenter
fileOrganizer: Content manager
organizer: Manager
reader: Viewer
writer: Contributor
```

6.67.32

Updated `<ToDriveAttribute>` to allow multiple `tdshare <EmailAddress> commenter|reader|writer` options.

Fixed bug in `gam <UserTypeEntity> print shareddrives` where `role` was improperly displayed as `unknown`
rather than `reader` when `Allow viewers and commenters to download, print, and copy files` was unchecked for the Shared Drive.

6.67.31

Updated `gam <UserTypeEntity> claim|transfer ownership <DriveFileEntity>` to properly
handle the case where `<DriveFileEntity>` referencess a Drive shortcut.

6.67.30

Fixed bug where the `fullpath` option in various commands was not converting the generic shared drive name `Drive` to the drive's actual name.

6.67.29

Added optional argument `owneraccess` to `gam courses <CourseEntity> remove teachers|students [owneracccess] <UserTypeEntity` and
`gam course <CourseID> remove teacher|student [owneraccess] <EmailAddress>` in order to test a possible API change.

Updated code to avoid a trap when `gam config auto_batch_min 1 csv file.csv gam ...` was entered.
The `config auto_batch_min 1` is not appropriate in this context and will be ignored.

6.67.28

Improved handling of `Bad Request` error in `gam <UserTypeEntity> collect orphans`.

6.67.27

Updated `gam <UserTypeEntity> collect orphans` to handle the following error:
```
ERROR: 400: badRequest - Bad Request
```

6.67.26

Fixed bug in `gam print vaultexports ... formatjson` that caused a trap.

6.67.25

Added option `owneraccess` to `gam info courses <CourseEntity>` and `gam info course <CourseID>` in order
to test a possible API change.

6.67.24

Fixed bug that caused HTML password notification email messages to be displayed in raw form.

6.67.23

Use local copy of `googleapiclient` to remove static discovery documents to improve performance.

6.67.22

Added `permissionidlist <PermissionIDList>` to `<PermissionMatch>` that allows matching any permission ID in a list.

Added option `exportlinkeddrivefiles <Boolean>` to `gam create vaultexport` that is used with `corpus mail`.

6.67.21

Updated `gam remove aliases <EmailAddress> user|group <EmailAddressEntity>` to give a more informative
error message when the target/alias combination does not exist.
```
Old: User: testsimple@domain.com, User Alias: tsalias@domain.com, Remove Failed: Invalid Input: resource_id
New: User: testsimple@domain.com, User Alias: tsalias@domain.com, Remove Failed: Does not exist
```

6.67.20

Added option `onelicenseperrow|onelicenceperrow` to `gam print users ... licenses` that causes GAM to print
a seperate user information row for each license a user is assigned. This makes processing
the licenses in a script possible and allows better sorting in a CSV File.

By default, all licenses for a user are displayed in a list on one row:
```
primaryEmail,LicensesCount,Licenses,LicensesDisplay
user@domain.com,2,1010020020 1010330004,Google Workspace Enterprise Plus Google Voice Standard
```
With `onelicenseperrow|onelicenceperrow`, each license is on a separate row:
```
primaryEmail,License,LicenseDisplay
user@domain.com,1010020020,Google Workspace Enterprise Plus
user@domain.com 1010330004,Google Voice Standard
```

6.67.19

Updated `gam create|update user ... notify` to encode the characters `<>&` in the password
so that they display correctly when the notify message content is HTML.

6.67.18

Cleaned up `Getting/Got` messages for `gam print courses|course-participants`.

6.67.17

Added option `showitemcountonly` to various commands that causes GAM to display the
item count on stdout; no CSV file is written.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups#display-group-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Courses#display-course-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Membership#display-course-membership-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices#display-cros-device-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices#display-device-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices#display-device-user-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups#display-group-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Mobile-Devices#display-mobile-device-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Organizational-Units#display-organizational-unit-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Resources#display-resource-counts
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users#display-user-counts

6.67.16

By default, `gam print group-members membernames` displays `Unknown` for members whose names can not be determined.
Added option `unknownname <String>` that let's you specify an alternative value.

Further improved performance of `gam print group-members membernames cachememberinfo`.

6.67.15

Update `gam print group-members membernames` to handle the following error:
```
ERROR: 400: failedPrecondition - Precondition check failed.
```

Added option `cachememberinfo [Boolean]` to `gam print group-members` that causes GAM to cache member info
so that only one API call is made to get information for each user/group. This consumes
more memory but dramatically reduces the number of API calls.

6.67.14

Updated reseller commands to handle the following error:
```
ERROR: 400: invalid - Customer domain [domain.com] is linked to one or more email verified customers, please provide a customer id.
```

6.67.13

Updated `gam create domain <DomainName>` to handle the following error:
```
ERROR: 409: conflict - Domain in request is in use by an email verified customer.
```

6.67.12

Added option `addcsvdata <FieldName> <String>` to `gam print datatransfers` that adds
additional columns of data to the CSV file output.

6.67.11

Updated various Gmail related commands to handle this error:
```
ERROR: 403: permissionDenied - Insufficient Permission
```
when the following service account scopes are selected:

```
[ ] 23)  Gmail API - Basic Settings (Filters,IMAP, Language, POP, Vacation) - read/write, Sharing Settings (Delegates, Forwarding, SendAs) - read
[ ] 24)  Gmail API - Full Access (Labels, Messages)
[ ] 25)  Gmail API - Full Access (Labels, Messages) except delete message
[*] 26)  Gmail API - Full Access - read only
[ ] 27)  Gmail API - Send Messages - including todrive
[ ] 28)  Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write
```

6.67.10

Fixed bug that caused a trap when optional argument `charset <Charset>` was used with `emlfile <FileName>` in `gam <UserTypeEntity> draft|import|insert message`.

6.67.09

Added option `maxevents <Number>` to `gam report <ActivityApplictionName>` that limits
the number of events displayed for each activity; the default is 0, no limit.
Setting options `maxactivities 1 maxevents 1 maxresults 1` can be used to as efficiently as possible
show the most recent activity/event; this can be useful when reporting drive activity for individual drive files.

6.67.08

Added optional argument `charset <Charset>` to `emlfile <FileName>` in `gam <UserTypeEntity> draft|import|insert message`;
the default value is `ascii`.

6.67.07

Updated `gam <UserTypeEntity> delete message` to handle this error:
```
ERROR: 403: permissionDenied - Insufficient Permission
```
when the following service account scopes are selected:

```
[ ] 24)  Gmail API - Full Access (Labels, Messages)
[*] 25)  Gmail API - Full Access (Labels, Messages) except delete message
```

6.67.06

Updated commands that create ACLs to handle the following error:
```
ERROR: 400: abusiveContentRestriction - Bad Request. User message: "You cannot share this item because it has been flagged as inappropriate."
```

6.67.05

Updated the following commands:
```
gam <UserTypeEntity> create|delete|update delegate
gam <UserTypeEntity> forward
gam <UserTypeEntity> create|delete forwardingaddresses
gam <UserTypeEntity> create|delete sendas
```
to handle this error:
```
ERROR: 403: permissionDenied - Insufficient Permission
```
when the following serice account scope is not enabled:
```
[ ] 28)  Gmail API - Sharing Settings (Delegates, Forwarding, SendAs) - write
```

6.67.04

Updated user attribute `replace <Tag> <UserReplacement>` to allow `field:photourl` which allows
embedding a link to a user's photo in their signature. Formatting the signature HTML
to properly display the photo is left to the GAM admin.

6.67.03

Fixed bug introduced in 6.67.02  in `gam <UserTypeEntity> claim ownership` that caused a trap.

6.67.02

Added option `skipids <DriveFileEntity>` to `gam <UserTypeEntity> copy drivefile` that handles special cases
where you want to prevent selected files/folders from being copied.

Updated commands that create files/folders on Shared Drives to handle the following errors:
```
storageQuotaExceeded
teamDriveFileLimitExceeded
teamDriveHierarchyTooDeep
```
* See: https://support.google.com/a/users/answer/7338880#shared_drives_file_folder_limits

6.67.01

Fixed bug in `gam print vaultcounts` that caused a trap.

6.67.00

Updated `gam <CrOSTypeEntity> update action <CrOSAction>` to use the new API function `batchChangeStatus`
that replaces the old API function `action`; ChromeOS devices are now processed in batches.
The batch size defaults to 10, the `actionbatchsize <Integer>` option can be used to set a batch size between 10 and 250.

Updated `gam create vaultexport matter <MatterItem>` to support `corpus calendar`.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault-Takeout#create-vault-exports

6.66.16

Added option `convertcrnl` to `gam update chromepolicy` to properly handle carriage returns (\r) and line feeds (\n)
in value strings entered on the command line in the `<Field> <Value>` form. 
```
gam update chromepolicy convertcrnl chrome.devices.DisabledDeviceReturnInstructions
    deviceDisabledMessage "Please return device to:\nSchool\n123 Main Street\nAnytown US" ou /Path/to/OU
```

6.66.15

Added option `copysubfilesownedby any|me|others` to `gam <UserTypeEntity> copy drivefile` that allows
specification of which source folder sub files to copy based on file ownership; the default is `any`.
This only applies when files are being copied from a 'My Drive'.

6.66.14

Updated `gam <UserTypeEntity> modify messages` to recognize the following error:
```
ERROR: 400: invalid - Invalid label: SENT
```

Updated `gam update alias <EmailAddressEntity> user|group|target <EmailAddress>`
to avoid the following problem.
```
$ gam update alias testalias@domain.com user testuser
User Alias: testalias@domain.com, Deleted
User Alias: testalias@domain.com, User: testuser@domain.com, Update Failed: Duplicate, Email Address: testalias@domain.com
```
GAM updates an alias to point to a new target by deleting the alias and then recreating the alias pointing to the new target.
Unfortunately, if these commands are executed back-to-back; Google generates the `Update Failed: Duplicate` error.
Now, GAM waits 2 seconds between the delete and the insert which seems to eliminate the problem. If the problem persists,
the option `waitafterdelete <Integer>` can be used to increase the wait time to a maximum of 10 seconds.

6.66.13

Updated functionality of option `preservefiletimes` in `gam <UserTypeEntity> update drivefile <DriveFileEntity>`.

* Current
  * `preservefiletimes localfile <FileName>` - `modifiedTime` of `<DriveFileEntity>` is set to that of `localfile <FileName>`
  * `preservefiletimes` - No effect
* Updated
  * `preservefiletimes localfile <FileName>` - `modifiedTime` of `<DriveFileEntity>` is set to that of `localfile <FileName>`
  * `preservefiletimes` - `modifiedTime` of `<DriveFileEntity>` retains its current value

6.66.12

Upgraded to Python 3.12.1 where possible.

Updated all drive commands to handle the following error:
```
ERROR: 401: Active session is invalid. Error code: 4 - authError
```
This is due to the Drive SDK API being disabled in the user's OU.
* See: https://support.google.com/a/answer/6105699

6.66.11

Fixed/improved handling of shortcuts in `gam <UserTypeEntity> transfer drive`.

6.66.10

Updated `gam create datatransfer` to handle the following error:
```
ERROR: 401: Active session is invalid. Error code: 4 - authError
```

6.66.09

Fixed bug in `gam <UserTypeEntity> print filelist ... allfields` that caused a trap
when `gam.cfg` contained `drive_v3_native_names = False`.

6.66.08

Added additional columns `isBase` and `baseId` to `gam <UserTypeEntity> print fileparenttree`
to simplify  processing the output in a script.

6.66.07

Fixed bug in `gam <UserTypeEntity> print diskusage` that caused a trap.

6.66.06

Added a command the print the parent tree of file/folder.
```
gam <UserTypeEntity> print fileparenttree <DriveFileEntity> [todrive <ToDriveAttribute>*]
        [stripcrsfromname]
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#display-file-parent-tree

6.66.05

Added column `space.name` to `gam <UserTypeEntity> print chatmembers`.

6.66.04

Updated Chat info|show|print commands to display all time fields in local time if specified in `gam.cfg`.

6.66.03

Fixed bug in `gam <UserTypeEntity> print filelist select <DriveFileEntity>` where `stripcrsfromname` was not being
applied to files below the selected folder.

6.66.02

Updated device commmands to handle the following error caused by an invalid query.
```
ERROR: 400: invalidArgument - Request contains an invalid argument.
```

Added fields `deviceid` and `hostname` to `<DeviceFieldName>`.

6.66.01

Added the following variables to gam.cfg that allow control over whether `\` is used as an escape character
when reading/writing CSV files.
```
csv_input_no_escape_char - default value True
csv_output_no_escape_char - default value False
todrive_no_escape_char - default value True
```
When the value is True, `\` is ignored as an escape character; when the value is False,
`\\` on input is converted to `\`, `\` on output is converted to `\\`.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Special-Characters

6.66.00

Added support for `Focus Time` and `Out of Office` status events in user's primary calendars.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events#status-events
This is a work-in-progress.

Updated `gam <UserTypeEntity> print|show messages` to allow option `show_size` to be used with option `countsonly`
to display the cumulative size of the messages selected.
```
gam user user@domain.com print messages query "newer_than:31d" countsonly showsize
Getting all Messages for user@domain.com
Got 16 Messagess for user@domain.com...
User,messages,size
user@domain.com,16,92806
```

6.65.17

Added the option `mappermissionsdomain <DomainName1> <DomainName2>` to `gam <UserTypeEntity> create drivefileacl <DriveFileEntity>`
that maps `<DomainName1>` to `<DomainName2>` in the `user <UserItem>)|(group <GroupItem>)|(domain <DomainName>)` options;
`<UserItem>` and `<GroupItem>` must specify email addresses for the mapping to succeed.
The option can be specified multiple times to provide different mappings. This option will be most useful
when reading a CSV file containing ACLs referencing `<DomainName1>` and you want a new ACL with the same options but in `<DomainName2>`.

6.65.16

Fixed bug in `gam <UserTypeEntity> print filecounts` where `Item Cap` showed an incorrect value.

Added option `addorigfieldstosubject` to `gam <UserTypeEntity> forward messages|threads` that causes GAM
to append  the original `from`, `to` and `date` fields to the message subject.
```
Fwd: Ross to TestUser (Original From: Ross Scroggs <ross.scroggs@gmail.com> To: testuser@domain.com Date: Thu, 23 Nov 2023 07:01:59 -0800)
```

6.65.15

Added additional options to `gam <UserTypeEntity> print|show youtubechannels`.

6.65.14

Fixed bug in gam <UserTypeEntity> copy|move drivefile` that caused a trap.
```
UnboundLocalError: cannot access local variable 'emailAddress' where it is not associated with a value
```

6.65.13

Added support for user language `en-CA`.

Added option `sizefield quotabytesused|size` to the following commands that specifies which
file size field to use when totaling file sizes; the default value is `quotabytesused`; previous versions used `size`.
```
gam <UserTypeEntity> print|show filecounts
gam <UserTypeEntity> print filelist
gam <UserTypeEntity> print|show filetree
gam <UserTypeEntity> print diskusage
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#file-size-fields

6.65.12

Additional updates on MacOS when a `gam csv` command is interrupted with a contol-C.

6.65.11

Updated multiprocessing to handle the following error that occurs on MacOS when a `gam csv` command
is interrupted with a contol-C.
```
multiprocessing/resource_tracker.py:224: UserWarning: resource_tracker: There appear to be N leaked semaphore objects to clean up at shutdown
```

Fixed bug in `gam print|show crostelemetry` where no CrOS device data was displayed if no selection
options were chosen; now, data is displayed for all CrOS devices as documented.

6.65.10

Fixed bug in `gam print crostelemetry` that caused a trap: `KeyError: 'reportTime'`.

6.65.09

Added option `noduplicate` to `gam <UserTypeEntity> create drivefile` that causes GAM
to issue a warning and not perform the create if a non-trashed item with the same name (regardless of MIME type)
exists in the parent folder.

Updated `gam <UserTypeEntity> get drivefile <DriveFileEntity>` to handle the following error
that seems to occur when multiple tabs from a Google sheet are being downloaded in parallel.
```
Download Failed: HTTP Error: 429
```

6.65.08

Added option `addcsvdata <FieldName> <String>` to `gam report <ActivityApplicationName>` that adds
additional columns of data to the CSV file output.

Added option `shownoactivities` to `gam report <ActivityApplicationName>` that causes GAM to display
a row with a key value of `NoActivities` when there are no activities to report.

For example, to find Shared Drives with no activity, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Reports#find-shared-drives-with-no-activity

6.65.07

Updated `gam delete building` to handle the following error:
```
ERROR: 412: conditionNotMet - Cannot delete building because there are Calendar resources associated with it.
```

6.65.06

Improved error message when trying to add external students/teachers to a course.
```
gam courses 544906261666 add student user@gmail.com
Course: 544906261666, Add 1 Student
  Course: 544906261666, Student: user@gmail.com, Add Failed: 403: permissionDenied - @CannotDirectAddUser Unable to directly add the user to the course. Please check that the user account exists and is within the course admin's domain. Add external user with: gam user user@gmail.com create classroominvitation courses 544906261666 role Student
```

6.65.05

Updated `gam info users <UserTypeEntity>` to make option `grouptree` effective when used
with option `formatjson`.

Added option `[formatjson [quotechar <Character>]]]`
to these commands so that event details are displayed in CSV format.
```
gam print|show grouptree <GroupEntity>
gam <UserTypeEntity> print|show grouptree
```

Added option `querytime<String> <Date>` to all commands that process messages.
For example, you can identify all messages within a particular time period, in this case, all messages unread
in the last 30 days.
```
gam user user@domain.com  print messages querytime30d -30d query "after:#querytime30d# is:unread"
```

Updated `gam <UserTypeEntity> import|insert message` to allow `replace <Tag> <UserReplacement>` as documented.

Updated non-owner permission handling in `gam <UserTypeEntity> copy|move drivefile`.

6.65.04

Fixed bug where license SKU `1010020031` (Google Workspace Frontline Standard) was improperly entered making it unusable;
its alias `wsflwstan` was usable.

Added support for Google Workspace Additional Storage.
* ProductID - 101043
* SKUID - 1010430001 | gwas | plusstorage

6.65.03

Fixed bug in commands that display calendar events where event start and end times were not properly displayed
when `gam.cfg` had `timezone utc`. The API returns the start and end times expressed in the calendar timezone
but GAM replaced the timezone specifier with a `Z`; the date and time values were as expected. This became
a problem when event data was exported and used to create or update events.

6.65.02

Updated `gam print|show browsers` to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.65.01

Added option `showmimetypesize` to `gam <UserTypeEntity> print|show filecounts` and
`gam <UserTypeEntity> print filelist countsonly` that displays the total file size for each MIME type.

6.65.00

Fixed bug in `gam <UserTypeEntity> create contact <JSONData>` that caused a trap when
contacts were being copied from one user to another.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People-Contacts-Profiles#copy-user-contacts-to-another-user

Updated the following commands to allow specification of a task list by its title.
```
<TaskListTitle> ::= tltitle:<String>
<TasklistTitleList> ::= "'<TasklistTitle>'(,'<TasklistTitle>')*"
<TasklistEntity> ::=
        <TasklistIDList> | <TaskListTitleList> | <FileSelector> | <CSVFileSelector>

gam <UserTypeEntity> create task <TasklistEntity>
gam <UserTypeEntity> show tasks [tasklists <TasklistEntity>]
gam <UserTypeEntity> print tasks [tasklists <TasklistEntity>]
gam <UserTypeEntity> update tasklist <TasklistEntity>
gam <UserTypeEntity> delete tasklist <TasklistEntity>
gam <UserTypeEntity> clear tasklist <TasklistEntity>
gam <UserTypeEntity> info tasklist <TasklistEntity>
```

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Tasks#specifying-task-lists

6.64.16

Fixed bug in `gam <UserTypeEntity> create task <TasklistIDEntity>` that caused a trap
when an invalid TaskListID was specified.

6.64.15

Updated `lookerstudioassets|lookerstudiopermissions` commands to handle the following error:
```
ERROR: 500: internalError - Internal error encountered.
```

6.64.14

Cleaned up and renamed `gam info appdetails` to `gam info chromeapp`.

6.64.13

Added command to get chrome app details.
```
gam info appdetails android|chrome|web <AppID> [formatjson]
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Installed-Apps

6.64.12

Upgraded to Python 3.12.0 where possible.
Upgraded to OpenSSL 3.1.3 where possible.

6.64.11

Added support for Google Workspace Labs license.
* ProductID - 101047
* SKUID - 1010470002 | gwlabs | workspacelabs

6.64.10

Fixed bug introduced in 6.64.09 that caused a trap when `gam redirect csv <FileName> multiprocess` was used.

6.64.09

Eliminated extraneous `permisssions.0.xxxx` headers in `gam <UserTypeEntity> print filelist ... oneitemperrow`
that appeared when some user in `<UserTypeEntity>` had no files to display.

6.64.08

Fixed bug in `redirect csv - todrive tdtitle "File Title" tdsheettitle "Sheet Title"` where
"Sheet Title" was not assigned to the new sheet.

6.64.07

Updated `gam <UserTypeEntity> move drivefile` to handle the following error:
```
ERROR: 403: targetUserRoleLimitedByLicenseRestriction - Cannot set the requested role for that user as they lack the necessary license
```

6.64.06

Added fields `devicelicensetype` and `osupdatestatus` to `<CrOSFieldName>`.

6.64.05

Added `matchfield organizerself <Boolean>` to `<EventMatchProperty>` to simplify selecting events
where the user in the following commands is/is not the organizer of the event.
```
gam <UserTypeEntity> update events <UserCalendarEntity> [<EventEntity>]
gam <UserTypeEntity> delete events <UserCalendarEntity> [<EventEntity>]
gam <UserTypeEntity> purge events <UserCalendarEntity> [<EventEntity>]
gam <UserTypeEntity> move events <UserCalendarEntity> [<EventEntity>]
gam <UserTypeEntity> info events <UserCalendarEntity> [<EventEntity>]
gam <UserTypeEntity> show events <UserCalendarEntity> [<EventEntity>]
gam <UserTypeEntity> print events <UserCalendarEntity> [<EventEntity>]
gam <UserTypeEntity> update calattendees <UserCalendarEntity> <EventEntity>
```

6.64.04

Updated `gam calendars <CalendarEntity> move events` and `gam <UserTypeEntity> move events <UserCalendarEntity>`
to handle the following error:
```
ERROR: 400: badRequest - Bad Request
```

6.64.03

Updated `gam <UserTypeEntity> get drivefile` to allow downloading Jamboard files; they must be downloaded with `format pdf`.

6.64.02

Updated `gam <UserTypeEntity> transfer drive` to handle the following error:
```
ERROR: 400: Bad Request. User message: "The action cannot be performed on an item of mime-type: application/vnd.google-apps.shortcut" - invalidSharingRequest
```

6.64.01

Updated `gam <UserTypeEntity> print|show youtubechannels` to handle the following error:
```
ERROR: 403: unsupportedSupervisedAccount - Access Forbidden. The authenticated user cannot access this service.
```

6.64.00

Added support for displaying users YouTube channels.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-YouTube

6.63.19

Fixed bug in `gam print vacation` where `endDate` value was not converted to `yyyy-mm-dd` format.

6.63.18

Updated `gam print|show ownership` to show the correct file owner when the most recent event is `change_owner`.

6.63.17

Added support for Duet AI license.
* ProductID - 101047
* SKUID - 1010470001 | duetai

Added `api_call_tries_limit` variable to `gam.cfg` that limits the number of tries
for Google API calls that return an error that indicates a retry should be performed.
The default value is 10 and the range of allowable values is 3-10.

6.63.16

Arguments `noinherit`, `blockinheritance` and `blockinheritance true` have been removed from the following
commands due to an upcoming API change that no longer allows blocking OU setting inheritance.
Arguments `inherit` and `blockinheritance false` are still valid.
```
gam create org <OrgUnitPath>
gam update org <OrgUnitItem>
gam update orgs <OrgUnitEntity>
```

6.63.15

Added `print_cros_ous` and `print_cros_ous_and_children` variables to `gam.cfg` that provide a default list of OUs for these commands:
```
gam print cros
gam print crosactivity
```

Updated `group` commands that manage members to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

Updated Data Studio to Looker Studio; added the following command synonyms:
* `lookerstudioassets` for `datastudioassets`
* 'lookerstudiopermissions` for `datastudiopermissions`

Corrected error message in `gam add datastudiopermissions`:
* Old -`ERROR: Missing argument: Expected <DataStudioAssetMembersEntity>`
* New - `ERROR: Missing argument: Expected <LookerStudioPermissionEntity>

6.63.14

Added option `verifyorganizer [<Boolean>]` to `gam <UserTypeEntity> copy|move drivefile`. When a copy/move
operation involves a Shared Drive, GAM verifies that the user is an organizer. Unfortunatley, this fails
when the user is not a direct organizer but is a member of a group that is an organizer. Specifying
`verifyorganizer false` suppresses the verification.

Updated the following commands to be able to specify a list of domains rather than a single domain:
```
gam print alias|aliases
gam print groups
gam print|show group-members
gam print users
```
Added `print_agu_domains` variable to `gam.cfg` that provides a default list of domains for these commands.

When multiple domains are specified and a query/queries are specified, an API call is made for each domain/query combination.
```
$ gam print users domains school.org,students.school.org queries "'email:admin*','email:test*'"
Getting all Users that match query (domain=school.org, query="email:admin*"), may take some time on a large Google Workspace Account...
Got 3 Users: admin@school.org - admindirector@school.org
Getting all Users that match query (domain=school.org, query="email:test*"), may take some time on a large Google Workspace Account...
Got 20 Users: testusera@school.org - testuserx@school.org
Getting all Users that match query (domain=students.school.org, query="email:admin*"), may take some time on a large Google Workspace Account...
Got 1 User: admin@students.school.org - admin@students.school.org
Getting all Users that match query (domain=students.school.org, query="email:test*"), may take some time on a large Google Workspace Account...
Got 1 User: testuser1@students.school.org - testuser1@students.school.org
primaryEmail
...
```

6.63.13

Updated `gam <UserTypeEntity> print filelist ... showdrivename` and `gam <UserTypeEntity> show fileinfo <DriveFileEntity> ... showdrivename`
to show the actual name of Shared Drives in other domains rather than `Drive`.

6.63.12

Updated commands that call the Reports API (including `gam info domain`) to handle a change
in the Reports API that generated the following warning:
```
WARNING: End date greater than LastReportedDate.
```

Added option `showdeleted [<Boolean>]' to `gam <UserTypeEntity> print|show chatmessages`.

6.63.11

Added option `ou_and_children  <OrgUnitItem>` to `gam print|show crostelemetry` to simplify getting
telemetry data for all ChromeOS devices in an OU and its children.

6.63.10

Added option `addcsvdata <FieldName> <String>` to these commands. This adds additional columns of data to the CSV file output
when the `csv` option is used. If a CSV file of calendar information is being used to specify the calenders, fields, e.g., summary
can be added to the ACL output file.
```
gam <UserTypeEntity> print calendaracls <UserCalendarEntity>
gam resource <ResourceID> print calendaracls
gam resources <ResourceEntity> print calendaracls
gam calendar <CalendarEntity> printacl
gam calendars <CalendarEntity> print acls
```

Added commands to show the number of CrOS devices or Users in an entity.
```
gam <CrOSTypeEntity> show count
gam <UserTypeEntity> show count
```

Updated `gam create project` to prompt user to mark `GAM Project Creation` as a trusted app.

6.63.09

Updated `gam create teamdrive` to handle the following error:
```
ERROR: 403: userCannotCreateTeamDrives - The authenticated user cannot create new shared drives.
```

6.63.08

Updated `cigroup` commands to handle the following error:
```
ERROR: 400: invalidArgument - Request contains an invalid argument.
```

6.63.07

Fixed bug in `gam <UserTypeEntity> append sheetrange` that caused a trap when appending to an empty sheet.

Upgraded to Python 3.11.5 where possible.

6.63.06

Updated `cigroup` commands to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.63.05

Updated `inboundsso` commands to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.63.04

Added option `ignorerole` to `gam update groups|cigroups <GroupEntity> sync [<GroupRole>|ignorerole] ... <UserTypeEntity>` that causes GAM
to remove members regardless of role and add new members with role MEMBER. This is a special purpose option, use with caution
and ensure that `<UserTypeEntity>` specifies the full desired membership list of all roles.

6.63.03

Added option `externalusersallowed <Boolean>` to `gam <UserTypeEntity> create chatspace`
that allows creation of chat spaces that allow external users.

Updated commands that process chat members to allow external users.

6.63.02

Fixed bug in `gam <UserTypeEntity> collect orphans` where shortcuts were being created unnecessarily
when `useshortcuts` was false; either by default or when explicitly set.

6.63.01

Added `process_wait_limit` variable to `gam.cfg` that controls how long (in seconds) GAM should wait for all batch|csv processes to complete
after all have been started. If the limit is reached, GAM terminates any remaining processes. The default is 0 which specifies no limit.

Following Jay's lead, added option `alwaysevict` to `gam create|update user` that is used to specify GAM's
behavior when `verifynotinvitable` is not specified and there is a conflict with an unmanaged account.

By default, when creating a user that has a conflict with an unmanaged account, GAM will honor the setting on this page:
  * https://admin.google.com/ac/accountsettings/conflictaccountmanagement

Specifying `alwaysevict` forces GAM to select this setting: `Replace conflicting unmanaged accounts with managed ones`

With `gam update user`, `alwaysevict` only applies if `createifnotfound` is specified and the user was not found to update and must be created.

6.63.00

Added support for calendar working location events.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events#working-location-events

6.62.08

Added option `addcsvdata <FieldName> <String>` to these commands.  This adds additional columns of data to the CSV file output
when the `csv` option is used.
```
gam create contact
gam <UserTypeEntity> create contact
gam <UserTypeEntity> create contactgroup
```

6.62.07

Added option `csv [todrive <ToDriveAttribute>*]` to these commands that causes GAM to output
the contact creator and contact ID in CSV form. This will be useful when bulk contacts are created.

Added `returnidonly` to these commands that causes GAM to return just the
contact ID as output. This will be useful in scripts that create a contact and then
want to perform subsequent GAM commands on the contact.
```
gam create contact
gam <UserTypeEntity> create contact
gam <UserTypeEntity> create contactgroup
```

6.62.06

Added output `Item cap` to `gam <UserTypeEntity> print filecounts select select <SharedDriveEntity>` that
displays the total number of files/folders on the Shared Drive divided by 400000, the maximum number of file/folders on a Shared Drive.

6.62.05

Added progress messages (suppressible)  to `gam <UserTypeEntity> print diskusage`.

6.62.04

Added command `gam <UserTypeEntity> print diskusage` to display disk usage by folder.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#display-disk-usage

6.62.03

Handled Google Directory API bug in `gam print groups` that caused a trap.

6.62.02

Fixed bug introduced in 6.62.01 that caused a trap that broke `redirect csv ... multiprocess`.
My apologies.

6.62.01

Updated code so that when `gam.cfg` variables `csv_output_timestamp_column` and `output_timeformat` are both specified,
the timestamp is output in the alternate output time format.

6.62.00

Added `output_dateformat` and `output_timeformat` variables to `gam.cfg` that provide alternate
output date and time formats that may be required by programs that will be processing the data.
GAM will not accept alternate date/time formats as input.

* See: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes

6.61.21

Updated `gam <UserTypeEntity> empty drivetrash <SharedDriveEntity>` to use new Drive API v3
functionality for emptying the trash of a Shared Drive with a single API call. Previously, GAM had to purge each
individual file and folder in the trash.

6.61.20

Remove `audit.googleapis.com` from the list of project APIs.

6.61.19

Fixed bug in `gam <UserTypeEntity> print|show chatmembers <ChatSpace>` that caused a trap.

6.61.18

Added the following options to `gam [<UserTypeEntity>] create shareddrive` to allow better control
of the create/update process when attributes other than `themeid` are specified.
```
errorretries <Integer> - Number of create/update error retries; default value 5, range 0-10
updateinitialdelay <Integer> - Initial delay after create before update: default value 10, range 0-60
updateretrydelay <Integer> - Retry delay when update fails; default value 10, range 0-60
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Shared-Drives#create-a-shared-drive

6.61.17

Updated `gam print|show vaultexports|vaultholds|vaultqueries` to not set a non-zero return code
when a vault matter changes state from `OPEN` to `CLOSED|DELETED` while the command is being processed.

Updated `gam create shareddrive <Name> ou|org|orgunit <OrgUnitItem>` to handle the following error:
```
ERROR: 403: permissionDenied - Request had insufficient authentication scopes.
```
It's not clear what causes the error.

6.61.16

Added the following license SKUs.
```
1010060005 - Google Workspace Essentials Plus
1010020031 - Google Workspace Frontline Standard
1010340005 - Google Workspace Business Starter - Archived User
1010340006 - Google Workspace Business Standard - Archived User
```

6.61.15

Added option `contentrestrictions ownerrestricted [<Boolean>]` to `<DriveFileAttribute>`.

6.61.14

Added `aggregatebyuser [Boolean]` option to `gam report user` to allow data aggregation for users across multiple dates.
Options `aggregatebyuser` and `aggregatebydate` are mutually exclusive.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Reports#user-reports

6.61.13

Added commands to display Analytic UA properties.
```
gam <UserTypeEntity> print analyticuaproperties [todrive <ToDriveAttribute>*]
        accountid [accounts/]<String>
        [maxresults <Integer>]
        [formatjson [quotechar <Character>]]
gam <UserTypeEntity> show analyticuaproperties
        accountid [accounts/]<String>
        [maxresults <Integer>]
        [formatjson]
```

6.61.12

Updated `gam print|show vaultexports|vaultholds|vaultqueries` to handle the case
where a vault matter changes state from `OPEN` to `CLOSED|DELETED` while the command is being processed.

6.61.11

Added option `returnidonly` to `gam create vaultexport|vaulthold|vaultmatter`
that causes GAM to return just the ID of the item created as output.

6.61.10

Fixed bug in `gam oauth create admin <EmailAddress>` which caused no scopes to be selected.

6.61.09

Updated `gam oauth create` to handle case where Google takes a very long time to respond
after you have allowed access to the scopes.

6.61.08

Updated `gam <UserTypeEntity> print messages showlabels` to include a column `LabelsCount` to
display the number of labels a message has. Use option `useronly` to limit the labels to user labels.

Updated `gam <UserTypeEntity> print messages` to display these columns, if applicable, as the
last columns in the CSV file.
```
SizeEstimate, LabelsCount, Labels, Snippet, Body
```

6.61.07

Improved action messages in `gam update org|ou <OrgUnitItem> sync <UserTypeEntity> [removetoou <OrgUnitItem>]`.

6.61.06

Added option `csv` to `gam <UserTypeEntity> check group|groups` that displays
the results in CSV format.
```
$ gam user testuser check groups csv testgroup1,testgroup2,alladmin
User: testuser@domain.com, Check in 3 Groups
user,group,role
testuser@domain.com,alladmin@domain.com,Not a MEMBER|OWNER|MANAGER
testuser@domain.com,testgroup1@domain.com,MEMBER
testuser@domain.com,testgroup2@domain.com,MANAGER
```

6.61.05

Fixed bug in `gam print contacts` that caused a trap when `show_gettings = False` in gam.cfg.

6.61.04

Updated `gam create shareddrive <Name>` to wait longer between creating the Drive
and updating any attributes that could not be specified as part of the creation; i.e.,
`<SharedDriveRestrictionsFieldName>`, `hidden`, `customtheme`, `color` and `orgunit`.
The initial wait is 30 seconds. Previously, GAM was not waiting long enough;
the Drive would be created but the update would fail; the attributes were not set.

6.61.03

Updated processing of `<UserMultiAttribute> externalid` to allow an empty `custom` type.
```
externalid account|customer|login_id|network|organization|(custom <String>)|<String> <String>
```
These are equivalent ways of expressing an empty custom type:
```
externalid "" "Value"
externalid custom "" "Value"
```

6.61.02

Fixed bug in `gam update groups <GroupEntity> sync` introduced in 6.60.31 that caused this error:
```
ERROR: 409: generic409 - Member already exists.
```

6.61.01

Added option `noactionifalias` to `gam delete groups <GroupEntity>` that prevents GAM from deleting a
group if `<GroupEntity>` specifies an alias rather than a primary email address.

6.61.00

Following Jay's lead, added `no_short_urls` variable to `gam.cfg`. When false, the long scopes URLs in `gam oauth create` and
`gam <UserTypeEntity> check|update serviceaccount` will be shortened at the site `https://gam-shortn.appspot.com`; the shortened
URL redirects to the long URL. For existing configurations, `no_short_urls` defaults to true; the long URLs are used as is.
For new configurations the `no_short_urls` defaults to false unless there is a file named `noshorturls.txt` in the folder
specified by the environment variable `OLDGAMPATH`.

6.60.31

Added option `addcsvdata <FieldName> <String>` to `gam print forms|formresponses`. This adds additional columns of data to the CSV file output.
This can be used to combine form information from several GAM commands.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Forms#combine-form-information

Following Jay's lead, projects can now be created with consumer accounts.

6.60.30

Added option `countsonly` to `gam <UserTypeEntity> print|show formresponses` that causes GAM to display
the number of responses to a form rather than displaying the response details.

6.60.29

Updated `gam <UserTypeEntity> delete|print emptydrivefolders` to show the path to the deleted folder
rather than just its name. Added an option to allow a starting point other that the root of My Drive or a Shared Drive.
Improved the commands performance.

6.60.28

Fixed bug in `gam <UserTypeEntity> print filelist countsonly showsource stripcrsfromname` where
carriage returns, linefeeds and nulls were not stripped from file names.

6.60.27

Updated `gam <UserTypeEntity> print filelist countsonly` to process `addcsvdata <FieldName> <String>`.
Additional fields are added before `Size` if present, otherwise `Total`.

6.60.26

Added option `orgunit|org|ou <OrgUnitPath>` to `gam print|show teamdrives` that limits the display
to Shared Drives in the specified Org Unit.

6.60.25

Added option `orgunit|org|ou <OrgUnitPath>` to `gam print|show teamdriveacls` that limits the display
of permissions to Shared Drives in the specified Org Unit.

6.60.24

Updated `gam <UserTypeEntity> info|show|print chatmessages` to show the sender email address
when the sender is a human.

6.60.23

Fixed bug in `config csv_input_row_filter|csv_output_row_filter` where "field:date<today" was being processed
as "field:date<=today" and "field:date>=today" was being processeed as "field:date>today".

6.60.22

Added option `pathdelimiter <Character>` to `gam <UserTypeEntity> create drivefolderpath` to simplify
specifying folder paths where a folder name contains a `/`. In the example, some folder has a '/' in it's name
so specifying `pathdelimiter "|"` allows `fullpath` to be properly processed. `pathdelimiter` defaults to '/'.
```
gam user user@domain.com create drivefolderpath pathdelimiter "|" fullpath "My Drive|Top Folder|Middle/Folder|Bottom Folder"
```

6.60.21

Fixed bug in `gam <UserTypeEntity> copy|create|update drivefile` where processing the following `<DriveFileAttribute>` attributes
was not correct. Previously, if multiple properties of the same visibility were specified, only the first was processed;
now, all values are processed.
```
privateproperty <PropertyKey> <PropertyValue>
publicproperty <PropertyKey> <PropertyValue>
property <PropertyKey> <PropertyValue> [private|public]
```

6.60.20

Updated `gam <UserTypeEntity> get document|drivefile <DriveFileEntity>` to handle shortcuts by downloading
the file that the shortcut references as the shortcut itself is not downloadable. If you do not want
this behavior and want GAM to report an error, use the option `donotfollowshortcuts`.

6.60.19

Updated `gam <UserTypeEntity> archive messages` to handle the following error:
```
ERROR: 400: failedPrecondition - Precondition check failed.
```

6.60.18

Updated `gam <UserTypeEntity> print|show tokens` to handle the following error that occurs
when a group email address is specified rather than a user email address.
```
ERROR: 400: badRequest - Type not supported: userKey
```

6.60.17

Fixed bug in `gam <UserTypeEntity> move drivefile` that caused an error when moving the contents
of a source Shared Drive to a target Shared Drive when `mergewithparents` was not specified or was
explicitly set False.

6.60.16

Updated commands that create files to handle the following error:
```
403: storageQuotaExceeded - The user's Drive storage quota has been exceeded.
```

6.60.15

Updated `gam print chromesnvalidity` to do case insenstitive serial number comparisons.

6.60.14

Added command to help verify Chrome device serial number validity.
```
gam print chromesnvalidity [todrive <ToDriveAttribute>*]
        cros_sn <SerialNumberEntity> [listlimit <Number>]
        [delimiter <Character>]
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices#check-chromeos-device-serial-number-validity

6.60.13

Updated `gam <UserTypeEntity> print|show chatspaces` to handle the following error:
```
Error: 403: permissionDenied - Permission denied to perform the requested action on the specified resource
```

6.60.12

Added option `tdretaintitle [<Boolean>]` that, when `True` and used with `tdfileid <DriveFileID>`,
causes GAM to not modify the CSV filename.

6.60.11

Fixed bug in `gam print addresses` where non-editable user/group aliases were not displayed.

6.60.10

Added a command to get information about a direct message chat space between two users.
```
gam <UserTypeEntity> info chatspacedm <UserItem>
        [formatjson]
```

6.60.09

Added option `csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]]`
to these commands so that event details are displayed in CSV format.
```
gam calendar|calendars <CalendarEntity> create|import|update event
gam <UserTypeEntity> create|import|update event <UserCalendarEntity>
```

Added option `additionalmembers [<GroupRole>] <EmailAddressEntity>` to `gam update group|groups <GroupEntity> sync`
that can be used to specify members in addition to those specified with `<UserTypeEntity>`.
```
gam update group teachers@domain.com sync member additionalmembers counselor@domain.com ou /Teachers
```

Added commands to display Analytic account/property/datastream information.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Analytics-Admin

6.60.08

Upgraded to Python 3.11.4 where possible.

6.60.07

Simplified specifying a Chat space name; previously, the `space` keyword was required;
now, it can be omittted and you can just enter `spaces/<String>`.
```
<ChatSpace> ::= spaces/<String> | space <String> | space spaces/<String>
```

6.60.06

Fixed bug in `gam print aliases` that caused a trap.

6.60.05

Updated Chrome Policy commands to handle the following error:
```
ERROR: 403: permissionDenied - The caller does not have permission.
```

6.60.04

Updated `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>` to disallow copying/moving
a folder into itself.

6.60.03

Updated commands to delete chatmembers; `delete chatmembers` now deletes members by
specifying a chat space and user email addresses; `remove chatmembers` deletes members by
specifying chatmember names.
```
gam <UserTypeEntity> delete chatmember space <ChatSpace>
        ((user <UserItem>)|(members <UserTypeEntity>))+
gam <UserTypeEntity> remove chatmember members <ChatMemberList>
```

6.60.02

Added option `<ChatContent>` to `gam <UserTypeEntity> create chatspace` to allow sending an initial message
to the newly created chatspace.

6.60.01

Updated `gam <UserTypeEntity> create chatspace` to support chatspace types `GROUP_CHAT` and `DIRECT_MESSAGE`
and to allow specification of members.

6.60.00

Added initial support for user chat spaces. This is a work in progress, test and report any problems.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Chat

Improved performance of `gam <UserTypeEntity> delete|move|update othercontacts`.

Upgraded to OpenSSL 3.1.1 where possible.

6.59.18

Updated `gam <UserTypeEntity> update drivefile <DriveFileEntity>` to handle the following error:
```
ERROR: 403: fileWriterTeamDriveMoveInDisabled - The domain administrator has not allowed writers to move items into a shared drive.
```

6.59.17

Added option `pathdelimiter <Character>` to the following commands that causes GAM to separate
components in a folder path with `<Character>` rather than the default character `/`.
This can help avoid confusion when Google folder names contain a `/`.

Previously, on Windows, path components were separated by `\\` when written to a CSV file and
`\` when written to stdout; now, `/` or `<Character>` will be used in all cases.
```
gam <UserTypeEntity> info drivefile <DriveFileEntity>
gam <UserTypeEntity> show fileinfo <DriveFileEntity>
gam <UserTypeEntity> print filelist
gam <UserTypeEntity> print|show filepaths <DriveFileEntity>
gam <UserTypeEntity> transfer ownership <DriveFileEntity>
gam <UserTypeEntity> claim ownership <DriveFileEntity>
```

6.59.16

Updated `<GroupSettingsAttribute> whocancontactowner` to include option `all_owners_can_contact`.

6.59.15

Updated error reporting in `gam delete|update chromepolicy <SchemaName>` to show the `<SchemaName>` as originally entered
when an unknown `<SchemaName>` is specified; previously, it was shown in lowercase which could cause confusion.

Updated column order in `gam print chromeschemas` to move `schemaName`, `policyDescription` and `policyApiLifecycle.*`
to follow column `name`.

Added columns `policyDescription` and `policyApiLifecycleStage` to `gam print chromeschemas formatjson`
to follow column `name`.

6.59.14

Improve bug fix for `gam <UserTypeEntity> print groups|grouptree|groupslist`.

6.59.13

Fixed bug in `gam <UserTypeEntity> print groups|grouptree|groupslist` that caused the following
error whan an email address contained an apostrophe.
```
WARNING: Got 0 Groups: Invalid Member - test.o'user@domain.com
```

Fixed bug in `gam <UserTypeEntity> print|show contacts ... filtercontactgroup <PeopleContactGroupItem>` that returned
no contacts when neither `allfields` or `fields <PeopleFieldNameList>` was specifiecd.

6.59.12

Fixed bug in `gam create user <EmailAddress> ... immutableous <OrgUnitEntity> ... createifnotfound`
that generated the following error when the user `<EmailAddress>` did not exist and needed to be created.
```
User: <EmailAddress>, Service not applicable/Does not exist
```

6.59.11

Updated `gam print|show chromepolicies` to query the following nameapaces when
`namespace <NamespaceList>` is not specified. Previously, only the namespaces
marked with a `*` were queried. `chrome.devices.managedguest` was added in 6.59.10.
```
chrome.users *
chrome.users.apps *
chrome.users.appsconfig
chrome.devices *
chrome.devices.kiosk *
chrome.devices.kiosk.apps
chrome.devices.managedguest *
chrome.devices.managedguest.apps
chrome.networks.cellular
chrome.networks.certificates
chrome.networks.ethernet
chrome.networks.globalsettings
chrome.networks.vpn
chrome.networks.wifi
chrome.printers
chrome.printservers
```

6.59.10

Fixed bug in `gam print|show chromepolicies` where policies in namespace `chrome.devices.managedguest`
were not displayed unless it was specified in `namespace <NamespaceList>`.

Improved error messages in `gam <UserTypeEntity> move events`.

6.59.09

Added option `addnumericsuffixonduplicate <Number>` to `gam create user <EmailAddress>` that
will attempt to create a unique `<EmailAddress>` when the original value is a duplicate user address.
If `<EmailAddress>` is `<String>@<DomainName>`, up to `<Number>` attempts will be made
to create a unique `<EmailAddress>`; `<Number>` defaults to 0.
```
<String>1@<DomainName>
<String>2@<DomainName>
...
```

6.59.08

Fixed bug in `csv_output_row_filter "FieldName:date<Operator>Never"` that didn't properly detect matches.
For example, the following command would not display users that had never logged in.
```
gam config csv_output_row_filter "lastLoginTime:date=Never" print users lastlogintime
```

6.59.07

Added option `immutableous <OrgUnitEntity>` to `gam <UserTypeEntity> update user ... org <OrgUnitPath>` that
does not update the user's OU to `<OrgUnitPath>` if `<OrgUnitPath>` appears in `<OrgUnitEntity>`. All other
fields are updated.

This can be used when a SIS outputs user data to be updated but students temporarily in special purpose
OUs should not be updated to the SIS specified OU. `<OrgUnitEntity>` and `<OrgUnitPath>` must both
specify OU paths, not IDs.
```
gam csv SISdata.csv gam update user "~primaryEmail" suspended off firstname "~First Name" lastname "~Last Name"
        ou "~OU" immutableous "'/Students/Lower School/Restricted,'/Students/Middle School/Restricted'"
```

6.59.06

Added option `sources <PeopleProfileSourceNameList>` to `gam <UserTypeEntity> print|show peopleprofile`
that allows specification of the sources of the data to display. By default, data from all sources is displayed.
```
<PeopleProfileSourceName> ::=
        account|accounts|
        domain|domains|
        profile|profiles
<PeopleProfileSourceNameList> ::= "<PeopleProfileSourceName>(,<PeopleProfileSourceName>)*"
```

Added option `updatefilepermissions [<Boolean>]` to `gam <UserTypeEntity> move drivefile <DriveFileEntity>`.
Previously, file permissions were not updated in the command; now, when `updatefilepermissions` is true,
file permissions will be removed/created as specified by the following noptions:
```
excludepermissionsfromdomains <DomainNameList>
includepermissionsfromdomains <DomainNameList>
mappermissionsdomain <DomainName> <DomainName>
```
Additionally, permissions referencing deleted groups/users will be removed.

The permissions are updated on the file before it is moved.

Test before using in production.

6.59.05

Added option `includepermissionsfromdomains <DomainNameList>` to the following commands
that copies only those permissions that reference any domain in `<DomainNameList>`.
It is mutually exclusive with `exludepermissionsfromdomains <DomainNameList>`.
```
gam copy|sync teamdriveacls <SharedDriveEntity>
gam <UserTypeEntity> copy|sync teamdriveacls <SharedDriveEntity>
gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>
```

6.59.04

Fixed bug in `gam <UserTypeEntity> print|show filesharecounts` where ACLs for deleted user/groups
were miscounted as external shares.

6.59.03

Cleaned up `Getting/Got` messages for several commands.

Improved performance of `gam print admins`.

6.59.02

Updated the Analytic account/property commands to use service account access so that data
can be retrieved for any user.

Fixed bug where the Analytics Admin API was not being added in `gam update project`
forcing you to manually enable it.

6.59.01

Updated `gam checkconnection` to check connections to the following sites:
```
Contacts API - Domain Shared Contacts - www.google.com
Email Audit API - apps-apis.google.com
Sites API - sites.google.com
```

6.59.00

Added commands to display Analytic account/property information.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Analytics-Admin

6.58.03

Fixed bug in `gam [<UserTypeEntity>] print shareddriveacls oneitemperrow shownopermissionsdrives true`
where the Shared Drives with no ACLs were not shown; they were shown if `oneitemperrow` was omitted.

6.58.02

Updated `gam <UserTypeEntity> print filelist ... filepath|fullpath` to not display parent information
for orphans. Previously, GAM would incorrectly display:
```
...,parents,parents.0.id,parents.0.isRoot,...
...,1,Orphans,False,...
```
Now the corrected display is:
```
...,parents,parents.0.id,parents.0.isRoot,...
...,,,,...
```
This change makes the output the same as when `filepath|fullpath` is omitted.

6.58.01

Added the following options to tag replace processing to allow control of the case of replacement data.

You can control the case of the letters in `replace <Tag> <String>` and `replace <Tag> <UserReplacement>`.
  * `{PC}...{Tag1}...{Tag2}...{/PC}` - For all sequences of letters between `{PC}` and `{/PC}`, the first letter is converted to uppercase, subsequent letters to lowercase.
  * `{UC}...{Tag1}...{Tag2}...{/UC}` - All letters between `{UC}` and `{/UC}` will be converted to uppercase
  * `{LC}...{Tag1}...{Tag2}...{/LC}` - All letters between `{LC}` and `{/LC}` will be converted to lowercase

6.58.00

Added `license_max_results` variable to `gam.cfg`.  When retrieving licenses from License API,
this variable controls how many should be retrieved in each chunk. The default value is 100; the range is 100-1000.
As of 2023-04-27, larger numbers cause Google to return an incorrect numbert of licenses.

6.57.11

Fixed bug where the `csv_output_header_force` variable in `gam.cfg` was being interpreted as
a list of `<RegularExpressions>` rather than a list of `<Strings>` as documented.

6.57.10

When doing commands similar to these:
```
gam redirect csv - multiprocess todrive csv Users.csv gam user "~primaryEmail" print filelist ...
gam config auto_batch_min 1 redirect csv - multiprocess todrive <UserTypeEntity> print filelist ...
```
GAM was including the name of the last user processed in the title of the uploaded Google Sheet;
as this is not accurate, it has been eliminated.

6.57.09

Added `emailaddresslist <EmailAddressList>` to `<PermissionMatch>` that allows matching any email address in a list.

6.57.08

Updated `gam <UserTypeEntity> print|show contacts|othercontacts` to retry the following error:
```
serviceNotAvailable - The service is currently unavailable.
```

6.57.07

Updated code to recognize the following Google Drive API error that is issued when Google
doesn't recognize an email address as valid.
```
$ gam user user@domain.com print filelist query "'j@ab.net' in writers" fields id,name
Getting all Drive Files/Folders that match query ('me' in owners and ('j@ab.net' in writers)) for user@domain.com

ERROR: 400: badRequest - Bad Request
$ gam user user@domain.com print filelist query "'j@ab.com' in writers" fields id,name
Getting all Drive Files/Folders that match query ('me' in owners and ('j@ab.com' in writers)) for user@domain.com
Got 0 Drive Files/Folders that matched query ('me' in owners and ('j@ab.com' in writers)) for user@domain.com...
Owner,id,name
```

6.57.06

Added `inherited <Boolean>` to `<PermissionMatch>` that applies only to Shared Drive files/folders;
this makes it easy to identify files/folders on Shared Drive with non-inherited permissions.
```
gam user organizer@domain.com print filelist select teamdriveid <TeamDriveID> fields id,name,mimetype pm inherited false em pmfilter oneitemperrow
```
This clause will always cause a permission match failure on My Drive files/folders.

6.57.05

Updated `gam batch <BatchContent>` and `gam tbatch <BatchContent>` commands to accept lines with the following form:
```
clear keyword
```
This can improve performance as subsequent lines in `<BatchContent>` will not be scanned for `%keyword%`.

6.57.04

Updated `gam batch <BatchContent>` and `gam tbatch <BatchContent>` commands to accept lines with the following form:
```
set keyword value
```
Subsequent lines in `<BatchContent>` will have `%keyword%` replaced with `value`.

6.57.03

Updated `gam <UserTypeEntity> info|print|show contacts|othercontacts` and
`gam info|print|show peoplecontacts|peopleprofiles` to default to displaying the fields `names,emailaddresses,phonenumbers`
as documented rather than all fields.

6.57.02

Following Jay's lead, removed Google bug (237397223) workaround code in
`gam print devices|deviceusers|crostelemetry` as the bug is now fixed.

6.57.01

Updated `gam <UserTypeEntity> vacation` to handle the following error:
```
ERROR: 400: failedPrecondition - Precondition check failed.
```
What the error means is unknown to me at the moment.

Updated GAM so that when the current project ID is required, it will first try to get it from oauth2service.json and
if not successful, try to get it from client_secrets.json. There are cases, e.g., when DASA is enabled,
that client_secrets.json is not present.

Previously, GAM checked for the existence of client_secrets.json on every command; this check has been
eliminated as the file is only required by `gam oauth create`.

6.57.00

Following Jay's lead, updated `gam create admin` to allow assignment of a delegated admin role to a group.
Updated `gam print admins` to display whether a role is assigned to a user or a group.

Updated version number to align with Standard GAM.

6.54.06

Added options `users <EmailAddressList>` and `groups <EmailAddressList>` to `gam print aliases` that is more
efficient for getting aliases for specific users and groups.

Added option `select <UserTypeEntity>` to `gam print aliases` that allows specification of a list users by `<UserTypeEntity>`;
e.g., a group or an org unit.

Added option `delimiter <Character>` to `gam print aliases` that is applicable when option `onerowpertarget` is specified.
Previously, multiple aliases were separated by a space character. Now, by default, the aliases are separated by the `csv_output_field_delimiter' from `gam.cfg`.
The option `delimiter <Character>` overrides that value.

6.54.05

Added option `addcsvdata <FieldName> <String>` to `gam print aliases`. This adds additional columns of data to the CSV file output.
This can be used when printing aliases for departed employees to indicate the new target for the user's alises. Subsequent
commands using the CSV file can reassign the aliases to the new target.

6.54.04

Updated `gam print|show channelcustomerentitlements` to handle the following error when
none of `gam.cfg/channel_customer_id` or command line arguments `channelcustomerid` or `name` are set.
```
ERROR: Parameter "parent" value "accounts/C03kt1789/customers/" does not match the pattern "^accounts/[^/]+/customers/[^/]+$"
```

6.54.03

By special request, British spelling of various keywords/arguments is now available.
```
backgroundcolor backgroundcolour
color colour
colorindex colourindex
costcenter costcentre
fileorganizer fileorganiser
foregroundcolor foregroundcolour
license licence
licenses licences
nolicenses nolicences
organization organisation
organizationname organisationname
organizations organisations
organizer organiser
organizeremail organiseremail
organizername organisername
textcolor textcolour
```

6.54.02

Updated `gam <UserTypeEntity> get photo` and `gam <UserTypeEntity> get profilephoto` to inspect the
photo data and add the appropriate extension: `jpg`, `png`, `gif`. If the type of the photo can't be
determined, `img` is used as the extenstion. If you use `[filename <FileNamePattern>]`, `#ext#` will be replaced
with the extension. 

Updated `gam <UserTypeEntity> [create|add] sendas <EmailAddress> [name] <String>` to allow the
optional argument `name` before `<String>` to make clear that `<String>` is the sendas display name.

6.54.01

Added commands to export messages/threads in EML/raw format.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Messages-Threads#export-messagesthreads

6.54.00

Following Jay's lead, updated `gam delete inboundssoassignment <SSOAssignmentSelector>` to allow
more flexibility in selecting assignments to delete.

Fixed bug in `gam <UserTypeEntity> print|show filesharecounts` that would cause a trap.

Updated `gam <UserTypeEntity> print filelist ... fullpath showparent` and `gam <UserTypeEntity> print filepath`
to properly display the file path of My Drive.

Upgraded to Python 3.11.3 where possible.

Added commands to create and delete Chrome networks.
```
gam create chromenetwork
        <OrgUnitItem> <String> <JSONData>
gam delete chromenetwork
         <OrgUnitItem> <NetworkID>
```

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Policies#create-chrome-network

6.53.03

`gam gam print|show svcaccts` now requires password authentication.

6.53.02

Added commands to display the share type counts of a user's files.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#display-file-share-counts

6.53.01

Following Jay's lead, added instructions to `gam create project` to have GAM be a trusted app.

6.53.00

Updated build steps to avoid trap with `gam create project` on M1 Macs.

Added option `noshowtextplain` to `gam <UserTypeEntity> show messages|threads` that suppresses
the default display of `text/plain` attachment content when `showattachments` is specified.

6.52.08

Added `maximumfilesize <Integer>` to the following commands to allow selection of files with content of size <= `<Integer>`.
```
gam <UserTypeEntity> print filelist
gam <UserTypeEntity> print|show filetree
gam <UserTypeEntity> print|show filecounts
```

Added field `workinglocationproperties` to `<EventFieldName>`.

* See: https://workspaceupdates.googleblog.com/2023/03/manage-working-location-feature-with-calendar-api.html

6.52.07

Fixed bug in `gam <UserTypeEntity> copy drivefile` that caused the following error:
```
ERROR: 403: parentNotAFolder - The specified parent is not a folder.
```

Current time is now printed in `gam version`.

6.52.06

Updated `gam <UserTypeEntity> create|update drivefile` to handle the following error that occurs when an attempt is
made to create/move a third-party shortcut on/to a Shared Drive.
```
ERROR: 403: teamDrivesShortcutFileNotSupported - The application associated with this third-party shortcut file does not support shared drives.
```

6.52.05

Added option `formatjson` to all commands that display Vault Matters, Exports, Holds and Saved Queries.

Updated `gam <UserTypeEntity> move drivefile` to handle the following error that occurs when an attempt is
made to move a third-party shortcut to a Shared Drive.
```
ERROR: 403: teamDrivesShortcutFileNotSupported - The application associated with this third-party shortcut file does not support shared drives.
```

6.52.04

Fixed bug in `gam info vaultquery` and `gam print|show vaultqueries` that caused a trap
when the `query` field was omitted from the `fields <VaultQueryFieldNameList>`.

6.52.03

Added commands to display Vault Matter saved queries.
```
gam info vaultquery <QueryItem> matter <MatterItem>
        [fields <VaultQueryFieldNameList>] [shownames]
gam info vaultquery <MatterItem> <QueryItem>
        [fields <VaultQueryFieldNameList>] [shownames]
gam print vaultqueries [todrive <ToDriveAttribute>*] [matters <MatterItemList>]
        [fields <VaultQueryFieldNameList>] [shownames]
gam show vaultqueries [matters <MatterItemList>]
        [fields <VaultQueryFieldNameList>] [shownames]
```

Updated `gam info resoldcustomer <CustomerID>` to display the customer primary email.

Following Jay's lead, the following scopes will be off by default as changes to Google Cloud session control
may require frequent use of `gam aouth create`.

* See: https://workspaceupdates.googleblog.com/2023/03/google-cloud-session-length-default-update.html
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#introduction

```
[ ] 21)  Cloud Storage API (Read, Vault/Takeout Download)
[ ] 22)  Cloud Storage API (Write, Vault/Takeout Copy)
```

6.52.02

Following Jay's lead, added the following License SKUs:
```
1010380001 - AppSheet Core 
1010380002 - AppSheet Enterprise Standard
1010380003 - AppSheet Enterprise Plus
```

6.52.01

Fixed bug where `API calls retry data` was displaying incorrect values when processing CSV files.

6.52.00

Updated process handling for `gam batch|csv`.

6.51.08

Updated `gam create|update user <EmailAddress> ... <JSONData>` to exclude additional fields
from the JSON data that can't be copied; the following error was displayed:
```
User: user@domain.com, Create Failed: Invalid Input: Bad request for 
```

6.51.07

Fixed bug introduced in 6.51.06 that caused a trap in `gam create project`.

6.51.06

Following Jay's lead, added option `validityhours <Number>` to `gam create|replace|update sakeys` and `gam rotate sakey`
that let's you set the length of time a Service Account key is valid.

6.51.05

With input from Jay, further upgraded `gam <UserTypeEntity> check serviceaccount` to avoid a trap when a proxy is being used.

6.51.04

Upgraded `gam <UserTypeEntity> check serviceaccount` to avoid a trap when a proxy is being used.

6.51.03

* Upgraded to OpenSSL 3.1.0 where possible.

6.51.02

Added support for `externalid`, `im`, `posix`, `relation`, `sshkeys` and `website` subfields in `gam <UserTypeEntity> signature` and
`gam <UserTypeEntity> create|update sendas` option `replace <Tag> <UserReplacement>`.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Tag-Replace

6.51.01

Added option `nogcspath` to `gam download storagefile <StorageBucketObjectName>` that causes GAM
to store the downloaded file directly into the target folder without any Google Cloud Storage path information.

6.51.00

Added the ability to read data from Google Cloud Storage bucket objects.
```
<StorageBucketName> ::= <String>
<StorageObjectName> ::= <String>
<StorageBucketObjectName> ::=
        https://storage.cloud.google.com/<StorageBucketName>/<StorageObjectName>|
        https://storage.googleapis.com/<StorageBucketName>/<StorageObjectName>|
        gs://<StorageBucketName>/<StorageObjectName>|
        <StorageBucketName>/<StorageObjectName>
```
Anywhere you can enter `gdoc|ghtml <UserGoogleDoc>)` you can enter `gcsdoc|gcshtml <StorageBucketObjectName>`.

Anywhere you can enter `gsheet <UserGoogleSheet>)` you can enter `gcscsv <StorageBucketObjectName>`.

The Type of the Cloud Storage bucket objects must match the option keyword.

* gcsdoc - text/plain
* gcshtml - text/html
* gcscsv - text/csv

These options require that scope `Cloud Storage (Read, Vault/Takeout Download)` be enabled in `gam oauth create`.

Added a command to download a Cloud Storage bucket object.
```
gam download storagefile <StorageBucketObjectName>
        [targetfolder <FilePath>]
```

6.50.14

Fixed bug in `gam <UserTypeEntity> copy drivefile` that caused a trap.

Fixed bug where `removefeature` but not `removefeatures` was recognized in `gam update resource`.

6.50.13

Added options `addfeatures <FeatureNameList>` and `removefeatures <FeatureNameList>` to `<ResourceAttribute>`.
These can be used in in the following commands to make incremental changes to resource features.
```
gam update resource <ResourceID> <ResourceAttribute>*
gam update resources <ResourceEntity> <ResourceAttribute>*
```

Updated processing of `<FeatureNameList>` which is a `<ResourceAttribute>` to properly handle `<FeatureName>s` containing spaces.
When entering `<FeatureNameList>` with `<FeatureName>s`containing spaces, enclose the list in `"` and the names containing spaces in `'`.
```
features "CameraSet"
features "'Laptop Cart'"
features "CameraSet,'Laptop Cart'"
```

6.50.12

Handle new trap in `gam <UserTypeEntity> forward messages`.

6.50.11

Handle new trap in `gam <UserTypeEntity> forward messages`.

6.50.10

Fixed bug in `gam <UserTypeEntity> forward messages altcharset <String>` where `<String>` was marked as an invalid argument.

Updated `gam <UserTypeEntity> copy drivefile <DriveFileEntity>` to allow copying Google Sites.

6.50.09

Added command `gam info adminrole <RoleItem> [privileges]` that displays a specific admin role and optionally its privileges.

Added option `privileges` to `gam print|show admins` that displays the privileges for each role
for the admin.

6.50.08

Added option `altcharset <String>` to `gam <UserTypeEntity> forward messages` to attempt to handle
errors like the following which occur when the message can not be decoded with character set UTF-8.
You can specify an alternate character set, e.g. latin1, that is used if the UTF-8 decode fails.
```
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x92 in position 1643: invalid start byte
```

6.50.07

Fixed build bug that caused the following error:
```
ERROR: Discovery File: /usr/local/gamadv-xtd3/datastudio-v1.json, Does not exist or has invalid format, No data
```

6.50.06

Fixed bug in `gam report usage customer` where an extraneous column `email` was displayed.

6.50.05

Fixed bug in `gam update resoldsubscription` that caused an error:
```
ERROR: 400: invalid - The seats provided are not valid
```

6.50.04

Added `allowcontentmanagerstosharefolders` to `<SharedDriveRestrictionsSubfieldName>` that is used in
`gam create|update teamdrive`. This terminology matches the Admin console setting `Allow Content Managers to share folders`.

Each pair of commands below are equivalent:
```
gam update teamdrive <SharedDriveEntity> allowcontentmanagerstosharefolders true
gam update teamdrive <SharedDriveEntity> sharingfoldersrequiresorganizerpermission false

gam update teamdrive <SharedDriveEntity> allowcontentmanagerstosharefolders false
gam update teamdrive <SharedDriveEntity> sharingfoldersrequiresorganizerpermission true
```

Updated status reporting in `gam update chromepolicy` to supply more details.

Fixed bug in `gam update chromepolicy` when processing an schema field with an empty list.

6.50.03

Fixed bug in `gam update resoldsubscription` that caused an error:
```
ERROR: 400: invalid - Request contains an invalid argument. 
```

6.50.02

Fixed bug in `gam create project` where invalid data was written to client_secrets.json.

6.50.01

Fixed YubiKey issue that caused a trap.

6.50.00

Following Jay's lead (with many thanks), added commands to enable running GAM securely on a Google Compute Engine.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Running-GAMADV-XTD3-securely-on-a-Google-Compute-Engine
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Using-GAMADV-XTD3-with-a-delegated-admin-service-account

Following Jay's lead (with many thanks), added commands to enable using a Yubikey.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Using-GAMADV-XTD3-with-a-YubiKey

These Wiki pages are a work in progress, contact me if you need help.

Updated handling of `seats` option in `gam create|update resoldsubscription` to properly assign
the API fields `numberOfSeats` and `maximumNumberOfSeats`.
Previously, this is how the option was processed:
  * Plan name `ANNUAL_MONTHLY_PAY` or `ANNUAL_YEARLY_PAY`
    * `seats <NumberOfSeats>` - `<NumberOfSeats>` was properly passed to the API
    * `seats <NumberOfSeats> <MaximumNumberOfSeats>` - `<NumberOfSeats>` was properly passed to the API; `<MaximumNumberOfSeats>` was passed to the API which ignored it
  * Plan name `FLEXIBLE` or `TRIAL`
    * `seats <NumberOfSeats>` - `<NumberOfSeats>` was improperly passed to the API; an API error was generated
    * `seats <NumberOfSeats> <MaximumNumberOfSeats>` - `<MaximumNumberOfSeats>` was properly passed to the API; `<NumberOfSeats>` was passed to the API which ignored it

Now, you can still use the above option which has been corrected or you can specify `seats <Number>` which will be properly passed in the correct form to the API based on plan name.

Hopefully fixed a bug in `gam <UserTypeEntity> forward messages` that caused a trap when the subject
contained Latin-1 characters.

6.42.10

Added option `accesstype public|team|announcementonly|restricted` to `gam create|update group`.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups#gui-api-group-access-type-settings-mapping

6.42.09

Cleaned up output in `gam print crostelemetry`; fields that are lists weren't being correctly sorted by index.

6.42.08

Added additional fields to `<CrOSTelemetryFieldName>`:
```
audiostatusreport|
bootperformancereport|
networkinfo|
networkdiagnosticsreport|
peripheralsreport|
thunderboltinfo|
networkdevices|
```

6.42.07

Improved `gam <UserTypeEntity> create|add drivefolderpath` to allow specifying paths
as returned by `gam <UserTypeEntity> print filepath`.

6.42.06

Fixed another bug in `gam <UserTypeEntity> create|add drivefolderpath` that failed when
trying to build a folder hierarchy on a Shared Drive.

6.42.05

Fixed bug in `gam <UserTypeEntity> create|add drivefolderpath` that failed when
trying to build a folder hierarchy on a Shared Drive.

6.42.04

Added a command that creates a folder hierarchy.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Manage#create-folder-hierarchy

6.42.03

Updated `gam <UserTypeEntity> get drivefile <DriveFileEntity> ... csvsheet <SheetEntity>` to allow
selection of the output format with `format <FileFormat>`. Previously, `csv` was always selected and
it is still the default. Valid formats are: `csv,tsv,ods,pdf,xlsx`.

6.42.02

Added `sha1checksum` and `sha256checksum` to `<DriveFieldName>`.
```
The SHA1/SHA256 checksum associated with a file, if available.
This field is only populated for files with content stored in Google Drive;
it isn't populated for Docs Editors or shortcut files.
```

Added option `addcsvdata <FieldName> <String>` to `gam <UserTypeEntity> print filelist` and
`gam print ownership`. This adds additional columns of data to the CSV file output.
```
Get a list of a user's shortcuts
gam redirect csv ./TSShortcuts.csv user user@domain.com print filelist fields id,name,parents,shortcutdetails showmimetype gshortcut
Headers
Owner,id,name,parents,parents.0.id,parents.0.isRoot,shortcutDetails.targetId,shortcutDetails.targetMimeType

For each shortcut, get the target file information; add the shortcut id, name and parent to the output
gam redirect csv ./TSShortcutFiles.csv multiprocess csv ./TSShortcuts.csv gam user user@domain.com print filelist select "~shortcutDetails.targetId" norecursion showownedby any
    fields id,name,mimetype,parents,owners.emailaddress addcsvdata shortcut.id "~id" addcsvdata shortcut.name "~name" addcsvdata shortcut.parents "~parents.0.id"
Headers
Owner,id,name,mimeType,owners,owners.0.emailAddress,parents,parents.0.id,parents.0.isRoot,shortcut.id,shortcut.name,shortcut.parents
```

6.42.01

Updated processing of option `matchlabel <LabelName>` to replace the following characters with a `-`
so that the query generated will work correctly. Previously, only ` ` (space) and `/` were replaced.
```
 &()"|{}/
```

6.42.00

Following Jay's lead, added commands commands to copy Google Vault and Organization Takeout data to your own GCS bucket.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault-Takeout#copy-vault-exports
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault-Takeout#copy-a-takeout-bucket

Updated `gam <UserTypeEntity> create contact` to treat the following options as errors;
previously, they were silently ignored.
```
addcontactgroup <ContactGroupItem>
removecontactgroup <ContactGroupItem>
```

Updated version number to align with Standard GAM.

6.32.05

Fixed bug in `gam show chromepolicies` that caused a trap.

Following Jay's lead, added `sharingfoldersrequiresorganizerpermission` to `<SharedDriveRestrictionsFieldName>` and
`<SharedDriveRestrictionsSubfieldName>`.

* See: https://workspaceupdates.googleblog.com/

6.32.04

Fixed bug in `gam <UserTypeEntity> move drivefile <DriveFileEntity>` where the following
error was not retried when `sendemailifrequired` was specified.
```
    User: user@domain.com, Drive Folder: Test, Permission: noninherited/writer/user/user@external.com, Copy Failed: You are trying to invite user@external.com. Since there is no Google account
              associated with this email address, you must check the "Notify people" box to invite this recipient.
```

6.32.03

Following Jay's lead, updated `gam create project` to handle the following error:
```
ERROR: 403: Permission 'resourcemanager.projects.get' denied on resource
```

6.32.02

Added support for `gender` subfields in `gam <UserTypeEntity> signature` and
`gam <UserTypeEntity> create|update sendas` option `replace <Tag> <UserReplacement>`.
```
<GenderSubfieldName> ::=
        addressmeas|
        customgender|
        type
<UserReplacementFieldSubfield> ::=
        ...
        gender.<GenderSubfieldName>|
        ...
```

6.32.01

Extended `csv_input_row_filter`, `csv_input_row_drop_filter`, `csv_output_row_filter` and `csv_output_row_drop_filter`
to allow specification of filters based on text comparisons.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Input-Filtering
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Output-Filtering

6.32.00

Added option `oneitemperrow` to `gam <UserTypeEntity> print filelist` to have each of a
files permissions displayed on a separate row with all of the other file fields. This produces
a CSV file that can be used in subsequent commands without further script processing.

Added option `pmfilter` to `gam <UserTypeEntity> print filelist` that is used in conjunction
with permission matching. By default, permission matching simply selects which files to display,
all ACLS are displayed. With `pmfilter`, only the ACLs that match are displayed.

6.31.09

Updated `gam gam <UserTypeEntity> create label <String>`, `gam <UserTypeEntity> create labellist <LabelNameEntity>`
and `gam <UserTypeEntity> update labelsettings <LabelName>` to expand the choices for label colors.
```
<ColorHex> ::= "#<Hex><Hex><Hex><Hex><Hex><Hex>"
<LabelColorHex> ::=
        #000000|#076239|#0b804b|#149e60|#16a766|#1a764d|#1c4587|#285bac|
        #2a9c68|#3c78d8|#3dc789|#41236d|#434343|#43d692|#44b984|#4a86e8|
        #653e9b|#666666|#68dfa9|#6d9eeb|#822111|#83334c|#89d3b2|#8e63ce|
        #999999|#a0eac9|#a46a21|#a479e2|#a4c2f4|#aa8831|#ac2b16|#b65775|
        #b694e8|#b9e4d0|#c6f3de|#c9daf8|#cc3a21|#cccccc|#cf8933|#d0bcf1|
        #d5ae49|#e07798|#e4d7f5|#e66550|#eaa041|#efa093|#efefef|#f2c960|
        #f3f3f3|#f691b3|#f6c5be|#f7a7c0|#fad165|#fb4c2f|#fbc8d9|#fcda83|
        #fcdee8|#fce8b3|#fef1d1|#ffad47|#ffbc6b|#ffd6a2|#ffe6c7|#ffffff
<LabelBackgroundColorHex> ::=
        #16a765|#2da2bb|#42d692|#4986e7|#98d7e4|#a2dcc1|
        #b3efd3|#b6cff5|#b99aff|#c2c2c2|#cca6ac|#e3d7ff|
        #e7e7e7|#ebdbde|#f2b2a8|#f691b2|#fb4c2f|#fbd3e0|
        #fbe983|#fdedc1|#ff7537|#ffad46|#ffc8af|#ffdeb5
<LabelTextColorHex> ::=
        #04502e|#094228|#0b4f30|#0d3472|#0d3b44|#3d188e|
        #464646|#594c05|#662e37|#684e07|#711a36|#7a2e0b|
        #7a4706|#8a1c0a|#994a64|#ffffff

backgroundcolor "<LabelColorHex>|<LabelBackgroundColorHex>|custom:<ColorHex>"
textcolor "<LabelColorHex>|<LabelTextColorHex>|custom:<ColorHex>"
```

6.31.08

Updated `csv_output_header_force` variable in `gam.cfg` that is a list of `<Strings>`
to be the exact list of headers to be included in the CSV file written by a gam print command.
This might be used when the CSV file data is to be uploaded into a database
and some headers may not be present in the output but must be included for the upload to work.

6.31.07

Added `csv_output_header_force` variable to `gam.cfg` that is a list of `<Strings>`
that are forced for inclusion in the CSV file written by a gam print command.
This might be used when the CSV file data is to be uploaded into a database
and some headers may not be present in the output but must be included for the upload to work.

6.31.06

Added support for new ChromeOS device fields:
```
<CrOSFieldName> ::=
        deprovisionreason|
        firstenrollmenttime|
        lastdeprovisiontimestamp|
```

6.31.05

Google can return an error `Internal error` on API calls; by default, GAM retries these API calls an additional 9 times
for a total of 10 tries. In some cases, determined by experience, the additional retries are unlikely to succeed and
GAM performs 1 additional retry rather than 9 for a total of 2 tries.

Added `bail_on_internal_error_tries` variable to `gam.cfg` that is used by GAM to control
the total number of tries for these API calls; Google seems to be sending this error when it is very busy.
The default value is 2 and values from 1 to 10 are allowed.
This is a rare event, this is an experiment to see if retrying these errors more times leads to success.

6.31.04

Added commands to display Chrome Devices Needing Attention counts.
```
gam print chromeneedsattn [todrive <ToDriveAttribute>*]
        [(ou <OrgUnitItem>)|(ou_and_children <OrgUnitItem>)|
         (ous <OrgUnitList>)|(ous_and_children <OrgUnitList>)]
        [formatjson [quotechar <Character>]]
gam show chromeneedsattn
        [(ou <OrgUnitItem>)|(ou_and_children <OrgUnitItem>)|
         (ous <OrgUnitList>)|(ous_and_children <OrgUnitList>)]
        [formatjson]
```

6.31.03

Added commands to display Chrome Auto Update Expiration counts.
```
gam print chromeaues [todrive <ToDriveAttribute>*]
        [(ou <OrgUnitItem>)|(ou_and_children <OrgUnitItem>)|
         (ous <OrgUnitList>)|(ous_and_children <OrgUnitList>)]
        [minauedate <Date>] [maxauedate <Date>]
        [formatjson [quotechar <Character>]]
gam show chromeaues
        [(ou <OrgUnitItem>)|(ou_and_children <OrgUnitItem>)|
         (ous <OrgUnitList>)|(ous_and_children <OrgUnitList>)]
        [minauedate <Date>] [maxauedate <Date>]
        [formatjson]
```

6.31.02

Updated `gam <UserTypeEntity> vacation` to process `(replace <Tag> <String>)*` in the subject.

6.31.01

Added option `nofile` to `gam <UserTypeEntity> get photo|profilephoto` that causes GAM to suppress
writing the photo data to a file. This would typicically be used when you are capturing the photo data
written to stdout.

6.31.00

Added `retry_api_service_not_available` variable to `gam.cfg` that is used to have GAM retry
`Service not applicable` errors on API calls; Google seems to be sending this error when it is very busy.
This is a rare event, this is an experiment to see if GAM can identify these errors and retry them.

6.30.18

Fixed bug in `gam <UserTypeEntity> move drivefile` where the modified time of files was inappropriately being changed.

6.30.17

Updated code for `gam <UserTypeEntity> get profilephoto size <Integer>` to account for API documentation error.

6.30.16

Added option `nodefault` to `gam <UserTypeEntity> get profilephoto` that causes GAM to display an
error message and set the return code to 50 if the user has a default profile photo.

6.30.15

Added option `gphoto <EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>` to `gam <UserTypeEntity> update photo`
that specifies an owner and file to be used as the source of the photo.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Photo

6.30.14

Fixed bug in `gam <UserTypeEntity> print|show peopleprofile fields ...` where metadata was being displayed
even when `showmetadata` was not specified.

6.30.13

Fixed bug in `gam <UserTypeEntity> show fileinfo <DriveFileEntity> fields shortcutdetails.targetid` that caused a trap.

Added option `size <Integer>` to `gam <UserTypeEntity> get profilephoto` that specifies the size in pixels of the file to download.

6.30.12

Updated `gam update group <GroupEntity> update [<GroupRole>] [[delivery] <DeliverySetting>] <UserTypeEntity>`
to handle the following error when `<UserTypeEntity>` is an external member.
```
ERROR: 404: resourceNotFound - Does not exist
```
This is a Google bug where some external members can't be updated by email address.

6.30.11

Added option `emailmatchpattern [not] <RegularExpression>` to `gam <UserTypeEntity> delete group|groups`
that allows deleting a user from all groups of which they are a member based on (not) matching the group email address.

6.30.10

Added the ability to specify fields when displaying calendars.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Calendars
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars

6.30.09

Added the following shortcuts to `<DriveFileQueryShortcut>`:
```
* my_top_files - "'me' in owners and mimeType != application/vnd.google-apps.folder and 'root' in parents"
* my_top_folders - "'me' in owners and mimeType = application/vnd.google-apps.folder and 'root' in parents"
* my_top_items - "'me' in owners and 'root' in parents"
```

6.30.08

Following Jay's lead, added the following License SKUs:
```
1010390001 - Assured Controls
1010400001 - Beyond Corp Enterprise
```

6.30.07

Added option `sheetsfields <SpreadsheetSheetsFieldList>` to `gam <UserTypeEntity> print|show sheet <DriveFileEntity>`
that lets you specfiy the desired subfields from the `sheets` field of a spreadsheet that should be displayed.
By default, all `sheets` subfields are displayed.
```
<SpreadsheetSheetsField> ::=
        bandedranges|
        basicfilter|
        charts|
        columngroups|
        conditionalformats|
        data|
        developermetadata|
        filterviews|
        merges|
        properties|
        protectedranges|
        rowgroups|
        slicers
<SpreadsheetSheetsFieldList> ::= "<SpreadsheetSheetsField>(,<SpreadsheetSheetsField>)*"
```

6.30.06

Fixed bug in `gam <UserTypeEntity> create|update|delete drivefileacl <DriveFileEntity> ... updatesheetprotectedranges`
that caused a trap.

6.30.05

Cleaned up code for option `updatesheetprotectedranges` in `gam <UserTypeEntity> create|update|delete drivefileacl <DriveFileEntity>`.

6.30.04

Improved output formatting for field `sheets` in  `gam <UserTypeEntity> info sheet <DriveFileEntity>`.

6.30.03

Updated `gam <UserTypeEntity> create|update drivefileacl <DriveFileEntity>` commands to handle the following error.
```
ERROR: 403: fileOrganizerOnFoldersInSharedDriveOnly - FileOrganizer role is only allowed on folders.
```

Added option `updatesheetprotectedranges` to `gam <UserTypeEntity> create|update|delete drivefileacl <DriveFileEntity>`
commands that causes GAM to update Sheet Protected Ranges if `<DriveFileEntity>` is a Google Sheet.

6.30.02

Fixed error message in `gam print cigroups` when an invalid field was specified.

6.30.01

Fixed bug in `gam create cigroup <EmailAddress> name <String> <GroupAttribute>+` where the group name was set to `<EmailAddress>` rather than `<String>`.

6.30.00

Added option `returnidonly` to `gam <UserTypeEntity> show fileinfo <DriveFileEntity>`
that causes GAM to return just the file ID of the files in `<DriveFileEntity>` file as output.
```
$ gam user user@domain.com show fileinfo root returnidonly
0AHYenC8f12ALUk9xyz

$ gam user testsimple show fileinfo name "Test File" returnidonly
0B3YenC8f12ALflhUTmtNS3E2Vk9LSUpBVXRSUG5lQ29GWkRtWHM1VzU1blc4ZW1pb2FnNTA
```

Changed the display format of file paths for files on Shared Drives.

* Old format - SharedDrive(TS Shared Drive 6)/TS SD6 Folder/TS TD6 Doc
* New format -SharedDrives/TS Shared Drive 6/TS SD6 Folder/TS TD6 Doc

Added option `returnpathonly` to `gam <UserTypeEntity> show filepath <DriveFileEntity>`
that causes GAM to return just the file path of the files in `<DriveFileEntity>` file as output.
```
$ gam user user@domain.com show filepath name "Test File" returnpathonly
My Drive/Classroom/Test File

$ gam user user@domain.com show filepath 0AJ6mqwXP9wHxUk9xyz returnpathonly
TS Shared Drive 6

$ gam user testsimple show filepath 0AJ6mqwXP9wHxUk9xyz returnpathonly fullpath
SharedDrives/TS Shared Drive 6

$ gam user user@domain.com show filepath teamdriveid 0AJ6mqwXP9wHxUk9xyz teamdrivefilename "TS TD6 Doc" returnpathonly
SharedDrives/TS Shared Drive 6//TS SD6 Folder/TS TD6 Doc
```

Added command `gam comment <String>*` that displays the comment data on stdout.
This can be used to validate `csv_input_row_filters` and column value extraction.
```
$ more Comment.csv 
col1,col2
aaa,111
bbb,222
ccc,333
$ gam config csv_input_row_drop_filter "col1:regex:bbb" csv Comment.csv gam comment "Col1:~~col1~~" "Col2:~~col2~~"
2022-12-16T12:41:50.045-08:00,0/2,Using 2 processes...
Col1:aaa Col2:111
Col1:ccc Col2:333
```

Updated `gam <UserTypeEntity> create|delete license <SKUIDList>` to take a list of SKUs.

Updated `gam create user <EmailAddress> ... license <SKUIDList>` to take a list of SKUs.

Updated `gam <UserTypeEntity> sync license <SKUIDList>` to take a list of SKUs and
added option `allskus|onesku` that is required when multiple SKUs are specified.

* `allskus` indicates that users in `<UserTypeEntity>` will  be updated to have all of the SKUs in `<SKUIDList>`.
  * This is typically used when assigning different types of licenses, such as an Enterprise license and a Voice license.
* `onesku` indicates that users in `<UserTypeEntity>` with none of the licenses in`<SKUIDList>` will be updated to have the first available license SKU in `<SKUIDList>`.
  * This is typically used with Google Education Plus or Google Education Standard licenses, which are split across multiple SKUs.

Added option `basic` to `gam print cigroups` that causes GAM to display the basic
Cloud Identity Group fields, i.e., those fields that do not require an additional API call per group.

Following Jay's lead, added option `query <String>` to `gam print cigroups`.

6.29.21

Fixed bugs in `gam selectfilter` that caused traps or inappropriate error messages.

6.29.20

Fixed bug in `gam <UserTypeEntity> archive messages <GroupItem>` that caused a trap.

6.29.19

Fixed bug introduced in 6.29.17 in `todrive` that caused a trap.

6.29.18

Added the following variables to `gam.cfg` to provide more flexibility when multiple row filters are specified.

* `csv_input_row_filter_mode allmatch|anymatch`
  * `allmatch` - all filters must match to include in input; this is the default and is the current behavior
  * `anymatch` - any filter must match to include in input
* `csv_input_row_drop_filter_mode allmatch|anymatch`
  * `allmatch` - all filters must match to drop from input
  * `anymatch` - any filter must match to drop from input; this is the default and is the current behavior
* `csv_output_row_filter_mode allmatch|anymatch`
  * `allmatch` - all filters must match to include in output; this is the default and is the current behavior
  * `anymatch` - any filter must match to include in output
* `csv_output_row_drop_filter_mode allmatch|anymatch`
  * `allmatch` - all filters must match to drop from output
  * `anymatch` - any filter must match to drop from output; this is the default and is the current behavior

6.29.17

Added option `todrive tdcellnumberformat text|number` that causes GAM to set the Sheet Number format when uploading files with `todrive`.
If the option is not specified, no number format is specified.

6.29.16

Fixed bug introduced in 6.29.15 that caused an error like this:
```
ERROR: Config File: gam.cfg, Section: DEFAULT, Item: todrive_locale, Value: "en_us", Expected: ,ar-eg,az-az,be-by,bg-bg,bn-in,ca-es,cs-cz,cy-gb,da-dk,de-ch,de-de,el-gr,en-au,en-ca,en-gb,en-ie,en-us,es-ar,es-bo,es-cl,es
```

6.29.15

Updated `gam [<UserTypeEntity>] info|print|show drivelabels languagecode <DriveLabelLanguageCode>` to use the BCP-47 language code.

6.29.14

Added option `stripcrsfromtitle` to `gam <UserTypeEntity> print|show datastudioassets` that causes carriage returns,
linefeeds and nulls to be stripped from asset titles.

6.29.13

Updated status messages in `gam delete|update chromepolicy` to be more informative.

Fixed bug in `gam delete chromepolicy` with schema chrome.users.apps.InstallType.

6.29.12

Fixed issue in `gam update chromepolicy` with schemas `chrome.users.apps.ManagedConfiguration`,
`chrome.devices.managedguest.apps.ManagedConfiguration` and `chrome.devices.kiosk.apps.ManagedConfiguration`.

6.29.11

Improved performance of `gam update chromepolicy`.

6.29.10

Attempted to fix issues in `gam update chromepolicy` with schemas `chrome.users.apps.InstallType`
and `chrome.users.apps.IncludeInChromeWebStoreCollection`.

6.29.09

Fixed bug in `gam <UserTypeEntity> create tasklist` that caused a trap.

Added `countsonly` option to `gam <UserTypeEntity> print|show tasks|tasklists` that causes GAM to display
the number of tasks|tasklists for a user rather than listing the details.

Added option `due <Time>` to `<TaskAttribute>` that can be used to set a task due date
in `gam <UserTypeEntity> create|update` task.

Fixed bug in `gam update chromepolicy` that caused an error with this prefix:
`1 Chrome Policy Update Failed: Invalid enum value:`

6.29.08

Fixed bug where `csvfile -:fieldName` was not properly recognized on Windows.

6.29.07

Added option `from <EmailAddress>` to `gam create|update user ... notify <EmailAddressList>` that
uses `<EmailAddress>` as the from address rather than the admin user identified in oauth2.txt.

6.29.06

Following Jay's lead, added option `returnnameonly` to `gam create|update inboundssoprofile` that
causes GAM to display just the profile name of the created|updated profile. This will be useful
in scripts that create|update a profile and then want to perform subsequent GAM commands that
reference the profile.

6.29.05

Improved code for `gam [<UserTypeEntity>] create teamdrive <Name> ou <OrgUnitItem>`.

6.29.04

Updated multiprocessing on MacOS to use `spawn` instead of `fork` when starting subprocesses
as `fork` was unreliable when large numbers (>20) of threads were used; subprocesses would
hang and never complete.

6.29.03

Thanks to Jay, added support for the user field `displayName` that can be set independently of `fullName`.

6.29.02

Thanks to Jay, updated `gam info|print|show crostelemetry` to avoid the following trap:
```KeyError: 'temperatureCelsius'```

6.29.01

Fixed bug in `gam <UserTypeEntity> print|show labels` where fields `messageListVisibility`,
`labelListVisibility` and `color` were not displayed.

Fixed bug in `gam <UserTypeEntity> draft|insert|import message emlfile <FileName>` where the
`Date` header in the file was overridden with the current date.

6.29.00

Added option `emlfile <FileName>` to `gam <UserTypeEntity> draft|insert|import message` that
allows processing an EML message file. SMTP headers specified in the command will replace those in the message file.

Following Jay's lead, added commands to manage/display Inbound SSO.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Inbound-SSO
* https://admin.google.com/ac/security/sso

6.28.12

Fixed bug in `gam create|update user ... password random notify <EmailAddress>` that caused a trap
when the random password contained `{` and `}`.

6.28.11

Fixed bug in  `gam <UserTypeEntity> update contact ... birthday ""` that caused a trap
rather that clearing the birthday from the contact.

6.28.10

Added option `addcsvdata <FieldName> <String>` to `gam create shareddrive ... csv`. This adds
additional columns of data to the CSV file output. For example, you are building student Shared Drives
and want to add ACLs to them adding the students as organizers. By adding the student's primary email address
to the CSV output, it can be used in subsequent commands.
```
StudentSharedDrives.csv
primaryEmail,Name
bob@domain.com,Bob Jones
mary@domain.com,Mary Smith
...

# Create the student Shared Drives
gam redirect stdout ./StudentSharedDrivesCreated.txt multiprocess redirect stderr stdout redirect csv ./StudentSharedDrivesCreated.csv multiprocess csv StudentSharedDrives.csv gam create shareddrive "~Name" csv addcsvdata primaryEmail "~primaryEmail"
# Add ACLs granting the students organizer access to their Shared Drives.
gam redirect stdout ./StudentSharedDrivesAccess.txt multiprocess redirect stderr stdout csv StudentSharedDrivesCreated.csv gam add drivefileacl "~id" user "~primaryEmail" role organizer
```

6.28.09

Updated `gam <UserTypeEntity> print filelist "query:mimeType='application/vnd.google-apps.folder'" to prevent the
following error.
```
ERROR: Invalid choice (query:mimetype='application/vnd): Expected <capabilities|contentrestrictions|labelinfo|labels|lastmodifyinguser|owners|parents|permissions|sharinguser|shortcutdetails|trashinguser>
```

6.28.08

Added option `today` to `gam report` to look for events on the current day. This will be most useful
with `gam report <ActivityApplictionName>` as `gam report users|customers` rarely has data for the current day.

Added option `today` to `gam <UserTypeEntity> print|show driveactivity` to look for events on the current day.

6.28.07

Added option `csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*` to `gam <UserTypeEntity> copy drivefile`
that causes GAM to output CSV data detailing the name, id and mimeType of the copied files and folders
rather than text messages. These are the CSV headers:
```
User,name,id,newName,newId,mimeType
```
You can add additional columns of data from the command line to the CSV data with `(addcsvdata <FieldName> <String>)*`.

Added option `suppressnotselectedmessages [<Boolean>]` to `gam <UserTypeEntity> copy drivefile`
that causes GAM to suppress text messages referencing files and folders not selected for copying by the following options:
```
copysubfiles false [filenamematchpattern <RegularExpression>] [filemimetype [not] <MimeTypeList>]
copysubfolders false [foldernamematchpattern <RegularExpression>
copysubshortcuts false [shortcutnamematchpattern <RegularExpression>
```

6.28.06

Fixed bug in `gam <UserTypeEntity> print|show messages ... showbody` that caused a trap.

Added code to handle the following error that occurs when copying permissions:
```
ERROR: 400: shareInNotPermitted - Bad Request. User message: "An item can't be shared with user@domain.com because of domain.com sharing policy"
```

6.28.05

Added the following items to `<UserMultiAttribute>`:
* `employeeid <String>` as a synonym for `externalids organization <String>`
* `manager <String>` as a synonym for `relations manager <String>`

Added the following items to `<UserFieldName>`:
* `employeeid` as a synonym for `externalids`
* `manager` as a synonym for `relations`

6.28.04

Added `filtercontactgroup <PeopleContactGroupItem>` to `<PeoplePrintShowUserContactSelection>`
that is used by `gam <UserTypeEntity> print|show contacts`. When `selectcontactgroup <PeopleContactGroupItem>`
is used in these commands, GAM makes an API call to get the list of contacts in `<PeopleContactGroupItem>`
and then makes an API call per contact to get the details; this may exceed quota limits.
When `filtercontactgroup <PeopleContactGroupItem>` is used, GAM makes an API call to get all contacts and
then filters the list to only those in `<PeopleContactGroupItem>`; quota limits should not apply.

6.28.03

Build MacOS x86_64 and arm64 executables.

6.28.02

Fixed bug in `gam forward message|thread` that misformatted the message when `Cc:` was present.

6.28.01

Fixed bug in `gam forward message|thread` where subject was blanked out.

6.28.00

* Upgraded to Python 3.11.0 where possible.
* Upgraded to OpenSSL 3.0.7 where possible.

Fixed bug in `gam forward message` where messages originally sent to multiple recipients
were not forwarded correctly.

Added command to forward threads; all messages referenced by the thread are forwarded; this is experimental, test.
```
gam <UserTypeEntity> forward thread|threads recipient|to <RecipientEntity>
        (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
         [quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
        [subject <String>]
```

6.27.21

Eliminated superfluous column header `labels` in `gam print cigroups`.

Added command to forward messages; this is experimental, test.
```
gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
        (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+
         [quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
```

6.27.20

Added option `url <URL>` to `gam <UserTypeEntity> create|update drivefile` that allows
GAM to upload files referenced by `URL` to Google Drive.

Added `csv_input_row_limit` variable to `gam.cfg` that is used to limit the number of rows read from a CSV file.

Added `csv_output_row_limit` variable to `gam.cfg` that is used to limit the number of rows written to a CSV file.

6.27.19

Added option `embedimage <FileName> <String>` to the following commands that allows
embedding images in HTML email messages.
```
gam sendemail [recipient|to] <RecipientEntity>
gam <UserTypeEntity> sendemail recipient|to <RecipientEntity>
gam <UserTypeEntity> sendemail from <EmailAddress>
gam <UserTypeEntity> draft|import|insert message
```

Your HTML message will contain lines like this:
```
<img src="cid:image1"/>
<img src="cid:image2"/>
```

Your command line will have: `embedimage file1.jpg image1 embedimage file2.jpg image2`

Added `archive` as a synonym for `archived` and `suspend` as a synonym for `suspended`
in `<UserBasicAttribute>`.

6.27.18

Added option `tdshare <EmailAddress> commenter|reader|writer` to `<ToDriveAttribute>`. When a new
todrive file is created, i.e., `tdfileid <DriveFileID>` is not specified, the uploaded file will
be shared as specified. `<EmailAddress>` must be valid within your Google Workspace.

6.27.17

Updated `todrive tdfileid <DriveFileID>` to display an informative error message when Google generates
an `Internal Error`. It appears that the file was successfully uploaded and converted to a sheet but
the conversion took longer that the API was willing to wait, so it generated the error.

6.27.16

Updated `todrive tdfileid <DriveFileID>` to not perform retries for `Internal Error` when updating an existing file
as the 6.27.15 update didn't fix the underlying problem.

6.27.15

Fixed bug in `gam show chromeschemas` that caused a trap due to unexpected data from Google.

Updated `gam <UserTypeEntity> collect orphans` to handle the error:
```
ERROR: 403: shortcutTargetInvalid - The specified file is not an allowed shortcut target type.
```
These are typically Google Backup & Sync images of laptops.

Fixed bug in `gam <UserTypeEntity> sendemail from <EmailAddress>` that reported:
```
User: user@domain.com, Send Email to 0 Recipients
```

Updated `todrive tdfileid <DriveFileID>` to perform retries for `Internal Error` when updating an existing file.

Added option `noselfowner` to all commands that print or show calendar ACls;
it suppresses the display of ACLs that reference the calendar itself as its owner.

6.27.14

Extended `gam print addresses` to include information about domains and resource calendars.
A new column `Target` was added that displays target information for user, group and domain aliases.

6.27.13

Added option `showdate` to `gam <UserTypeEntity> print|show messages|threads` that displays
the `internalDate` field for a message|thread.
```
The internal message creation timestamp (epoch ms), which determines ordering in the inbox.
For normal SMTP-received email, this represents the time the message was originally accepted by Google,
which is more reliable than the Date header. 
```

6.27.12

Added option `labellist <LabelNameEntity>` to `gam <UserTypeEntity> print|show labels`
to allow selection of labels to display.

Added option `cigrouptree` to `gam info user`. Previously, the `grouptree` option used
the Cloud Identity Groups API to display the users group tree structure. This API is licensed
and the command would generate an error if you didn't have the license. Now, the `grouptree` option
uses the Directory API and the `cigrouptree` option uses the Cloud Identity Groups API.

Updated `gam <UserTypeEntity> collect orphans` to not use shortcuts by default.
If an orphan file can have its parent changed without affecting its access by other users, the parent is changed.
If a parent change would affect the access by other users, a shortcut is created. You can still use
the `useshortcuts true` option to force the use of shortcuts. If you specify the `preview` option,
a new column, `action`, shows `changeParent` or `createShortcut` to indicate what action will be taken
when `preview` is omitted.

6.27.11

Added options `showparentsaslist [<Boolean>]` and `delimiter <Character>` to `gam print grouptree` and
`gam <UserTypeEntity> print grouptree` that display the group parent emails and names in two columns
as delimited lists rather than multiple indexed columns.

Added options `downloadattempts <Integer>` and `retryinterval <Integer>` to `gam download vaultexport`
that cause GAM to wait for a vault export to be completed. By default, GAM makes only one download attempt.
If multiple attempts are specified with `downloadattempts <Integer>`, GAM waits `retryinterval <Integer>` seconds
between attempts; the default retry interval is 30 seconds.

6.27.10

Added command `gam <UserTypeEntity> print|show grouptree` to display a user's groups and their parent groups.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Group-Membership#display-groups-and-their-parents

6.27.09

Corrected JSON output in `gam <UserTypeEntity> print userlist`.

6.27.08

Added command `gam <UserTypeEntity> print userlist` to display the list of users in `<UserTypeEntity>` in a single row.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users#print-user-list

6.27.07

Fixed bug introduced in 6.27.06 that caused commands that get a list of groups for a specific user to fail;
e.g., `gam info user user@domain.com`.

6.27.06

Fixed bug in `gam print addresses` where no output was generated.

Updated multiprocessing to fix issues on Mac OS where excuting commands from a CSV file would
hang if the number of threads was 20 or greater.

6.27.05

Updated `gam create vaultexport` to handle the following error that occurs when the
`region` option is specified but is not allowed by your licenses.
```
ERROR: 400: invalidArgument - Request contains an invalid argument.
```

6.27.04

Updated `gam download vaultexport` to replace `:` with `-` in the download filename to avoid
issues on Windows.

6.27.03

Fixed update in 6.27.01 to allow empty resource calendar feature lists.

6.27.02

Added options `labelinfo` and `<DriveLabelInfoSubfieldName>` to `<DriveFieldName>` and
option `includelabels <DriveLabelIDList>` to `gam <UserTypeEntity> show fileinfo` and
`gam <UserTypeEntity> print filelist` to allow easier access to display drive file labels.
This options do not require an extra API call like the `showlabels details|ids` option does.
```
gam user user@domain.com show fileinfo 1kM4T2K4l0CCdR8lmp0pdXcytghAzXZ2fe5ThQpDwxyz fields id,name,mimetype,labelinfo includelabels "mRoha85IbwCRl490E00xGLvBsSbkwIiuZ6PRNNEbbFcb"
gam user user@domain.com show fileinfo query "'labels/mRoha85IbwCRl490E00xGLvBsSbkwIiuZ6PRNNEbbFcb' in labels" fields id,name,mimetype,labelinfo.fields includelabels "mRoha85IbwCRl490E00xGLvBsSbkwIiuZ6PRNNEbbFcb"
```

6.27.01

Updated `<ResourceAttribute>` to allow `features ""` for resources.

6.27.00

Updated code to use Python yield functionality when downloading long lists of items from Google APIs.

6.26.17

Fixed bug in `gam <UserTypeEntity> print filelist ... showparent` where parent folder was not shown in all cases.

Following Jay's lead, updated `gam info customer|domain` to provide better information when executed by a non super admin.

6.26.16

Updated `gam <UserTypeEntity> collect orphans` to include orphaned folders that were previously
excluded due to multi-parenting issues.

6.26.15

Updated `gam <UserTypeEntity> collect orphans` to use shortcuts by default rather than making parent changes.

This addresses the following issue:
* `testuser2` owns a file `X1234` located in a folder owned by user `testuser1` and shared with additional users
* `testuser1` removes `testuser2's` access to that folder
* File `X1234` now looks like an orphan to `testuser2`
* `gam user testuser2 collect orphans useshortcuts false`
* This moves `X1234` to the folder `testuser2 orphaned files`; i.e., it has a new parent
* `testuser1` and all other users no longer have access to `X1234` as it is now in a folder for which they have no access

Updated `gam <UserTypeEntity> add|delete|update|print|show datastudiopermissions` to display an appropriate
error message, `The caller does not have permission`, when the user doesn't have permission to execute the command.
Previously, the following incorrect error message was displayed:
`ERROR: Data Studio API not enabled. Please run "gam update project" and "gam user user@domain.com check serviceaccount"`

6.26.14

Extended `csv_input_row_filter`, `csv_input_row_drop_filter`, `csv_output_row_filter` and `csv_output_row_drop_filter`
to allow specification of filters based on field string length.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Input-Filtering
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Output-Filtering

6.26.13

Fixed bug in `gam <UserTypeEntity> copy othercontacts` that caused it to move a contact rather than copy it.

6.26.12

Fixed bug in `gam <UserTypeEntity> replacedomain contacts` that caused the error `ERROR: Invalid argument`.

Fixed bug in `gam <UserTypeEntity> print filetree` where some orphaned files were not displayed.

6.26.11

Updated `gam info group <GroupEntity> ... formatjson` to omit `"cloudIdentity": {},`
from the output when no Cloud Identity fields are requested.

Updated `gam info user <UserTypeEntity>` error message reporting to give this
message for non-existent users in the primary or sub domains.
```
User: user@domain.com, Does not exist
User: user@sub.domain.com, Does not exist
```
Previously, a non-existent user in a sub domain gave this error.
```
User: user@sub.domain.com, Service not applicable/Does not exist
```

6.26.10

Fixed bug in `gam print deviceusers` where command would never terminate. This would also occur
in `gam print devices` when `nodeviceusers` was not specified.

Added option `select <DeviceID>` to `gam print deviceusers` that displays device users for a specific device.

6.26.09

With many thanks to Jay:

* Added more OpenSSL 3.0.5 support
* Added support for Linux Ubuntu 22.04 Jammy Jellyfish x86_64

6.26.08

* Upgraded to Python 3.10.7
* Updated google-api-python-client to version 2.60.0
* Dropped support for Linux Precise (glibc 2.15)

6.26.07

Fixed bug in `gam <UserTypeEntity> update photo "https://drive.google.com/thumbnail?sz=w300&id=xxxxxxxxxxxxxxxxx"`
that generated a `Update Failed: Not Found: xxxxxxxxxxxxxxxxx` error.

6.26.06

Added `endpointverificationspecificattributes` to `<DeviceFieldName>` used by `gam info device`
and `gam print devices`.

* See: https://cloud.google.com/endpoint-verification/docs/overview

6.26.05

Fixed bug in `gam <UserTypeEntity> update contacts ... removecontactgroup <ContactGroupItem>` that failed
to remove the contact group `<ContactGroupItem>` when it was specified as the contact group formatted name
as opposed to the resource name; e.g., `Work Contacts` as opposed to `contactGroups/2ef39b48f4e361a`.

6.26.04

Updated `gam print courses ... aliasesincolumns` to properly align `Aliases` columns.

6.26.03

Updated the following commands to display a usage error (`ERROR: Invalid file selection with adminaccess|asadmin`)
if `<DriveFileEntity>` does not reference Shared Drives. Previously, execution errors (`Shared drive not found: xxxx`) would be displayed.
```
gam [<UserTypeEntity>] create|add drivefileacl <DriveFileEntity> [adminaccess|asadmin]
gam [<UserTypeEntity>] update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [adminaccess|asadmin]
gam [<UserTypeEntity>] delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [adminaccess|asadmin]
gam [<UserTypeEntity>] info drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [adminaccess|asadmin]
gam [<UserTypeEntity>] print drivefileacls <DriveFileEntity> [todrive <ToDriveAttribute>*] [adminaccess|asadmin]
gam [<UserTypeEntity>] show drivefileacls <DriveFileEntity> [adminaccess|asadmin]
gam [<UserTypeEntity>] create|add permissions <DriveFileEntity> <DriveFilePermissionsEntity> [adminaccess|asadmin]
gam [<UserTypeEntity>] delete permissions <DriveFileEntity> <DriveFilePermissionIDEntity> [adminaccess|asadmin]
```

6.26.02

Added option 'includederivedmembership' to `gam <UserTypeEntity> check groups` to allow 
checking if a user is a member of a group or one of its sub-groups.

6.26.01

Added option `nodetails` to gam <UserTypeEntity> print|show groups` that simply lists
the user's groups without making the addtional API call per group to get role, status and delivery settings.

Added command that allows checking if a user is a member of specific groups and optionally has a specific role.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Group-Membership#check-users-group-membership

6.26.00

Build MacOS universal version.

* Upgraded to OpenSSL 3.0.5 where possible.

Updated code in `gam create course <CourseAttribute>* copyfrom <CourseID>` to avoid a trap
caused by Google returning unexpected data in the `DueTime` field for course work.

6.25.21

Fixed bug in `gam <UserTypeEntity> check drivefileshortcut` that caused a trap when checking
a shortcut on a Shared Drive.

6.25.20

Updated `gam <UserTypeEntity> print|show shareddrives` to handle spurious Google Drive API error.
```
ERROR: 404: fileNotFound - Does not exist
```

6.25.19

Updated code to reflect Google change in how Cloud Identity User Invitations API is authenticated.

6.25.18

Updated processing of CSV files to allow a Google Doc to be downloaded as plain text and processed as a CSV file.

These are allowed
```
gdoc <UserGoogleDoc>
gdoc:<FieldName>)+ <UserGoogleDoc>
```
wherever the following are allowed.
```
gsheet <UserGoogleSheet>
gsheet(:<FieldName>)+ <UserGoogleSheet>
```

6.25.17

Added options `[formatjson [quotechar <Character>]]` to `gam print group-members|cigroup-members`.

Following Jay's lead, improved command `gam checkconnection`.

6.25.16

Added the following option to `gam <UserTypeEntity> copy drivefile ... recursive` to allow more control
over what sub files are copied when a top folder is copied.
```
filemimetype [not] <MimeTypeList>
```

6.25.15

Following Jay's lead, added command `gam checkconnection` that performs checks to verify the network connection to Google.
This is an initial effort to help diagnose Google connection issues usually caused by firewalls and/or proxies.

* Upgraded to Python 3.10.6

6.25.14

Added the following options to `gam <UserTypeEntity> copy drivefile ... recursive` to allow more control
over what sub files, folders and shortcuts are copied when a top folder is copied.
```
copysubfiles [<Boolean>] filenamematchpattern <RegularExpression>
copysubfolders [<Boolean>] foldernamematchpattern <RegularExpression>
copysubshortcuts [<Boolean>] shortcutnamematchpattern <RegularExpression>
```

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Copy-Move#copy-files-and-folders

Added the following mutually exclusive options to `gam <UserTypeEntity> delete|update|sync|print|show groups`
to allow more control over which groups are processed for a user. The `customerid <CustomerID>` option
will be most useful to resellers.
```
domain <DomainName>
customerid <CustomerID>
```

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Group-Membership

6.25.13

Updated code in `gam report users` to handle bug in Report API that caused a trap; when the `userEmail` field is
mistakenly omitted, GAM backs up to an earlier date.

Updated `gam info user` to display the same data (in different formats) when `quick` is used with and without `formatjson`.

6.25.12

Added option `selectmaincontacts` to `<PeoplePrintShowUserContactSelection>` to allow more flexibility in selecting contacts to display
with `gam <UserTypeEntity> print|show contacts`.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People-Contacts-Profiles#select-user-contacts

6.25.11

Updated error handling for `gam create|delete admin`.

6.25.10

Added option `norecursion [<Boolean>]` to `gam <UserTypeEntity> transfer ownership` to allow
ownership transfer of a folder but not its contents.

6.25.09

Fixed bug in `gam oauth info` that deleted the scopes in oauth2.txt if it had expired.

6.25.08

Added error checking to `gam create datatransfer` to avoid a trap.

6.25.07

Fixed bug introduced in 6.25.06 where only one row of a CSV file/Google Sheet was read by default.

6.25.06

Updated option `maxrows <Integer>` for `gam csv|loop` to be applied after input row filtering;
this allows limiting the number of filtered rows processed as opposed to the number of rows read.
* `maxrows 0` - All rows are processed, this is the default
* `maxrows N` - N filtered rows are processed

6.25.05

Added option `maxrows <Integer>` to `gam csv|loop` that allows you to limit the number of rows
read from the CSV file/Google Sheet. This can be used during testing in order to verify the functioning
of the command on a few rows before committing to all of the rows.
```
gam csv|loop <FileName>|-|(gsheet <UserGoogleSheet>) [charset <Charset>] [warnifnodata]
        [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>]
        (matchfield|skipfield <FieldName> <RegularExpression>)* [showcmds [<Boolean>]]
        [maxrows <Integer>]
        gam <GAMArgumentList>
```
* `maxrows -1` - All rows are read, this is the default
* `maxrows 0` - No rows are read
* `maxrows N` - N rows are read

6.25.04

Updated `gam create|update course ... copyfrom <CourseID> ... copytopics true` to preserve the topics order.

6.25.03

Updated `gam print users` to properly display the `languages` attribute based on the output format:
* `default` - `languages` column has the value `en+`
* `formatjson` - `JSON` column contains `"languages": [{"languageCode": "en", "preference": "preferred"}]`

6.25.02

Added option `missingtextvalue <String>` to `gam <UserTypeEntity> create note json ...` that causes GAM
to supply a value for JSON `list` and `text` items that are missing text fields. This option must appear
before the `json` option. If not specified and a text field is missing, you'll get the following error:
`Request contains an invalid argument.`

6.25.01

Updated license commands to retry the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

Updated `https://apps.google.com/user/hub` to `https://workspace.google.com/dashboard` in the new user email message; thanks to @jay-eleven.

6.25.00

Added initial support for the Drive Labels API. GAM can display drive labels and it can apply them to files
and display drive labels on files. Please test/experiment and report any issues.

To use these commands you must add the 'Drive Labels API' to your project and update your service account authorization.
```
gam update project
gam user user@domain.com check serviceaccount
```
Supported editions for this feature: Business Standard and Business Plus; Enterprise; Education Standard and Education Plus; G Suite Business; Essentials.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Labels
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display

6.24.27

Following Jay's lead, updated Cloud Identity API from v1beta1 to v1 for `userinvitations` commands.

6.24.26

Updated handling of shortcuts in `gam <UserTypeEntity> claim|transfer ownership`.

6.24.25

Corrected progress messages for `gam print groups showownedby`.

6.24.24

Added `gradebooksettings` to `<CourseFieldName>`.

6.24.23

Increase wait time in `gam create project` as Google is taking much longer to create projects.

6.24.22

Added option `license <SKUID> [product|productid <ProductID>]` to `gam create user` that assigns a
license to a user at the time of creation.

6.24.21

Fixed bug in `gam <UserTypeEntity> move drivefile ... createshortcutsfornonmovablefiles` that caused the following error:
```
ERROR: 403: shortcutTargetInvalid - The specified file is not an allowed shortcut target type.
```

6.24.20

Fixed bug in `gam <UserTypeEntity> claim ownership` that caused a trap.

6.24.19

* Upgraded to OpenSSL 1.1.1q

6.24.18

Added the following items to `<CrOSTypeEntity>`:
```
cros_ou_query <OrgUnitItem> <QueryCrOS>
cros_ou_and_children_query <OrgUnitItem> <QueryCrOS>
cros_ous_query <OrgUnitList> <QueryCrOS>
cros_ous_and_children_query <OrgUnitList> <QueryCrOS>
cros_ou_queries <OrgUnitItem> <QueryCrOSList>
cros_ou_and_children_queries <OrgUnitItem> <QueryCrOSList>
cros_ous_queries <OrgUnitList> <QueryCrOSList>
cros_ous_and_children_queries <OrgUnitList> <QueryCrOSList>
```
These allow specifying an OU, or a list of OUs, and a query or a list of queries
that apply to those OUs.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-ChromeOS-Devices

Example:
```
gam cros_ou_query /StudentChromebooks "sync:..2019-01-01" update ou "/OldChromebooks"
```

6.24.17

Updated `gam report user` to avoid a trap due to an unexpected change in the Reports API.

6.24.16

Fixed bug in `gam update cros <CrOSEntity> ... updatenotes "#notes#"abc"` that caused a trap
when the ChromeOS device didn't previously have notes.

6.24.15

Added `pre_provisioned_disable` and `pre_provisioned_reenable` to `<CrOSAction>`.

Updated code to take advantage of an update to the directory API that simplifies getting
ChromeOS devices from an OU and its children.

Fixed bug in `gam create|update adminrole` where child privileges were not recognized in `<PrivilegesList>`.

6.24.14

Fixed bug introduced in 6.24.13 that prevented specifying a contact group by name.

6.24.13

The Customer ID value that the Cloud Channel API describes is not the Google Workspace Customer ID value; it is unique to the Cloud Channel API.

Added `channel_customer_id` variable to `gam.cfg` that is used in `gam print|show channelcustomercentitlements` to specify the default value for `customerid`
rather than `customer_id` from `gam.cfg`.

6.24.12

Changed how `selectcontactgroup <ContactGroupItem>` is processed in commands that process
user contacts. Previously, GAM would download all of a user's contacts and locally filter
to get only the contacts in `<ContactGroupItem>`. Now, the People API is used to get the
list of contacts in `<ContactGroupItem>` and they are are individually downloaded for processing.

6.24.11

Following Jay's lead, updated `gam print devices|deviceusers` to try to work around
a Google API internal bug (237397223) that generates the following error after an hour:
```
ERROR: 400: invalidArgument - Request contains an invalid argument.
```

6.24.10

Updated `gam print devices` to refresh the access token between listing the devices
and listing the device users to try to avoid the following error:
```
ERROR: 400: invalidArgument - Request contains an invalid argument.
```

6.24.09

Updated `gam print devices|deviceusers` to handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.24.08

Added option `adminaccess` to `gam [<UserTypeEntity>] delete teamdrive <SharedDriveEntity>`
to allow Super Admins to delete Shared Drives even if they are not an organizer.

Added option `[<DriveFileParentAttribute>]` to `gam <UserTypeEntity> claim ownership <DriveFileEntity>`.
By default, `claim ownership` does not change the parents of `<DriveFileEntity>`; this options allows
specification of a parent folder in the My Drive of the claiming user `<UserTypeEntity>`.

Added option `[<DriveFileParentAttribute>]` to `gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem>`.
By default, `transfer ownership` does not change the parents of `<DriveFileEntity>`; this options allows
specification of a parent folder in the My Drive of the target user `<UserItem>`.

* Upgraded to Python 3.10.5
* Upgraded to OpenSSL 1.1.1p

6.24.07

Updated commands that process group settings to handle the following error:
```
ERROR: 401: authError - Authorization Failed
```

6.24.06

Improved `gam user user@domain.com print filecounts select teamdriveid "<DriveFileID>" summary only`
to display the Shared Drive ID and name on the summary line.

6.24.05

Updated option `orderby completed|due|updated` to `gam <UserTypeEntity> print|show tasks` to
display tasks in date order regardless of the hierarchy.

Fixed bug in 6.24.03 bug fix in `gam <UserTypeEntity> transfer drive <UserItem> ... targetfolderid root ...`.

6.24.04

Updated `gam update chromepolicy` to allow zero-length values for `TYPE_STRING` policy values;
this is required to be able to clear a value from such a policy.

6.24.03

Fixed bug in `gam <UserTypeEntity> transfer drive <UserItem> ... targetfolderid root ...` that
transferred data to the source user's root folder, not the target user's root folder.

6.24.02

Fixed bug in `gam print crostelemetry` that included a spurious column header, `devicdId`, in the output.

6.24.01

Updated `gam <UserTypeEntity> print|show tasks` to display tasks in hierarchical order.

Added option `orderby completed|due|updated` to `gam <UserTypeEntity> print|show tasks` to
display tasks in date order within the hierarchy.

6.24.00

Added commands to manage and display Google Tasks.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Tasks

6.23.01

Updated `gam <UserTypeEntity> create|update|show|print form` to give a better error message when the Forms API is not enabled.
```
ERROR: 403: permissionDenied - Google Forms API has not been used in project XXXXXXX before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/forms.googleapis.com/overview?project=XXXXXXX then retry. If you enabled this API recently, wait a few minutes for the action to propagate to our systems and retry.
```
is replaced with
```
ERROR: Forms API not enabled. Please run "gam update project" and "gam user user@domain.com check serviceaccount"
```

6.23.00

Updated `gam <UserTypeEntity> copy|move drivefile` to produce more
informative progress messages. The source file name(ID) are shown
as well as the target parent folder name(ID) and target file/folder name(ID).

Deleted options `copytopfileparents`, `copytopfolderparents` `copysubfileparents` and `copysubfolderparents`
from `gam <UserTypeEntity> copy drivefile` as multi-parent file/folders can not be copied with multiple parents.

Updated `gam <UserTypeEntity> copy drivefile` to use shortcuts when the same file appears more that once in the copy.
The first time the file is processed, it is copied; if it is processed again (because of multiple parents within the source
folder structure), a shortcut is created that points to the first copy.

Added option `copiedshortcutspointtocopiedfiles [<Boolean>]` to `gam <UserTypeEntity> copy drivefile`.
In previous versions, copying shortcuts caused an error because shortcuts can't be copied, they must be re-created.

If a shortcut in the source structure points to a file/folder that is not in the source structure:
 * The shortcut is re-created to point to the original file/folder.
If a shortcut in the source structure points to a file/folder that is in the source structure:
* `copiedshortcutspointtocopiedfiles` omitted or `copiedshortcutspointtocopiedfiles true` - The shortcut is re-created to point to the copied file/folder.
* `copiedshortcutspointtocopiedfiles false` - The shortcut is re-created to point to the original file/folder.

Deleted options `copysubfileparents` and `copysubfolderparents`
from `gam <UserTypeEntity> move drivefile` as multi-parent file/folders can not be moved with multiple parents.

Added option `createshortcutsfornonmovablefiles [<Boolean>]` to `gam <UserTypeEntity> move drivefile`
to control processing of non-movable files; for example, files owned by users outside of your domain.
It causes GAM to create a shortcut in the target folders for files in the source folders that are not movable.
* `createshortcutsfornonmovablefiles` omitted or `createshortcutsfornonmovablefiles false` - No shortcuts
are created and an error message is given explaining why the file can't be moved.
* `createshortcutsfornonmovablefiles true` - A shortcut is created that points to the non-movable file.

6.22.22

Fixed bug in `gam <UserTypeEntity> create|update contact` where the `relation` property was not properly processed.

6.22.21

Fixed bug where redirected stderr output from Gam main process was written
after GAM sub processes redirected stderr output.

6.22.20

The following update applies to one or two GAM users, if you're not one of them, stop reading.

When GAM is processing commands with data from a CSV file, `csv_input_row_drop_filter` and
`csv_input_row_filter` are evaluated and utilized by the GAM main process and are not
evaluated or processed by the GAM sub processes.

When GAM is processing commands with data from a CSV file, `csv_output_header_drop_filter`,
`csv_output_header_filter`, `csv_output_row_drop_filter` and `csv_output_row_filter` are
evaluated by the GAM main process and utilized by the GAM sub processes.

Evaluating the row filters once in the GAM main process means that `<RowValueFilter>`
forms `data:<DataSelector>` and `notdata:<DataSelector>` only read the data from `<DataSelector>` once.

6.22.19

Updated code to handle OUs with a `%` in their name. OUs with a `+` in their name
are still handled incorrectly by the API when accessed directly.

6.22.18

Added option `oneitemperrow` to `gam print vaultexports|exports` to have each of an
exports cloudStorageSink files displayed on a separate row.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault#display-vault-exports

Added options `bucketmatchpattern <RegularExpression>` and `objectmatchpattern <RegularExpression>`
to `gam download vaultexport|export` to allow selective downloading of export files.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault#download-vault-exports

6.22.17

Added `quick_cros_move` variable to `gam.cfg` that is used to provide the default value for `quickcrosmove [<Boolean>]` in:
```
gam update cros <CrOSEntity> <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatchupdate]
gam <CrOSTypeEntity> update <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatchupdate]
gam update org|ou <OrgUnitItem> add|move <CrOSTypeEntity> [quickcrosmove [<Boolean>]]
gam update org|ou <OrgUnitItem> sync <CrOSTypeEntity> [removetoou <OrgUnitItem>] [quickcrosmove [<Boolean>]]
```

Added `use_projectid_as_name` variable to `gam.cfg` that modifies `gam create project` to set
the default project name to the project ID instead of 'GAM Project' and to set the
default app name to the project ID instead of 'GAM'.

Improved error handling for the following error that occurs when the Customer ID is invalid.
```
ERROR: 400: invalidInput - Invalid Input
```

6.22.16

Corrected spelling of `spreadcheetid` to `spreadsheetid` and `spreadcheeturl` to `spreadsheeturl`
in `<SpreadsheetField>` used by `gam <UserTypeEntity> info|print|show sheet <DriveFileEntity>`.
```
<SpreadsheetField> ::=
        developermetadata|
        namedranges|
        properties|
        sheets|
        spreadsheetid|
        spreadsheeturl
```

6.22.15

Updated code to handle the following Oauth2 error:
```
ERROR: Authentication Token Error - access_denied: Account restricted
```

6.22.14

Added option `stripcrsfromname` to `gam <UserTypeEntity> print|show filepath` that causes carriage returns,
linefeeds and nulls to be stripped from file names.

Added option `fullpath` to `gam <UserTypeEntity> print|show filepath` and `gam <UserTypeEntity> show fileinfo`
that adds additional path information indicating that a file is an Orphan or Shared with me.

Added keywords `mydriveid` and `rootid` to `<DriveFileEntity>` as synonyms for `mydrive` and `root` in all
commands except `gam <UserTypeEntity> print filelist|filetree`. In those commands, `select mydrive|root`
is used to select a class of files; `select mydriveid|rootid` is used to select a folder starting point.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display#display-file-list

6.22.13

Updated code to handle another Google API problem when updating the OU of a Chromebook.

6.22.12

Updated code to handle a Google API problem when updating the OU of a Chromebook.

6.22.11

Updated `gam download vaultexport|export` to avoid a trap when the
`usenewexport true` option was used on the `gam create vaultexport|export` command
that created the matter.

6.22.10

Dropped deprecated argument `enforcesingleparent <Boolean>` from these commands:
```
gam <UserTypeEntity> create|add|update drivefile
gam <UserTypeEntity> create|add drivefileacl
gam <UserTypeEntity> create|add permissions
gam <UserTypeEntity> create|add sheet
```

6.22.09

Fixed bug in `gam print cros ...showdvrsfp` that caused a 'ZeroDivisionError: division by zero' trap.

6.22.08

Fixed bug where `gam info people` was not recognized as a valid command.

6.22.07

Fixed bug in `gam <UserTypeEntity> print|show filetree select <DriveFileEntity>` where the `stripcrsfromname`
option was not applied.

6.22.06

Updated code to handle Enterprise Licensing API issue with SKU 1010060001 (Google Workspace Essentials).

6.22.05

Fixed bug introduced in 6.22.04 in `gam print users` that caused a trap.

6.22.04

Fixed bug in `gam update drivefile <DriveFileEntity> ... parentid <DriveFolderID> newfilename <DriveFileName>`
where the file was not renamed.

The Enterprise License Manager API doesn't provide an option to get a list of the licenses a user holds.
For `gam info user`, GAM makes a batch API call with 47 product/SKU pairs querying whether the user holds
a license for the product/SKU. An error is returned (and suppressed) for each product/SKU pair for which
the user does not hold a license.

Currently, when you specify the `license` option with `gam print users`, GAM downloads all licenses for the domain
and from that data determines which licenses a user holds. For large numbers of users this works reasonably well;
for a small number of users the all license download might be overly expensive. The following options (synonyms)
`licensebyuser|licensesbyuser|licencebyuser|licencesbyuser` were added to `gam print users` that cause it
to use the batch API call method to retrieve the licenses for each user.

Additionally, these options `(products <ProductIDList>)|(skus <SKUIDList>)` can be used with both `gam info user`
and `gam print users` to limit the licenses retrieved.

Added `license_skus` variable to `gam.cfg` that defines the SKUs that will be processed when getting licenses.
Each item in the list can be  a `<SKUID>` which will be validated or `<ProductID>/<SKUID>` which will not.
The default, an empty string, means that all SKUs will be processed when getting licenses.

6.22.03

Fixed bug in `gam report customers|users ... date <Date> nodatechange` where previous
bug fix in 6.20.10 changed the format of the output.

6.22.02

Google has updated the Directory API to explicitly allow updating the OU of a Chromebook
with the OU ID rather than the OU path. The `update_cros_ou_with_id` variable in `gam.cfg` specifies
whether to use the OU ID or path to update the OU of a Chromebook.

The Directory API now supports displaying the OU ID of a Chromebook; added `orgunitid` to `<CrOSFieldName>`
to allow display of this attribute in `gam info|print cros`.

Added display of the OU ID of a Chromebook to `gam print crosactivity`.

6.22.01

Fixed bug in code introduced in 6.22.00 that caused a trap.

6.22.00

Extended `csv_input_row_filter`, `csv_input_row_drop_filter`, `csv_output_row_filter` and `csv_output_row_drop_filter`
to allow specification of filter values from a list, flat file or CSV file.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Input-Filtering
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Output-Filtering

6.21.07

When setting a multivalued custom schema field for a user, if `type home|other|work|(custom <String>)` is not specified,
`work` will be assigned. Previously, if type was not specified, Google would accept the field without a type
but would eventually set type to `work` itself in the background.

Added ProuctID `101036: Google Meet Global Dialing` and SKUID `meetdialing|googlemeetglobaldialing`;
thanks to @jay-eleven.

Added option `formatjson` to `gam info resoldcustomer <CustomerID>`.

6.21.06

Fixed bug in `gam update|use project` that caused the command to fail on Windows.

6.21.05

Fixed bug in `gam print|show projects|svcaccts` that caused a trap.

Added support for new calendar event read-only field `eventType`; thanks to @josemdv.

6.21.04

Updated handling of multivalued custom schema fields that are specified without a type;
the type will be shown as `work` as Google eventually sets the type to `work` itself in the background.

6.21.03

Fixed bug in `gam info|show schema` that caused a trap.

6.21.02

Updated `gam update chromepolicy` to allow specification of policy data with JSON.
For complex policies, this is the only way to enter the policy data.
```
gam update chromepolicy
        (<SchemaName>
          (<Field> <Value>)+ |
          (json [charset <Charset>] <JSONData>) |
          (json file <FileName> [charset <Charset>])
        )+
        ou|org|orgunit <OrgUnitItem> [(printerid <PrinterID>)|(appid <AppID>)]
```

6.21.01

Added `clock_skew_in_seconds` variable to `gam.cfg` that defines the number of seconds
of clock skew allowed between local time and Google time. The default value is 10 seconds
which was the previous hard-coded value.

Updated GAM spreadsheet commands to handle the following error:
```
ERROR: 400: failedPrecondition - This operation is not supported for this document
```

6.21.00

Added option `allowitemdeletion` to `gam [<UserTypeEntity>] delete shareddrive <SharedDriveEntity>`
that allows deletion of non-empty Shared Drives. This option requires a Super Admin user.

6.20.10

Fixed bug in `gam report customers|users ... date <Date> nodatechange` where no data was returned
in some cases when `allverifyuser <UserItem>` was not specified.

6.20.09

Added option `aliasmatchpattern <RegularExpression>` to `gam print users` that limits the display of aliases
to those that match `<RegularExpression>`.

6.20.08

Fixed bug in `gam <UserTypeEntity> copy|move drivefile` that caused a trap when a Shared Drive was involved.

6.20.07

Additional fixes to bug that caused a trap when `config csv_output_timestamp_column` and `formatjson` were used in the same command.

6.20.06

Fixed bug that caused a trap when `config csv_output_timestamp_column` and `formatjson` were used in the same command.

6.20.05

Updated options `notarchived|archived` in `gam update group|groups <GroupEntity> add|remove|sync`
to be usable with additional `<UserTypeEntity>`.

6.20.04

Added option `dynamicsecurity|makedynamicsecuritygroup` to `gam update cigroups <GroupEntity>`
so you can update a dynamic group to be a security group. You should use this option if you use
this option `security|makesecuritygroup` and get this error:
```
ERROR: 400: invalidArgument - Error(2022): Removing labels is not supported.
```

6.20.03

Fixed handling of Shared Drive API errors that was broken in 6.20.00.

6.20.02

Fixed bug in `gam <UserTypeEntity> create drivefileacl <DriveFileEntity ... csv formatjson` that caused a trap.

6.20.01

Added code to validate values in `<CAARegionList>` in `gam create|update caalevel`.

6.20.00

Following Jay's lead, updated `gam [<UserTypeEntity>] print|show teamdrives` to display
the `orgUnit` path for a Shared Drive in addition to its `orgUnitId`. The org unit information
is only available when the command is run as an administrator. Additional API calls are
necessary to get the `orgUnit` path; the option `noorgunits` disables the additional API
calls and display of the path .

Following Jay's lead, added option `ou|org|orgunit <OrgUnitItem>` to `gam [<UserTypeEntity>] update teamdrive` to
move the Team Drive to the specified OU. This option is only available when the command is run as an administrator.
As Jay says: THIS FEATURE IS CURRENTLY ALPHA.

Follwing Jay's lead, added commands to manage/display Context-Aware Access Levels.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Context-Aware-Access-Levels

6.18.04

Added the ability to upload Note attachments to Google Drive.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Keep#download-note-attachments

6.18.03

Added command to download Note attachments.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Keep#download-note-attachments

Updated `gam delete|update schema` to handle the following error:
```
ERROR: 500: FIELD_IN_USE - Cannot delete a field in use.resource.fields
```

6.18.02

Updated `gam create project` to proceed even if one or two APIs fail to be enabled;
currently, any failure terminates the project creation.

6.18.01

* Upgraded to Python 3.10.4

6.18.00

Added initial support for the Cloud Channel API; this is used by resellers.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Channel

6.17.02

Added a command to update basic form settings.
```
gam <UserTypeEntity> update form <DriveFileEntity>
        [title <String>] [description <String>] [isquiz [Boolean>]
```

6.17.01

Fixed bug in `gam <UserTypeEntity> print forms` that caused a trap when a form has no title.

6.17.00

Added initial support for the Forms API.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Forms

Fixed bug in `gam <UserTypeEntity> print|show filecounts ... showmimetype [not] <MimeTypeList>` that
removed `'me' in owners` from the query.

* Upgraded to Python 3.10.3
* Upgraded to OpenSSL 1.1.1n

6.16.19

Fixed bug in `gam print vaultcounts matter <MatterItem> corpus mail accounts <EmailAddressEntity>` where
extraneous lines `emails,0,` appeared in the output.

6.16.18

Fixed bug in `gam update contactphotos` and `gam <UserTypeEntity> update contactphotos` where
option `drivedir|(sourcefolder <FilePath>)` was not properly processed. Unfortunately, the
Domain Shared Contacts API seems to be broken when trying to manage contact photos.

6.16.17

Updated `gam <UserTypeEntity> replacedomain contacts emailmatchpattern <RegularExpression> domain <OldDomainName> <NewDomainName>`
to only replace `<OldDomainName>` with `<NewDomainName>` in the email addresses within the contact that match `<RegularExpression>`.
Previously, `emailmatchpattern <RegularExpression>` selected a contact and all email addresses within the contact had
their domain names updated if applicable.

6.16.16

Added option `aggregateusersby clientid|appname` to `gam <UserTypeEntity> print|show tokens` that
aggregates the users by `clientid|appname` and displays a count of the number of users rather
than the individual users for each `clientid|appname`.

6.16.15

Updated to allow new 10 million cell limit in Google Sheets.
* See: https://workspaceupdates.googleblog.com/2022/03/ten-million-cells-google-sheets.html

6.16.14

Added command to replace domain names in contact email addresses; this can be useful
when merging/renaming domains.
```
gam <UserTypeEntity> replacedomain contacts
        [<PeopleResourceNameEntity>|<PeopleUserContactSelection>]
        (domain <OldDomainName> <NewDomainName>)+
```

Fixed sorting of permissions in `gam <UserTypeEntity> print drivefileacls`.

6.16.13

Fixed the fix in 6.16.12.

6.16.12

Updated code to eliminate fix for a Python 3.10.0 bug that caused `gam <UserTypeEntity> print notes ... formatjson`
to display quotes in note text incorrectly.

6.16.11

Fixed bug in `gam <UserTypeEntity> show notes` that caused a trap when a note has no text
or a check box has no text.

6.16.10

Fixed bug in `gam <UserTypeEntity> print notes ... formatjson` where carriage returns and line feeds
were not properly displayed.

Fixed bug in `gam <UserTypeEntity> create note ... json` where carriage returns and line feeds
were not properly input.

6.16.09

Added option `role|roles <DriveFileACLRoleList>` to `gam <UserTypeEntity> print|show drivefileacls`
to simplify limiting displayed ACLs by role.

6.16.08

Added command to upload image files for use in Chrome policies.
```
<ChromePolicyImageSchemaName> ::=
        chrome.devices.managedguest.avatar |
        chrome.devices.managedguest.wallpaper |
        chrome.devices.signinwallpaperimage |
        chrome.users.avatar |
        chrome.users.wallpaper

gam create chromepolicyimage <ChromePolicyImageSchemaName> <FileName>
```

6.16.07

Extended option `stripcrsfromname` in the following commands to strip nulls and linefeeds
from displayed file names in addition to carriage returns.
```
gam <UserTypeEntity> info drivefile <DriveFileEntity>
gam <UserTypeEntity> print|show filerevisions <DriveFileEntity>
gam <UserTypeEntity> show fileinfo <DriveFileEntity>
gam <UserTypeEntity> print|show filetree
gam <UserTypeEntity> print filelist
```

6.16.06

Updated code to remove Python 3.9 dependency introduced in 6.16.05.

6.16.05

Added option `domain <DomainName>` to `gam print aliases` to simplify printing aliases from a secondary domain.

6.16.04

Fixed bug in `gam <UserTypeEntity> get drivefile` that caused a trap when the target file couldn't be written.

6.16.03

Fixed bug that broke `vault` commands.

Updated `gam oauth create` to use client access authentication flow as in Standard GAM, `config no_browser true` is no longer necessary.

6.16.02

Following Jay's lead, added option `removeresetlock` to `gam wipe device <DeviceEntity>` that will remove the account lock
on the Android or iOS device. This lock is enabled by default and requires the existing device user to log in after the wipe in order to unlock the device.
* See: https://support.google.com/android/answer/9459346

Following Jay's lead, added option `usenewexport <Boolean>` to `gam create vaultexport ... corpus mail`.
* See: https://support.google.com/vault/answer/4388708#new_gmail_export&zippy=%2Cfebruary-new-gmail-export-system-available

6.16.01

Updated `gam oauth create` to allow retries when `no_browser` is true and the user
enters an invalid authentication code.

6.16.00

With many thanks to Jay, updated `gam oauth create` to use a new client access authentication flow
as required by Google for headless computers/cloud shells; this is required as of February 28, 2022.
* See: https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html
  * OAuth out-of-band (oob) flow will be deprecated

6.15.24

Cleaned up `gam report` commands again to improve verification that valid data has been received.

Fixed bug in `gam <UserTypeEntity> dedup contacts` where `<PeopleResourceNameEntity>|<PeopleUserContactSelection>`
was not optional as documented.

6.15.23

Added option `replacefilename <RegularExpression> <String>` to `gam <UserTypeEntity> copy|create|update drivefile`
that allows using regular expressions to modify the copied/updated file name.
```
gam user user@domain.com update drivefile query "name contains '2020-2021'" replacefilename "2020-2021" "2021-2022"
gam user user@domain.com copy drivefile name Template parentid root recursive replacefilename Template NewCustomer
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Manage#update-files
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Copy-Move#copy-files-and-folders

6.15.22

Cleaned up `gam report` commands to improve verification that valid data has been received.

6.15.21

Added email audit monitor commands that were deleted in 5.34.00.
```
gam audit monitor create <EmailAddress> <DestEmailAddress> [begin <DateTime>] [end <DateTime>]
        [incoming_headers] [outgoing_headers] [nochats] [nodrafts] [chat_headers] [draft_headers]
gam audit monitor delete <EmailAddress> <DestEmailAddress>
gam audit monitor list <EmailAddress>
```
To use these commands, you should do:
```
gam update project
gam oauth create
```

6.15.20

Fixed bug in `gam <UserTypeEntity> print datastudiopermissions` where `todrive` was not recognized.

6.15.19

Further cleanup of `gam create|update alias`.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Aliases

6.15.18

After discussions with Jay, the default for creating/updating aliases is to verify that
the target `<UniqueID>|<EmailAddress>` exists by making extra API calls;
if you know that the target exists, you can suppress the verification with `notargetverify`.

6.15.17

Added option `verifytarget` to `gam create|update alias <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>`
that causes Gam to verify that the target `<UniqueID>|<EmailAddress>` exists.

6.15.16

Updated `gam <UserTypeEntity> deprovision` and `gam <UserTypeEntity> delete|update backupcodes`
to give a more informative error message when a user is suspended and backup codes can't be deleted|updated.

6.15.15

Fixed bug in `gam print crosactivity recentusers oneuserperrow` that caused a trap.

6.15.14

Added option `setchangepasswordoncreate [<Boolean>]` to `gam <UserTypeEntity> update user` that can be used
to force created (as opposed to updated) users to change their password at their next login.

6.15.13

Updated error messages in `gam <UserTypeEntity> update user createifnotfound`.

6.15.12

Added option `notifyonupdate [<Boolean>]` to `gam <UserTypeEntity> update user` that can be used
to suppress the email notificaton when options `notify <EmailAddressList> notifypassword <String>`
are specified for use in the case when the user must be created but not used when the user does exist
and is simply updated.

6.15.11

Updated `gam create cigroup` to handle the following error:
```
ERROR: 403: permissionDenied - Error(3006): This feature (Dynamic Groups) requires a premium SKU.
```

6.15.10

Fixed bug in `gam update ou / add|move ...` that caused the following error:
```
ERROR: 400: invalid - Invalid field selection orgUnitPath
```

6.15.09

Updated option `corpus` in `gam print vaultcounts` to only allow `mail` and `groups` as
required by the API.

6.15.08

Following Jay's lead, added option `condition securitygroup|nonsecuritygroup` to `gam create admin`
and option `condition` to `gam print|show admins`.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Administrators

6.15.07

Updated code in `gam print cros` to handle a missing data field that caused a trap.

6.15.06

Added option `dateheaderconverttimezone [<Boolean>]>` to `gam <UserTypeEntity> print|show messages|threads` that
converts `<SMTPDateHeader>` values to the `gam.cfg timezone`.

Updated option `dateheaderformat iso|rfc2822|<String>` to `gam <UserTypeEntity> print|show messages|threads` that allows
reformatting of any `<SMTPDateHeader>` value from RFC2822 format to the the following:
* `iso` - Format is `%Y-%m-%dT%H:%M:%S%z`
* `rfc2822` - Format is `%a, %d %b %Y %H:%M:%S %z`
* `<String>` - Format according to: https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior

6.15.05

Added option `dateheaderformat <String>` to `gam <UserTypeEntity> print|show messages|threads` that allows
reformatting of the message `Date` header from RFC2822 format to the format specified by `<String>`.
If `<String>` is `iso`, then ISO 8601 format is used, otherwise see: https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior
If the `Date` header can't be parsed as RFC2822, it is left unchanged.

6.15.04

Fixed bug in `gam <UserTypeEntity> copy drivefile <DriveFileEntity> ... excludepermissionsfromdomains <DomainNameList>` that caused a trap.

6.15.03

Updated `<CourseAttribute>` and `<CourseFieldName>` to use `descriptionheading` and `heading` synonymously.

6.15.02

Added the following options to `gam <UserTypeEntity> copy drivefile <DriveFileEntity>`
that provide more flexibility in managing permissions when copying/moving folders.
* Thanks to Kevin Sanghvi for suggesting these enhancements.
```
copysheetprotectedrangesinheritedpermissions [<Boolean>]
copysheetprotectedrangesnoninheritedpermissions [<Boolean>]
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Copy-Move#copy-permissions

6.15.01

Fixed bug in `gam <UserTypeEntity> print|show messages ... showattachments|saveattachments` where
some attachments were not recognized.
* Thanks to Craig Millsap for spending the time with me to find the solution.

6.15.00

Updated processing of `teamdrive <SharedDriveName>` in the following commands.
Previously, if there were multiple Shared Drives with the same `<SharedDriveName>`, GAM silently processed
the first one which may not have been the desired action. Now, a message is issued listing the multiple `<DriveFileIDs>` and
no processing is performed. Determine which Shared Drive ID is desired and reissue the command with `teamdriveid <DriveFileID>`.
```
gam <UserTypeEntity> print filelist select teamdrive <SharedDriveName>
gam <UserTypeEntity> print|show filecounts select teamdrive <SharedDriveName>
gam <UserTypeEntity> print|show filetree select teamdrive <SharedDriveName>
gam <UserTypeEntity> update teamdrive teamdrive <SharedDriveName>
gam <UserTypeEntity> delete teamdrive teamdrive <SharedDriveName>
gam <UserTypeEntity> hide teamdrive teamdrive <SharedDriveName>
gam <UserTypeEntity> unhide teamdrive teamdrive <SharedDriveName>
gam <UserTypeEntity> info teamdrive teamdrive <SharedDriveName>
gam <UserTypeEntity> print emptydrivefolders teamdrive <SharedDriveName>
gam <UserTypeEntity> delete emptydrivefolders teamdrive <SharedDriveName>
gam <UserTypeEntity> empty drivetrash teamdrive <SharedDriveName>
```

Added the following commands to transfer top level ACLs from one Shared Drive to another.
```
gam [<UserTypeEntity>] copy teamdriveacls <SharedDriveEntity> to <SharedDriveEntity>
        [adminaccess|asadmin]
        [showpermissionsmessages [<Boolean>]]
        [excludepermissionsfromdomains <DomainNameList>]
        (mappermissionsdomain <DomainName> <DomainName>)*
gam [<UserTypeEntity>] sync teamdriveacls <SharedDriveEntity> with <SharedDriveEntity>
        [adminaccess|asadmin]
        [showpermissionsmessages [<Boolean>]]
        [excludepermissionsfromdomains <DomainNameList>]
        (mappermissionsdomain <DomainName> <DomainName>)*
```

Added option `shownopermissionsdrives false|true|only` to `gam <UserTypeEntity> print|show teamdriveacls` that
controls whether Shared Drives with no permissions are displayed.
* `false` - Do not display Shared Drives with no permissions; this is the default
* `true` - Display Shared Drives with no permissions in addition to Shared Drives with permissions
* `only` - Display only Shared Drives with no permissions

Added the option `mappermissionsdomain <DomainName1> <DomainName2>` to `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>`
that maps `<DomainName1>` to `<DomainName2>` in any non-inherited permissions that are copied. The option can be specified multiple times
to provide different mappings.
* Thanks to Kevin Sanghvi for suggesting this enhancement.

Updated `gam <UserTypeEntity> delete othercontacts` to retry the delete step when
`notFound` errors are returned after the update step.

Fixed bug in `gam courses <CourseEntity> add|remove students|teachers` that caused API
call retries to fail with the following error:
```
Temporary error: notFound - @CourseNotFound The course was not found.
```

Improved performance when converting Shared Drive names to IDs.

Updated code to handle Shared Drive names that contain single quotes.

6.14.07

Corrected `gam.cfg` variable `cmdlog_max__backups` to be `cmdlog_max_backups`.

6.14.06

Fixed bug in `gam sync devices` where option `serialnumber_column` was not recognized.

Fixed bug in `gam sync devices` where a trap occurred when option `assigned_missing_action` was not specified.

6.14.05

Upgraded the `countsonly` suboption `showsource` in `gam <UserTypeEntity> print filelist` to display
the name of the source drive/folder (Name column) in addition to its ID (Source Column).

6.14.04

Added a command to move Other Contacts to My Contacts.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People-Contacts-Profiles#move-user-other-contacts
```
gam <UserTypeEntity> move othercontacts <OtherContactResourceNameEntity>|<OtherContactSelection>
```

Improved action performed messages in `gam <UserTypeEntity> update othercontacts`.

6.14.03

Added a command to delete Other Contacts.
* Thanks to Kim Nilsson for finding a Stack Overflow page that showed the way to do this.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People-Contacts-Profiles#delete-user-other-contacts
```
gam <UserTypeEntity> delete othercontacts <OtherContactResourceNameEntity>|<OtherContactSelection>
```

Added a command to update Other Contacts and move them to My Contacts.
* Thanks to Kim Nilsson for finding a Stack Overflow page that showed the way to do this.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People-Contacts-Profiles#update-user-other-contacts
```
gam <UserTypeEntity> update othercontacts <OtherContactResourceNameEntity>|<OtherContactSelection>
        <PeopleContactAttribute>+
        (contactgroup <ContactGroupItem>)*
```

6.14.02

Updated `gam print|show teamdriveacls` to display the creation time of the Team/Shared drives.

6.14.01

Added the option `excludepermissionsfromdomains <DomainNameList>` to `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>`
that excludes permissions that reference any domain in `<DomainNameList>` from being copied.
* Thanks to Kevin Sanghvi for suggesting this enhancement.

Fixed bug `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>` where option `copymergewithparentfolderpermissions`
was not recognized.

6.14.00

Added the following options to `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>`
that provide more flexibility in managing permissions when copying/moving folders.
* Thanks to Kevin Sanghvi for suggesting these enhancements.
```
copyfileinheritedpermissions [<Boolean>]
copyfilenoninheritedpermissions [<Boolean>]
copymergewithparentfolderpermissions [<Boolean>]
copymergedtopfolderpermissions [<Boolean>]
copytopfolderiheritedpermissions [<Boolean>]
copytopfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
copymergedsubfolderpermissions [<Boolean>]
copysubfolderinheritedpermissions [<Boolean>]
copysubfoldernoniheritedpermissions never|always|syncallfolders|syncupdatedfolders
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Copy-Move#copy-permissions
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Copy-Move#move-permissions

Following Jay's lead, added command `gam <UserTypeEntity> show vaultholds` to display all vault holds
affecting a user. This allows you to investigate the error `Delete Failed: Precondition is not met.`
when trying to delete a user.

Added option `buildpath [<Boolean>]` to `gam <UserTypeEntity> create filter label <LabelName>` that controls whether
`<LabelNames>` of the form `Top/Middle/Bottom` will be created as single-level or multi-level.

Added option `hidden <Boolean>' to `gam <UserTypeEntity> update teamdrive`.

Fixed bug in `gam print|show matters matterstate <MatterStateList>` that caused a trap.

Fixed bug in `gam update mobile <MobileEntity> action block` that caused the following error:
```
ERROR: 400: invalidInput - Invalid value for: action_block is not a valid value
```

* Upgraded to Python 3.10.2
* Updated google-api-python-client to version 2.35.0

6.13.09

Fixed bug in `gam <UserTypeEntity> update chromepolicy` that caused a trap.

Fixed bug in `gam print|show datatransfers oldowner|newowner <UserItem>` that did not
properly handle `<UserItem>` of form `uid:<String>`.

6.13.08

* Upgraded to OpenSSL 1.1.1m

Added command `gam info currentprojectid` that displays the current Project ID.

6.13.07

Added options `showpermissionmessages` and `sendemailifrequired` to `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>`.
Previously, when attempting to copy ACLs, GAM would report any errors; some errors were generated when an attempt
was made to inappropriately copy an ACL. Now, GAM will not attempt to copy ACLs unless they are appropriate.
When `showpermissionmessages` is specified GAM will display messages about ACLs not copied, ACLs that were copied
and any remaining copy errors.

When copying an ACL that references a non Google account, an error is generated unless an email is sent to the account;
by default, no email notifications are sent. The `sendemailifrequired` options instructs GAM to send an email notification in this case.

6.13.06

Added option `formatjson` to `gam <UserTypeEntity> info filters` and `gam <UserTypeEntity> show filters`.

6.13.05

Handle the following error in `gam <UserTypeEntity> signout`:
```
ERROR: 400: invalidInput - Invalid Input
```
This can be caused by applying the command to a suspnded user.

6.13.04

Added option `showsize` to `gam <UserTypeEntity> print|show filecounts` that displays the
size (in bytes) of the files counted.

Following Jay's lead, added commands to display ChromeOS device telemetry data.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices#display-chromeos-telemetry-data

To use these commands  you must authorize an additional scope:
* `Chrome Management API - Telemetry read only`
```
gam oauth create
```

Added option `reverselists <ListFieldNameList>` to commands that display ChromeOS device information.
For each list in `<ListFieldNameList>`, the list order is changed from ascending (oldest to newest) to descending (newest to oldest);
this makes it easy to get the `N` most recent values with `listlimit N reverselists <ListFieldNameList>`.

6.13.03

Added options `parentselector <OrgUnitSelector>` and `childselector <OrgUnitSelector>` to
`gam print orgs|ous` that add an additional column `orgUnitSelector` to the output. This column
value can be used in subsequent `gam csv` commands to appropriately select members without duplication.
```
<OrgUnitSelector> ::=
        cros_ou | cros_ou_and_children|
        ou| ou_ns | ou_susp|
        ou_and_children | ou_and_children_ns | ou_and_children_susp

Get file count summaries by OU; top level selector is ou, sub level selectors are ou_and_children

gam redirect csv ./TopLevelOUs.csv print ous showparent toplevelonly parentselector ou childselector ou_and_children fields orgunitpath
gam redirect csv ./FileCounts.csv multiprocess csv ./TopLevelOUs.csv gam "~orgUnitSelector" "~orgUnitPath" print filecounts excludetrashed summary only summaryuser "~orgUnitPath"
```

6.13.02

Updated error handling in `gam <UserTypeEntity> copy drivefile` when copying files to a shared drive folder.

6.13.01

Added option `summaryuser <String>` to `gam <UserTypeEntity> print filecounts` and
`gam <UserTypeEntity> print filelist countsonly` that replaces the default summary user `Summary`
with `<String>`.
```
gam redirect csv ./FileCounts.csv multiprocess csv ./OUs.csv gam ou_ns "~orgUnitPath" print filecounts excludetrashed summary only summaryuser "~orgUnitPath"
```

Uodated `gam <UserTypeEntity> update drivefile <DriveFileEntity> teamdriveparentid <DriveFolderID>
to handle the following error:
```
ERROR: 400: shareOutNotPermitted - Bad Request. User message: "shareOutNotPermitted"
```

6.13.00

Fixed bug in `gam <UserTypeEntity> copy drivefile` where `contentManager|fileOrganizer` ACLs
were not copied from a source shared drive folder to a target shared drive folder.

6.12.06

Fixed bug where `redirect csv - multiprocess todrive redirect stdout - multiprocess` would disable
`multiprocess` for `redirect csv` which resulted in multiple files being uploaded.

Added option `showshareddrivepermissions` to `gam <UserTypeEntity> show fileinfo <DriveFileEntity>` that is applicable
when no fields are selected and `<DriveFileEntity>` is a shared drive file/folder. In this case,
the Drive API returns the permission IDs but not the permissions themselves so GAM makes an additional API call
to get the permissions.

Added option `showshareddrivepermissions` to `gam <UserTypeEntity> print filelist` that is applicable
when no fields are selected and shared drives are queried/selected. In this case,
the Drive API returns the permission IDs but not the permissions themselves so GAM makes an additional API call
per file to get the permissions.

Added commands that can process lists of Gmail labels.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Labels

6.12.05

Updated `gam info|print cros showdvrsfp formatjson` to include `diskVolumeReports.volumeInfo.storageFreePercentage`.

Improved error messages for `gam create resource` when options `capacity <Number>` and `floor <String>`
are required but not provided.

6.12.04

Added option `showdvrsfp` to `gam info|print cros` that causes GAM to display a field
`diskVolumeReports.volumeInfo.storageFreePercentage` which is calculated as:
* `(diskVolumeReports.volumeInfo.storageFree/diskVolumeReports.volumeInfo.storageTotal)*100`

You can use an output row filter to only show ChromeOS devices with a limited amount of free space:
* `config csv_output_row_filter "diskVolumeReports.volumeInfo.0.storageFreePercentage:countrange=1/15"`
Use `countrange=1/15` instead of `count<15` as the latter will display ChromeOS devices with no
diskVolumeReports; a blank entry is treated as a zero.

ChromeOS devices can have multiple diskVolumeReports; some experimentation may be required to
get the desired results.

6.12.03

The 6.12.02 bug fix in `gam <UserTypeEntity> print|show filetree select <DriveFileEntity>`
was too aggressive; when showing a file tree, folders owned by others must be processed
so that files owned by the user within those folders are displayed.

6.12.02

When running `gam oauth create` and `gam.cfg no_browser = true`, the authorization link is
no longer copied to the file `gamoauthurl.txt` as this functionality required modifying
a Google supplied library.

Removed the option `writeurltofile` from `gam check| svcacct` that caused GAM to write
the authorization link to the file `gamsvcaccturl.txt`.

Fixed bug in `gam <UserTypeEntity> print|show filetree select <DriveFileEntity>` where
file ownership was not being checked which resulted in files not owned by the user being displayed.

6.12.01

Updated code to perform retries when a `serviceNotAvailable` error occurs when listing file permissions.

6.12.00

Fixed bug in `gam <UserTypeEntity> copy drivefile <DriveFileEntity> <DriveFileParentAttribute> recursive`
that mis-copied files when the target parent folder `<DriveFileParentAttribute>` was within the folder structure of `<DriveFileEntity>`.

Fixed bug in `gam <UserTypeEntity> check drivefileshortcut <DriveFileEntity> csv` that caused a trap.

6.11.07

Added command `gam <UserTypeEntity> delete labelid <LabelID>` that is used to
delete Gmail labels by ID rather than by name.

6.11.06

Fixed bug in 6.11.05 for updating Chromebook OU by ID.

6.11.05

Added `update_cros_ou_with_id` variable to `gam.cfg` that causes GAM to update
the OU of a Chromebook with the OU ID rather than the OU path.
Set this value to true if you are getting the following error:
```
400: invalidInput - Invalid Input: Inconsistent Orgunit id and path in request
```

6.11.04

When specifying `<UserAttribute> languages`, it is an error to specify a custom language with a preference suffix `+-`.

Added option `includederivedmembership` to `gam print|show cigroup-members`.
This option causes the API to list indirect members of groups.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups-Membership

Updated `gam oauth export|refresh` to privent the following error.
```
ERROR: Authentication Token Error - Not all requested scopes were granted by the authorization server, missing scopes , https://sitesgooglecom/feeds, https://wwwgooglecom/m8/feeds
```

6.11.03

Added option `noinvitablecheck` to `gam whatis <EmailItem>` that suppresses the user invitation check
to avoid exceeding quota limits when checking a large number of addresses.

Following Jay's lead, updated processing of `<UserAttribute> languages`.
You could always set a user's languages via the API; Google has added the ability to
indicate whether a language is `preferred` or `not_preferred`. This is implemeted in
GAM by optionally appending a `+` to a language code to set `preferred` and a '-' to set `not_preferred`.
In the user's profile, only `preferred` languages are displayed.
```
gam update user user@domain.com languages en+,fr+.
```

Updated all Cloud Identity API group calls to use version `v1` of the API rather than version `v1beta1`.

6.11.02

Added option `nobatchupdate` to `gam <CrOSTypeEntity> update ou <OrgUnitPath>` and
`gam update cros <CrOSEntity> ou <OrgUnitPath>` that prevents GAM from using batch mode
to update the devices; this allows handling the `rateLimitExceeded` error described below.

6.11.01

Updated code to to handle the following error as retryable:
```
403: rateLimitExceeded - Quota exceeded for quota metric 'Queries' and limit 'Queries per minute per user' of service 'admin.googleapis.com' for consumer 'project_number: (project)'
```

6.11.00

Updated `gam print groups` and `gam print|show group-members` to allow identification of groups
with the `All users in the organization` member with: `member id:<CustomerID>`.

Upgraded to Python 3.10.1

6.10.05

Added option to the `copyfrom` option used with `gam create/update course` that modifies how
course work and materials are copied.
* `markdraftaspublished` - Mark all draft course work and materials as published

Updated `todrive` options to simplify updating an existing sheet within an existing file.
Previously, if you specified `tdfileid <DriveFileID> tdsheet (id:<Number>)|<String> tdupdatesheet`,
the sheet had to exist. The updated behavior is:
* `tdfileid <DriveFileID> tdsheet id:<Number> tdupdatesheet` - The specified sheet must exist
* `tdfileid <DriveFileID> tdsheet <String> tdupdatesheet` - The specified sheet will be created if necessary

6.10.04

Fixed bug introduced in 6.10.03 that broke `gam <UserTypeEntity> update drivefileacl <DriveFileEntity>`.

Updated `gam whatis <EmailItem>` to give a better message if `<EmailItem>` is not a group/user email address
or alias and Service Account scope `Cloud Identity User Invitations API` is not enabled.

Renamed client access scope `Directory API Printers` to `Chrome Printer Management API`; there is
no change in functionality.

6.10.03

Updated `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity> <DriveFileParentAttribute>`
to enforce the requirement that the specified user be a Shared Drive organizer
if either `<DriveFileEntity>` or `<DriveFileParentAttribute>` specifies a Shared Drive.

Added options `csv [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]` to
`gam <UserTypeEntity> create|update drivefileacl <DriveFileEntity>` that causes GAM to
output the new ACL details in CSV form rather than indented keywords and values.

6.10.02

Following Jay's lead, fixed obscure problem when creating a project in timezones ahead of GMT.

6.10.01

Updated `gam create domainalias|aliasdomain <DomainAlias> <DomainName>` to handle error when
an invalid `<DomainAlias>` is specified.

6.10.00

Added `csv_output_subfield_delimiter` and `people_max_results` variables to `gam.cfg`.
```
csv_output_subfield_delimiter
    Character used to delimit fields and subfields in headers when writing CSV files;
    this must be a single character
    Default: '.'

people_max_results
    When retrieving lists of People from API,
    how many should be retrieved in each API call
    Default: 100
    Range: 0 - 1000
```

6.08.31

Updated `<UserBasicAttribute>` so that an OU ID can be specified in addition to an OU path.
```
<UserBasicAttribute> ::=
        org|ou|orgunitpath <OrgUnitPath>|<OrgUnitID>
```
This is applicable to `gam create|update user`; n.b., the API requires a path so an additional API call
must be made to convert the ID to a path.

6.08.30

Added option `showsize` to `gam <UserTypeEntity> print filelist countsonly` that adds an additional
column `Size` that indicates the total size (in bytes) of the files represented on the row.

6.08.29

Added options `onerowpertarget` and `suppressnoaliasrows` to `gam print aliases`.

By default, the CSV output has three columns: `Alias,Target,TargetType`; if a target
has multiple aliases, there will be multiple rows, one per alias. Specifying `onerowpertarget` changes
the three columns to: `Target,TargetType,Aliases`; all aliases for the target are space-separated in the
`Aliases` column.

Specifying both `onerowpertarget` and `suppressnoaliasrows` causes GAM to not display any targets that have no aliases.

Added command `gam remove aliases|nicknames <EmailAddress> user|group <EmailAddressEntity>` to more efficiently
delete the aliases in `<EmailAddressEntity>` from the `user|group` `<EmailAddress>`.

You can combine these two changes as follows:
```
gam redirect csv ./OldDomainAliases.csv print aliases aliasmatchpattern ".*@olddomain.com" onerowpertarget suppressnoaliasrows
gam csv ./OldDomainAliases.csv gam remove aliases "~Target" "~TargetType" "~Aliases"
```

Fixed bug in `gam user user@domain.com sendemail ... ghtml ...` that caused an inappropriate error.
```
ERROR: User: user@domain.com, Drive File: Email Doc, Data Not Retrieved: Invalid mimeType application/vnd.google-apps.document, must be text/html
```

6.08.28

Updated Google API libraries.

6.08.27

Reverted update 6.08.26 as it couldn't accurately distinguish between the following cases in all instances:
* A Service Account scope is not authorized
* A user with a service disabled
* A user from outside your domain

6.08.26

Improved the error message displayed when a Service Account scope is not authorized so it
can be distinguished from a user with the service disabled.

6.08.25

Updated `gam create|use project` to handle the following spurious Google error:
```
ERROR: 500: Failed to convert server response to JSON - 500
```

6.08.24

Fixed bug in `gam <UserTypeEntity> print|show contacts fields ...` that caused an error
when retrieving other contacts.

Revert Google Auth library to version 2.0.2 to avoid the following error:
```
ERROR: Token used too early, 1634572527 < 1634572532. Check that your computer's clock is set correctly.
```

6.08.23

Updated code to format Google timestamps with fractional seconds, e.g., `2021-10-13T13:35:42.590124Z`
and `timezone = utc` in gam.cfg.

6.08.22

Fixed bug in `gam create|clear|dedup|delete|info|print|show|update contacts` where
the command would fail if the domain was not defined in gam.cfg

6.08.21

Fixed bug `gam <UserTypeEntity> print contactdelegates` that caused a trap.

6.08.20

Updated `gam print|show ownership` to display the event name of the most recent
primary event. If the event name is `delete`, then you'll know who the owner was
but won't be able to do much with the file.

6.08.19

Fixed bug in `gam update group` where field `memberKey` was mistakenly converted to `preferredMemberKey`;
this caused a trap.

6.08.18

Updated code to work around issue in Cloud Identity Groups API where a group member of
type `CUSTOMER` is not properly marked as that type; this caused a trap.

6.08.17

Fixed bug in `gam show cigroup-members` where the deprecated field `memberKey` was still being used;
it was replaced with `preferredMemberKey`.

6.08.16

Fixed bug in metacommand `multiprocessexit` where GAM would not terminate when the condition was met
by one process while multiple other processes terminated simultaneously with the condition not met.

6.08.15

In 6.07.24, `delivery_settings` was added to the default list of fields in `gam print group-members`.
Unfortunately, it is still the case that an additional API call per member is required to get this setting;
this makes getting group members very slow for large groups.

`delivery_settings` has been removed from the default list of fields and the option `showdeliverysettings`
adds this field to the default list of fields. You can always specify a specific list of fields that includes
`delivery_settings`.

6.08.14

Fixed bug in `gam redirect csv ... multiprocess ...` that caused a trap when running on Windows.

6.08.13

Fixed bugs in `gam <UserTypeEntity> copy othercontacts` that rendered it unusable; sigh.

Following Jay's lead, added support for newly announced group member restrictions.
You can update groups to restrict membership to only include users, groups or service accounts as well as internal users and groups.
* See: https://workspaceupdates.googleblog.com/2021/10/membership-restrictions-google-groups-.html
In the API, these member restrictions fall with a category called `SecuritySettings`.

Added option `nosecuritysettings` to `gam info cigroups <GroupEntity>`. By default, GAM
makes an additional API call to get the `SecuritySettings`; this option suppresses that call.

Added option `memberrestrictions <QueryMemberRestrictions>` to `gam update cigroups <GroupEntity>`
to define member restrictions.
* See: https://cloud.google.com/identity/docs/reference/rest/v1beta1/SecuritySettings#MemberRestriction

Added option `memberrestrictions` to `gam print cigroups` that causes GAM to make an
additional API call to get the member restrictions from the `SecuritySettings`.

6.08.12

Added `(json [charset <Charset>] <JSONData>)|(json file <FileName> [charset <Charset>])` to `<PrinterAttribute>`
that allows specification of printer attributes from JSON data in `gam create|update printer`.
```
<PrinterAttribute> ::=
        (description <String>)|
        (displayname <String>)|
        (json [charset <Charset>] <JSONData>)|(json file <FileName> [charset <Charset>])|
        (makeandmodel <String>)|
        (ou|org|orgunit <OrgUnitItem>)|
        (uri <String>)|
        (driverless [<Boolean>])
```

6.08.11

Added option `copysheetprotectedranges [<Boolean>]` to `gam <UserTypeEntity> copy drivefile` that causes
GAM to copy the Google Sheet permissions and protected ranges from the source file to the target file.

Updated `gam update cigroups <GroupEntity> update [<GroupRole>] expires <Time> <UserTypeEntity>`
to handle the following error:
```
ERROR: 403: permissionDenied - Error(3005): Non-premium customers do not have access to certain premium features.
```

6.08.10

Fixed bug in `gam <UserTypeEntity> clear contacts` that caused a trap.

6.08.09

Changed license SKU `Google-Apps` name `Google Workspace Free/Standard` to `G Suite Legacy` to be
consistent with Google.

6.08.08

Updated all commands that reference Cloud Identity Group members to use the field `preferredMemberKey`
rather than the deprecated field `memberKey` which would cause traps.

6.08.07

Fixed bug in `gam <UserTypeEntity> create|update contact json <JSONData>` that failed to delete
the read-only field `updateTime` which caused the command to fail.

Added the following keyword to `gam.cfg` that causes GAM to add a timestamp column
to the CSV output file; the value in each row is time at which the command started.
```
csv_output_timestamp_column
        Name of column in the CSV output file to contain a timestamp
        Default: ''
```

Added option `timestampcolumn` to `<Redirect>` that causes GAM to add a timestamp column labeled `<String>`
to the output CSV file; the value in each row is time at which the command started.
This overrides the `csv_output_timestamp_column` value in `gam.cfg`.

```
<Redirect> ::=
        redirect csv <FileName> [multiprocess] [append] [noheader] [charset <Charset>]
                     [columndelimiter <Character>] [quotechar <Character>]
                     [timestampcolumn <String>]
                     [todrive <ToDriveAttribute>*] |
```

6.08.06

Added `formatjson` to `gam info|show resoldsubscriptions` and `formatjson [quotechar <Character>]`
to `gam print resoldsubscriptions`.

Handle the following error as retryable when managing user's contacts:
```
ERROR: API access Denied
```

6.08.05

Added option `addcsvdata <FieldName> <String>` to `gam create drivefile ... csv`. This adds
additional columns of data to the CSV file output. For example, you are building student folders
on a Shared Drive as an admin and want to add ACLs to the folders allowing the student write access
and you want a shortcut on the student's My Drive pointing to the folder. By adding the student's
primary email address to the CSV output, it can be used in subsequent commands.
Substitute for admin@domain.com and `<TeamDriveID>`.
```
Students.csv
primaryEmail,Name
bob@domain.com,Bob Jones
mary@domain.com, Mary Smith
...

# Create the student folders on the Shared Drive
gam redirect csv ./StudentFolders.csv multiprocess csv Students.csv gam user admin@domain.com create drivefile mimetype gfolder drivefilename "~~Name~~ Digital Portfolio" parentid <TeamDriveID> csv addcsvdata primaryEmail "~primaryEmail"
# Add ACLs granting the students write access to their folders; ~User refers to admin@domain.com
gam csv StudentFolders.csv gam user "~User" add drivefileacl "~id" user "~primaryEmail" role fileorganizer
# Add a shortcut to the folder on the student's My Drive
gam csv StudentFolders.csv gam user "~primaryEmail" create drivefileshortcut "~id" parentid root
```

6.08.04

Handle the following error in `gam move drivefile`:
```
ERROR: 400: crossDomainMoveRestriction - Bad Request. User message: "crossDomainMoveRestriction"
```

Improved error messages when an unknown contact ID is used in a command.

6.08.03

Use Python library pathvalidate to clean up filenames in `gam get drivefile|document`.
If you are using the source verson of GAMADV-XTD3, do the following command to update your Python libraries.
```
pip install --upgrade -r src/requirements.txt
```

6.08.02

Updated `gam sync devices` to include the `assetTag` field, if specified, as part of the device
comparison key in addition to `serialNmmber` and `deviceType`.

6.08.01

Fixed bug in `gam create device` that caused a trap.

Updated `gam print|show chromeapps|chromedevices|chromeversions` to handle the following error.
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.08.00

GAM now uses the People API to manage user contacts rather than the Contacts API.

Most commands will work unchanged but Google has completely changed how the data is presented. If you
have scripts that process the output from `print contacts` for example, they will have to be changed.

You might want to keep an older version of GAM available so you can compare the output from the two
versions and make adjustments as necessary.

This is work in progress, report issues/problems.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People-Contacts-Profiles

6.07.31

Fixed bugs in `gam sync devices` that rendered it useless.

Deleted most local copies of Google and non-standard Python libraries.
If you are using the source verson of GAMADV-XTD3, do the following command to update your Python libraries.
```
pip install --upgrade -r src/requirements.txt
```
You should delete the following files from `src/gam`:
```
distro.py,filelock.py
```
You should delete the following directories from `src/gam`:
```
dateutil,google,google_auth_httplib2,googleapiclient,
httplib2,oauthlib,passlib,requests,requests_oauthlib
```

6.07.30

Update Google API libraries.

6.07.29

Removed `agreed2terms|agreedtoterms <Boolean>` from `<UserBasicAttribute>`; this is a read-only attribute
and can't be modified.

6.07.28

Fixed bug in `gam user user@domain.com remove calendars courses_with_teacher user@domain.com` that caused a trap.

6.07.27

Updated from `Cloud Identity Groups API` version v1beta1 to version v1.

6.07.26

Added metacommand `multiprocessexit (rc<Operator><Number>)|(rcrange=<Number>/<Number>)|(rcrange!=<Number>/<Number>)`
that will terminate processing of a CSV or batch file when one of the subprocesses returns a matching return code.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Meta-Commands-and-File-Redirection#specify-multiprocessing-termination-return-code

This change was inspired by the brute force approach to finding the owner of a file by stepping through
all users. Once the owner is found, there is no need to process the remaining users; this change allows
processing to be terminated when the owner is found.
```
gam config auto_batch_min 1 multiprocessexit rc=0 redirect csv - multiprocess redirect stderr null multiprocess all users print filelist select id <DriveFileID> fields id,name,owners.emailaddress norecursion showownedby any
```

6.07.25

Cleaned up License Product/SKU names; replaced `G Suite` with `Google Workspace` where appropriate.

6.07.24

Added option `defaultsender self|group` to `<GroupSettingsAttribute>`.

Added `delivery_settings` to the default list of fields in `gam print group-members`.

6.07.23

Update Google API libraries, remove unused libraries.

6.07.22

Updated `gam info domain` to generate an error when the `customer_id` and `oauth2_txt` values are not consistent.
This typically happens when the wrong customer ID is assigned to a `gam.cfg` section.

6.07.21

Fixed bug in `gam create datatransfer <OldOwnerID> <DataTransferServiceList> <NewOwnerID>`
where the privacy level was not being set in all applications if more than one was
specified in `<DataTransferServiceList>`.

6.07.20

* Upgraded to Python 3.9.7
* Upgraded to OpenSSL 1.1.1l

6.07.19

Fixed bug in `gam print chromepolicies` that caused the following error:
```
Chrome Policy: chrome.devices.*, Print Failed: Invalid page token, request parameters do not match page token.
```

6.07.18

Updated `gam create|update course copyfrom <CourseID> ... markpublishedasdraft` to mark
published course materials as draft as well as course work; this matches the console
copy course behavior.

Updated more course related commands to handle the following error.
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.07.17

Following Jay's suggestion, added option `maxresults <Number>` to `gam print|show resoldsubscriptions`;
the default value is 100 and the range is 1-100.

6.07.16

Updated `gam <UserTypeEntity> claim|transfer ownership <DriveFileEntity>` to handle the following error:
```
ERROR: 403: insufficientFilePermissions - The user does not have sufficient permissions for this file.
```

6.07.15

Updated `gam <UserTypeEntity> copy drivefile <DriveFileEntity>` to allow more attributes
to be specified on the copy. These only apply when a single file/folder is being copied.
```
<DriveFileCopyAttribute> ::=
        (contentrestrictions readonly false)|
        (contentrestrictions readonly true [reason <String>])|
        (copyrequireswriterpermission [<Boolean>])|
        (description <String>)|
        ignoredefaultvisibility|
        (keeprevisionforever|pinned)|
        (lastviewedbyme <Time>)|
        (modifieddate|modifiedtime <Time>)|
        (mimetype <MimeType>)|
        (ocrlanguage <Language>)|
        (privateproperty <PropertyKey> <PropertyValue>)|
        (publicproperty <PropertyKey> <PropertyValue>)|
        (property <PropertyKey> <PropertyValue> [private|public])|
        (viewerscancopycontent [<Boolean>])|
        (writerscanshare|writerscantshare [<Boolean>])
```

6.07.14

Following Jay's suggestions, updated `gam download vaultexport <ExportItem> matter <MatterItem> targetname <FileName>`
to avaid data loss when `<FileName>` does not contain `#filename#` and there are multiple top level files with the same extension.
The files will be named `FileName-N.ext` where `N` is `1,2,3,...`.

6.07.13

Fixed `gam <UserTypeEntity> print filelist ... formatjson nodataheaders <String>` to
output only `<String>` when there is no data.

6.07.12

Updated various course related commands to handle the following error.
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.07.11

Fixed bug in `gam <UserTypeEntity> modify messages|threads removelabel <LabelName>` where `<LabelName>`
was being created inappropriately.

6.07.10

Due to missing API documentation, `gam <UserTypeEntity> print|show datastudioassets orderby title ascending|descending`'
displayed in the opposite of the specified order.

Fixed bug that caused a trap in `gam print|show chromeschemas std`.

6.07.09

Following Jay's suggestion, added `all` to `assettype` in all `datastudioassets`
and `datastudiopermissions` commands so you can get information on both `reports`
and `datasources` in a single command.

6.07.08

Fixed bug that caused a trap in `gam <UserTypeEntity> transfer calendars <UserItem> <UserCalendarEntity> append description|location|summary`.

6.07.07

Added option `alias|aliases <EmailAddressList>` to `gam create user` that causes GAM
to create the user aliases in `<EmailAddressList>` after creation of the user. The
same option was added to `gam update user createifnotfound` and applies when a user is
not found and must be created.

6.07.06

Handle the following error in `gam create|update drivefileacl`:
```
ERROR: 400: publishOutNotPermitted - Bad Request. User message: "publishOutNotPermitted"
```

6.07.05

Updated `gam print|show datatransfers status completed|failed|inprogress`;
previously, `pending` was allowed but it generates an error.

6.07.04

Updated `gam copy drivefile` to avoid the following error when copying a shortcut to a folder.
```
ERROR: 403: fieldNotWritable - The resource body includes fields which are not directly writable.
```

6.07.03

Fixed bug in `gam show ownership` that always showed file name as blank.

6.07.02

Updated various Google libraries and httplib2.

6.07.01

Updated `gam print|show admins` to allow specification of both `user <UserItem>`
and `role <RoleItem>` and then avoid the undocumented API rule that disallows both.

6.07.00

Added the following keywords to `gam.cfg` to provide logging of GAM commands.
```
cmdlog
        Path to GAM Log file
        Default: ''
cmdlog_max_backups
        Maximum number of backup log files
        Default: 5
        Range: 1 - 10
cmdlog_max_kilo_bytes
        Maximum kilobytes per log file
        Default: 1000
        Range: 100 - 10000
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Command-Logging-Progress#command-logging

Added the following keyword to `gam.cfg` to display commands to stderr when executing `gam batch|tbatch|csv|loop`.
```
show_commands
        Display commands to stderr when executing `gam batch|tbatch|csv|loop`.
        Default: False
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Command-Logging-Progress#command-progress

6.06.15

Updated option`showcmds` output in `gam batch|csv|tbatch` to show the total number of commands
to be executed in addition to the current command number.

Added option `showcmds [<Boolean>]` option to `gam loop`; this causes GAM to display each command to stderr
as it is initiated so you can monitor GAM's progress. If `<Boolean>` is omitted, True is assumed.
When `showcmds` is not specified or False, the input file is processed line-by-line. When `showcmds` is True,
the input file is pre-processed so the total number of commands is known.

6.06.14

The following options have been deprecated in `gam <UserTypeEntity> copy drivefile <DriveFileEntity>`
as Google no longer supports multiple parents on files; using them will cause an error so as to alert
you to review the command.

No existing parents are copied for source top/sub files/folders.
```
These options control the action GAM takes when a source top file/folder has multiple parents.
* `copytopfileparents all` - Copy all of the existing parents.
* `copytopfolderparents all` - Copy all of the existing parents.

These options control the action GAM takes when a source sub file/folder has multiple parents.
* `copysubfileparents nonpath` - Copy all of the existing parents except the parent on the path from the top folder; this is the default action.
* `copysubfileparents all` - Copy all of the existing parents.
* `copysubfolderparents nonpath` - Copy all of the existing parents except the parent on the path from the top folder; this is the default action.
* `copysubfolderparents all` - Copy all of the existing parents.
```

6.06.13

Fixed bug in `gam info user <UserItem> quick` that generated the following error:
```
Cloud Identity Group: groups/-, Lookup Failed: Error(4016): Insufficient permissions to retrieve membership graph.
```

Added option `domainlist|notdomainlist <DomainNameList>` to `<PermissionMatch>`
to make it easier to specify a list of domains.

Added option `notrole <DriveFileACLRole>` to `<PermissionMatch>`
to make it possible to match any role other that the specified role.

6.06.12

Fixed bug in `gam report <ActivityApplicationName>` where only the last subevent
of an event was shown rather than all subevents.

6.06.11

Following Jay's lead, improved error messages when invalid client_secrets.json, oauth2service.json
and oauth2.txt files are encountered.

6.06.10

Code cleanup for internal routines cleanJSON, flattenJSON, showJSON.

6.06.09

Fixed more issues caused by update to Cloud Resource Manager API v3.

6.06.08

Fixed bug in `gam update project` that caused a trap.

6.06.07

Defined `<ProjectIDEntity>` to allow selection of project IDs from a flat or CSV file in addition
to the current options.
```
<ProjectIDList> ::= "<ProjectID>(,<ProjectID>)*"
<ProjectIDEntity> ::=
        current | gam | <ProjectID> | (filter <String>) |
        (select <ProjectIDList> | <FileSelector> | <CSVFileSelector>)
gam update project [[admin] <EmailAddress>] [<ProjectIDEntity>]
gam delete project [[admin] <EmailAddress>] [<ProjectIDEntity>]
gam show projects [[admin] <EmailAddress>] [all|<ProjectIDEntity>]
        [states all|active|deleterequested] [showiampolicies 0|1|3]
gam print projects [[admin] <EmailAddress>] [all|<ProjectIDEntity>] [todrive <ToDriveAttribute>*]
        [states all|active|deleterequested] [showiampolicies 0|1|3 [onememberperrow]]
        [delimiter <Character>]] [[formatjson [quotechar <Character>]]

gam create|add svcacct [[admin] <EmailAddress>] [<ProjectIDEntity>]
        [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>]
        [sadescription <ServiceAccountDescription>]
gam delete svcacct [[admin] <EmailAddress>] [<ProjectIDEntity>]
        (saemail <ServiceAccountEmail>)|(saname <ServiceAccountName>)|(sauniqueid <ServiceAccountUniqueID>)
gam show svcaccts [[admin] <EmailAddress>] [all|<ProjectIDEntity>]
        [showsakeys all|system|user]
gam print svcaccts [[admin] <EmailAddress>] [all|<ProjectIDEntity>]
        [showsakeys all|system|user]
        [todrive <ToDriveAttribute>*]
        [formatjson [quotechar <Character>]]
```

6.06.06

Fixed issues caused by update to Cloud Resource Manager API v3.

Following Jay's lead, added command to create a Google Cloud Platform folder.
This folder can be used in a subsequent `gam create project` command.
```
gam create gcpfolder <String>
gam create gcpfolder [admin <EmailAddress] folder <String>
```

6.06.05

Updated `gam print|show|update chromepolicy` to handle the following special case policies:
```
chrome.users.AutoUpdateCheckPeriodNew autoupdatecheckperiodminutesnew
chrome.users.BrowserSwitcherDelayDuration browserswitcherdelayduration
chrome.users.FetchKeepaliveDurationSecondsOnShutdown fetchkeepalivedurationsecondsonshutdown
chrome.users.MaxInvalidationFetchDelay maxinvalidationfetchdelay
chrome.users.PrintingMaxSheetsAllowed printingmaxsheetsallowednullable
chrome.users.PrintJobHistoryExpirationPeriodNew printjobhistoryexpirationperioddaysnew
chrome.users.SecurityTokenSessionSettings securitytokensessionnotificationseconds
chrome.users.SessionLength sessiondurationlimit
chrome.users.UpdatesSuppressed updatessuppresseddurationmin
chrome.users.UpdatesSuppressed updatessuppressedstarttime
```

6.06.04

Fixed bug in `gam print|show chromepolicies` that caused a trap.

6.06.03

Fixed `gam print|show chromepolicies` to display `targetKey.additionalTargetKey` fields.

Updated `gam info|show|print note` to display `owner` and `ownedByMe` fields.

Following Jay's lead, updated to Cloud Resource Manager API v3.

6.06.02

Improved Google Keep notes commands.

6.06.01

Code cleanup for Google Keep notes commands.

6.06.00

Added commands to manage and display Google Keep notes.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Keep

6.04.25

Updated random password processing in `gam create|update user`.

As in prior versions of Advanced GAM, if you create a user and don't specify a password
or specify `password random`, a password of length 25 comprised of letters, numbers and special characters is created.
This does not match Standard GAM; it generates an unusable login password.
You can specify the length of the random password with `password random <Integer>`,
`<Integer>` must be between 8 and 100; this is not available in Standard GAM.

If you specify `password blocklogin`, a password of length 4096 comprised of random Unicode
characters is created; it's purpose is to create a password that blocks logins. This
matches the `password random` option of Standard GAM.

6.04.24

Handle the following error in `gam <UserTypeEntity> copy drivefile <DriveFileEntity>`:
```
ERROR: 400: invalidLinkVisibility - Bad Request. User message: ""
```

6.04.23

Following Jay's lead, improved `gam <UserTypeEntity> waitformailbox [retries <Number>]`.

6.04.22

Added additional code to handle the following error in `gam print group-members`.
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

6.04.21

Fixed bugs in `gam <UserTypeEntity> print|show messages|threads sendermatchpattern <RegularExpression> countsonly`.

6.04.20

Added option `sendermatchpattern <RegularExpression>` to `gam <UserTypeEntity> print|show messages|threads`
that causes GAM to display messages and threads only if the sender matches the `<RegularExpression>`.
This is used to display messages sent by a paticular delegate for a delegator; the message is
from the delegator but sent by the delegate.

See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Messages-Threads#display-messages-sent-by-delegates-for-delegator

6.04.19

Updated processing of `query <QueryGmail>` that contains `(after|before|newer|older):YYYY/MM/DD`
so that GAM results match Gmail results. `YYYY/MM/DD` is interpreted as midnight on the given
date but GAM has to adjust the time to be consistent with `gam.cfg timezone`.

6.04.18

Handle the following error in `gam <UserTypeEntity> print filelist select teamdriveid <SharedDriveID>`
when `<SharedDriveID>` is not valid.
```
ERROR: 404: fileNotFound - Does not exist
```

6.04.17

* Upgraded to Python 3.9.6
* Upgraded to Google API Python Client 2.10.0
* Upgraded to Google Auth 1.32.0

Added option `groupidfilter <String>` to `gam report <ActivityApplictionName>`.

From the API documentation: https://developers.google.com/admin-sdk/reports/reference/rest/v1/activities/list
```
Comma separated group ids (obfuscated) on which user activities are filtered,
i.e, the response will contain activities for only those users that are a
part of at least one of the group ids mentioned here. Format: "id:abc123,id:xyz456"
```
Is `obfuscated` explained? No. Does the option work in my testing? No.
Updates when I figure out what's going on.

6.04.16

Added fields `resourcekey  and `linksharemetadata` to `<DriveFieldName>`.

Added option `securityupdate <Boolean>` to `<DriveFileAttribute>` that
sets `linkShareMetadata.securityUpdateEnabled` to `<Boolean>`.

6.04.15

Fixed bug in `gam <UserTypeEntity> sendemail newuser <EmailAddress> ...` that caused a trap.

6.04.14

Fixed bug in `gam <UserTypeEntity> print filelist filetree|filepath ..." where all
files were not displayed.
* `showownedby` not specified - Files owned by the user in `Shared with me` were not displayed
* `showownedby me` - Files owned by the user in `Shared with me` were not displayed
* `showownedby others` - Files not owned by the user that are orphans were not displayed

6.04.13

Added option `clearfilter` to `gam <UserTypeEntity> update drivefile <DriveFileEntity> csvsheet <SheetEntity>`
that causes GAM to clear the spreadsheet basic filter when uploading data to the existing sheet so hidden data will be overwritten.

6.04.12

Added option `addsheet <String>` to `gam <UserTypeEntity> update drivefile <DriveFileEntity>`
that allows creating a new sheet within a Google spreadsheet with data from `localfile <FileName>`.
Remember, when updating a file with `addsheet|csvsheet` and `localfile <FileName>`, you may want to
use the `retainname` option so that the spreadsheet file is not renamed to `<FileName>`.

6.04.11

Updated Contacts API calls to handle the following error generated by Google as a reminder
to switch to the People API.
```
Contacts API is being deprecated. Migrate to People API to retain programmatic access to Google Contacts.
See: https://developers.google.com/people/contacts-api-migration.
```

6.04.10

Fixed bug in `gam print resources formatjson` that caused a trap.

Added ability to display output in JSON format to `gam info|print|show buildings`.

Added command to display empty drive folders on My Drive or a selected Shared Drive.
```
gam <UserTypeEntity> print emptydrivefolders [todrive <ToDriveAttribute>*]
        [select <SharedDriveEntity>]
```

6.04.09

Handle the following error generated by `gam report ... fields xxx`.
```
ERROR: 400: invalidInput - Invalid value 'xxx'. Values must match the following regular expression: '(((accounts)|(classroom)|(cros)|(gmail)|(calendar)|(docs)|(gplus)|(sites)|(device_management)|(drive)):[^,]+,)*(((accounts)|(classroom)|(cros)|(gmail)|(calendar)|(docs)|(gplus)|(sites)|(device_management)|(drive)):[^,]+)'
```

6.04.08

Updated processing of `<DriveFileURL>` as Google introduced this new form
of a folder URL that GAM didn't recognize and thus couldn't isolate `<DriveFileID>`.
```
https://drive.google.com/drive/folders/<DriveFileID>?resourcekey=<String>
```

6.04.07

Changed `config csv_input_row_filter|csv_output_row_filter` processing of blank fields
for `count<Operator><Number>` and `boolean:<Boolean>`. Previously, a blank field was
always treated a mismatch; now a blank field will be interpreted as `False` for `<Boolean>`
and `0` for `<Number>` and the match test will be performed.

Added options `primary` and `default` to the following commands
so that only the primary or default sendas is displayed
for each user in `<UserTypeEntity>` rather than all sendas.
```
gam <UserTypeEntity> show sendas [compact|format|html]
        [primary] [default] [verifyonly]
gam <UserTypeEntity> print sendas [compact]
        [primary] [default] [verifyonly] [todrive <ToDriveAttribute>*]
```

Added options `primary` and `default` to the following commands
so that the primary or default signature is displayed
for each user in `<UserTypeEntity>` rather than the current signature.
```
gam <UserTypeEntity> show signature [compact|format|html]
        [primary] [default] [verifyonly]
gam <UserTypeEntity> print signature [compact]
        [primary] [default] [verifyonly] [todrive <ToDriveAttribute>*]
```

Added option `verifyonly` to the commands shown above; it causes a Boolean
to be displayed in the `signature` field rather that the signature text;
this simplifies checking for users with undefined signatures.

For example, this command will display a list of users without a primary email address signature (wrapped for readability):
```
gam config csv_output_row_filter "signature:boolean:false" csv_output_header_filter "User,displayName,signature"
    auto_batch_min 1 num_threads 10 redirect csv ./NoPrimarySignature.csv multiprocess
    all users print signature primary verifyonly

Explanation:
config csv_output_row_filter "signature:boolean:false" - Output rows that indicate no signature
csv_output_header_filter "User,displayName,signature" - Output basic headers
auto_batch_min 1 num_threads 10 - Turn on parallel processing
redirect csv ./NoPrimarySignature.csv multiprocess - Intelligently combine output from all processes
all users - Process all non-suspended users
print signature primary verifyonly - Display state of primary email address signature
```

6.04.06

Eliminated `ios` from `<DeviceType> ::= android|chrome_os|google_sync|linux|mac_os|windows`
as company owned IOS devices can not be created with `gam create device`.

6.04.05

Fixed bug in `gam <UserTypeEntity> get drivefile` where extensions were inappropriately applied
to files that Google reported as having no extension.

6.04.04

Fixed bug in `gam <UserTypeEntity> move drivefile ... duplicatefiles uniquename` that caused
a trap when the source file name contained a '(' with no following ')' or contained a '['.

Updated `gam <UserTypeEntity> move drivefile ... duplicatefiles uniquename` to not treat the
rightmost '.' followed by more than five characters as an extension.
* `foo.abcde` will be renamed to `foo(1).abcde` when moved into a folder containing `foo.abcde`
* `foo.abcdef` will be renamed to `foo.abcdef(1)` when moved into a folder containing `foo.abcdef`

6.04.03

Fixed bug in `gam report` where event names were not put in upper case for:
`chrome`, `contextawareaccess`, `datastudio` and `jamboard`.

6.04.02

Added `chrome`, `contextawareaccess` and `datastudio` to `<ActivityApplicationName>` so you can do `gam report xxx`.

6.04.01

Added `keep` to `<ActivityApplicationName>` so you can do `gam report keep`.

Handle the following error when trying to share a folder on a Team Drive to a domain.
```
ERROR: 400: invalidLinkVisibility - Bad Request. User message: ""
```

6.04.00

Following Jay's lead, added chat bot commands.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Chat-Bot

6.03.34

Updated `gam copy drivefile` to handle the following error:
```
ERROR: internalError - Internal Error
```

6.03.33

Added option `stripnameprefix <String>` to `gam create|copy|update drivefile` to aid in the following situation.
You have a CSV file listing some files owned by an external user; your ultimate goal is to move them to a Shared Drive.
This is not possible so you decide to make locally owned copies, backup the externally owned originals and then rename
the copies to have the original name and then move those copies to thw Shared Drive.
```
# Make copies of the externally owned files
gam csv ./ExtFiles.csv gam user user@domain.com copy drivefile "~id"
# You now have `FileName` and 'Copy of Filename`; move the originals to a backup folder
gam csv ./ExtFiles.csv gam user user@domain.com update drivefile "~id" parentid <BackupParentFolderID>
# Generate a list of the "Copy of " copied files
gam redirect csv ./CopyOfFiles.csv user user@domain.com print filelist fields id,name query "name contains 'Copy of '"
# Rename the files stripping off the "Copy of " prefix
gam csv ./CopyOfFiles.csv gam user user@domain.com update drivefile "~id" newfilename "~name" stripnameprefix "Copy of "
```

6.03.32

Added option `notdomain <RegularExpression>` to `<PermissionMatch>` to make it easier to
select files owned by someone outside of your domain.
```
gam user user@domain.com print filelist showownedby others fields id,name,owners.emailaddress pm type user role owner notdomain domain.com em
```

6.03.31

Fixed a bug in `gam create|update user` where the required `area` field in `location`
could be omitted and no error message was given.

6.03.30

Added option `addtitle <String>` to `gam print|show drivefileacls` to provide more useful output
when reading file IDs from a CSV file. By default, just the file ID is displayed with the permissions;
the `showtitles` option adds the file name to the output at the expense of an additional API call.
If you have the file name in the CSV file, you can use the `addtitle` option to supply the file name.
For example, to get the ACLs for your Team Drives with the Team Drive name included in the output:
```
gam redirect csv ./TeamDrives.csv print teamdrives
gam redirect csv ./TeamDriveACLs.csv multiprocess csv ./TeamDrives.csv gam print drivefileacls teamdriveid "~id" addtitle "~name" fields id,domain,emailaddress,role,type,deleted
```

6.03.29

Added option `stripcrsfromname` to the following commands that causes carriage returns `\r`
to be stripped from drive file names. This option is special purpose and will not generally be used.
```
gam <UserTypeEntity> show fileinfo
gam <UserTypeEntity> print filelist
gam <UserTypeEntity> print|show filetree
gam <UserTypeEntity> print|Show filerevisions
```
How did a carriage return get added to a drive file name? Good question; the files seen so far are named `Icon\r`.

6.03.28

Fixed bug in `gam <UserTypeEntity> print filelist` where blank lines were being displayed after
the `Got n Drive File/Folder ...` messages.

6.03.27

Updated `gam print courses` to handle the following error.
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

Updated `gam <UserTypeEntity> move events <UserCalendarEntity> <EventEntity> to|destination <CalendarItem>`
to correct an incorrect error message from Google.
* Incorrect message: Move Failed: You need to have reader access to this calendar.
* Correct message: Move Failed: You need to have writer access to both calendars.

6.03.26

Updated the following commands to allow selection of archived users from a source group.
```
gam update group add|delete|update|sync
gam update cigroups add|delete|update|sync
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups-Membership
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups-Membership

Updated the following command to allow selection of archived users to be cleared.
```
gam update group clear
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups-Membership

Updated the following commands to allow selection of archived users for display.
```
gam info group
gam print groups
gam print group-members
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups

Added new option to `<UserTypeEntity>` that allows selection of group members based on their archived status.
```
group_users_select <GroupList>
       [members] [managers] [owners]
       [notsuspended|suspended] [notarchived|archived]
       [primarydomain] [domains <DomainNameList>] [recursive|includederivedmembership] end
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-Users#selected-users-from-groups

6.03.25

Updated `gam create project` to handle Google change that causes the following error:
```
ERROR: 403: Permission iam.serviceAccountKeys.create is required to perform this operation on service account
```

6.03.24

Added option `showdetails` to `gam <UserTypeEntity> create drivefile` that adds the
parent folder ID and MIME type to the output.

6.03.23

Updated `<BrowserFieldName>`:
* Added `deviceidentifiershistory`
* Removed `installedbrowserversion`

Updated `gam print browsers` to avoid token expiration and minimize memory usage.

6.03.22

Fixed bug in `gam <UserTypeEntity> update drivefile` where the options `retainname | (newfilename <DriveFileName>)`
were ignored if they appeared after option `localfile <FileName>`; the options can now appear in any order.

6.03.21

Updated the processing of `<UserTypeEntity>` to minimize memory usage when getting users directly in an OU.
```
ou|ou_ns|ou_susp <OrgUnitItem>
ous|ous_ns|ous_susp <OrgUnitList>
```

Updated `gam [<UserTypeEntity>] create|update teamdrive <Name> ... customtheme <DriveFileID> <Float> <Float> <Float>`
to better handle errors.

Updated `gam [<UserTypeEntity>] create teamdrive <Name>` to output the name of the newly created
Team Drive in addition to its ID.
```
$ gam user user@domain.com create teamdrive Test
User: user@domain.com, Shared Drive Name: Test, Shared Drive ID: 0ALHCDtCDTx_4Uk9XYZ, Created
```

6.03.20

Updated `gam <UserTypeEntity> print filelist select <DriveFileEntity>` to display progress
messages as it recurses through the folder tree.

Updated `gam <UserTypeEntity> print filelist select <DriveFileEntity> norecursion` to
retrieve the selected folder without retrieving its direct children which aren't going to be displayed.

6.03.19

Added option `showattachments [attachmentnamepattern <RegularExpression>]` to
`gam <UserTypeEntity> print messages|threads`. This adds the column `Attachments`
that shows the number of attachments and columns `Attachments.n.name` and `Attachments.n.mimeType`
that show the attachment names and MIME types.

6.03.18

Added commands to delete specific domain contacts and user's contacts using the People API.
```
gam delete domaincontacts <PeopleResourceNameEntity>
gam <UserTypeEntity> delete peoplecontacts <PeopleResourceNameEntity>
```
* https://github.com/taers232c/GAMADV-XTD3/wiki/People
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People

Updated various google libraries.

6.03.17

Corrected 6.03.16 code fix to avoid trap on Windows when doing the following:
```
gam config debug_level 1 redirect stdout foo.txt multiprocess ..
```
It fixed the trap but disabled the redirect.

6.03.16

Fixed code to avoid trap on Windows when doing the following:
```
gam config debug_level 1 redirect stdout foo.txt multiprocess ..
```

Updated code to handle the following error in `gam copy drivefile`:
```
ERROR: 400: badRequest - Bad Request
```

Updated code in `gam info resoldcustomer <CustomerID>` to avoid a trap when `<CustomerID>`
is not a resold customer ID.

Fixed bug in `gam <UserTypeEntity> print filelist ... formatjson` that caused a trap when no files were listed.

6.03.15

Fixed bug in `gam update cigroup` where `dynamic <QueryDynamicGroup>` was marked as invalid.

6.03.14

Added code to handle the following errors when adding an ACL on a Team Drive file.
```
ERROR: 403: cannotShareTeamDriveWithNonGoogleAccounts - Cannot share a shared drive with non Google accounts.
ERROR: 400: shareOutNotPermitted - Bad Request. User message: "This email address is linked to a personal Google Account. <Your domain> doesn't allow sharing with personal accounts."
```

6.03.13

Added option `show all|direct|inherited` to `gam print|show chromepolicies` which allows selection of
policies by whether the policy is set directly on the OU or is inherited from a parent OU; the default is `all`.
A Boolean field/column, `direct`, has been added to the output. This makes copying only direct policies from one OU to another easy.
```
# Display direct policies
gam redirect csv ChromePolicies.csv print chromepolicies ou "/Path/To/OU1" show direct
gam csv ChromePolicies.csv gam update chromepolicy "~name" "~fields.0.name" "~fields.0.value" "~fields.1.name" "~fields.1.value" ou "/Path/To/OU2"

# Display all policies, select direct on update
gam redirect csv ChromePolicies.csv print chromepolicies ou "/Path/To/OU1"
gam config csv_input_row_filter "direct:boolean:true" csv ChromePolicies.csv gam update chromepolicy "~name" "~fields.0.name" "~fields.0.value" "~fields.1.name" "~fields.1.value" ou "/Path/To/OU2"
```

6.03.12

Updated `gam update chromepolicy (<SchemaName> (<Field> <Value>)+)+` to allow empty
`<Field> <Value>` pairs. This makes copying a set of policies from one OU to another easy
without having to deal with policies with differing numbers of fields.
```
gam redirect csv ChromePolicies.csv print chromepolicies ou "/Path/To/OU1"
gam csv ChromePolicies.csv gam update chromepolicy "~name" "~fields.0.name" "~fields.0.value" "~fields.1.name" "~fields.1.value" ou "/Path/To/OU2"
```

Following Jay's lead, added option 'grouptree` to `gam info user` and `membertree` to `gam info cigroup`.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users#display-information-about-a-single-user
* https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups#display-information-about-individual-groups

6.03.11

Upgraded to Python 3.9.5.

Following Jay's lead, Google time is now checked against admin.googleapis.com rather than www.googleapis.com.

Updated code to convert the Shared Drive file field `trashedTime` from UTC according to `gam.cfg timezone`.

6.03.10

Fixed bug in `gam create course ... copyfrom <CourseID> ... copytopics ... copymaterialsfiles true materialstates "all"`
that generated the following error:
```
ERROR: 400: invalidArgument - Request contains an invalid argument.
```

6.03.09

Added command to print Chrome policies.
```
gam print chromepolicies [todrive <ToDriveAttribute>*]
        [filter <String>]
        ou|org|orgunit <OrgUnitItem> [(printerid <PrinterID>)|(appid <AppID>)]
        [[formatjson [quotechar <Character>]]
```

6.03.08

Added commands to display specific domain profiles and user's contacts using the People API.
```
gam info domainprofiles <PeopleResourceNameEntity>
        [allfields|(fields <PeopleFieldNameList>)]
        [formatjson]
gam <UserTypeEntity> info peoplecontacts <PeopleResourceNameEntity>
        [allfields|(fields <PeopleFieldNameList>)]
        [formatjson]
```
* https://github.com/taers232c/GAMADV-XTD3/wiki/People
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People

6.03.07

Updated code to properly set the values for the following Chrome Policy schema values:
* chrome.users.SessionLength - sessionDurationLimit
* chrome.users.BrowserSwitcherDelayDuration - browserSwitcherDelayDuration
* chrome.users.MaxInvalidationFetchDelay - maxInvalidationFetchDelay
* chrome.users.SecurityTokenSessionSettings - securityTokenSessionNotificationSeconds
* chrome.users.PrintingMaxSheetsAllowed - printingMaxSheetsAllowedNullable

6.03.06

Added enhanced commands for displaying Chrome Policy schemas.
```
gam info chromeschema <SchemaName>
        <ChromePolicySchemaFieldName>* [fields <ChromePolicySchemaFieldNameList>]
        [formatjson]
gam show chromeschemas
        [filter <String>]
        <ChromePolicySchemaFieldName>* [fields <ChromePolicySchemaFieldNameList>]
        [formatjson]
gam print chromschemas [todrive <ToDriveAttribute>*]
        [filter <String>]
        <ChromePolicySchemaFieldName>* [fields <ChromePolicySchemaFieldNameList>]
        [[formatjson [quotechar <Character>]]
```

6.03.05

Added commands to print Gmail imap/pop/language settings to CSV files.
```
gam <UserTypeEntity> print imap|imap4 [todrive <ToDriveAttribute>*]
gam <UserTypeEntity> print pop|pop3 [todrive <ToDriveAttribute>*]
gam <UserTypeEntity> print language [todrive <ToDriveAttribute>*]
```

6.03.04

Added commands to display user's other contacts using the People API.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People

To use this feature you must add the `People API` to your project and authorize the appropriate scopes:
* `People API - Other Contacts - read only`: https://www.googleapis.com/auth/contacts.other.readonly
```
gam update project
gam user user@domain.com check serviceaccount
```

Added commands to display user's contact groups using the People API.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People

6.03.03

Added commands to display user's contacts using the People API.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People

Simplified commands for displaying domain contacts/profiles with the People API.
* https://github.com/taers232c/GAMADV-XTD3/wiki/People

6.03.02

Changed the time window for `api_calls_rate_check` from 100 seconds to 60 seconds as Google
seems to be changing quota limits to be measured over 60 seconds.

6.03.01

Added option `showsource` to `gam <UserTypeEntity> print filelist countsonly` that adds an additional
column `Source` that indicates the top level folder ID from which the counts are derived.

6.03.00

As the Contacts API is being deprecated in June, additional support for the People API has been added.
This is the first step of many required to make the transition.
* https://github.com/taers232c/GAMADV-XTD3/wiki/People

The existing commands `get profilephoto`, `print|show peopleprofile` have been changed to use
Service Account Access to avoid having to make additional Directory API calls to convert the user email address to the people ID.

To use these features you must add the `People API` to your project and authorize the appropriate scopes:
* `Client Access` - `People Directory API - read only`.
* `Service Account Access`
  * `People Directory API - read only`: https://www.googleapis.com/auth/directory.readonly
  * `OAuth2 API`: https://www.googleapis.com/auth/userinfo.profile
```
gam update project
gam oauth create
gam user user@domain.com check serviceaccount
```

Following Jay's lead, added new license SKU `Cloud Search`.

6.02.04

Updated code to handle the following error:
```
ERROR: Authentication Token Error - Not all requested scopes were granted by the authorization server, missing scopes , https://sites.google.com/feeds, email, https://www.google.com/m8/feeds, profile.
```

6.02.03

Added optional argument `convertalias` to all commands that manipulate Gmail delegates.
If not specified, the extra API call introduced in 6.02.00 to convert potential delegate email aliases
to primary email addresses is not performed; if you specify an alias as a delegate, the command will fail.
If you know that all of the delegate email addresses are primary, you can omit `convertalias` and avoid the extra API calls.

6.02.02

Thanks to Jay's assistance in getting a Data Studio API discovery document,
updated the Data Studio permissions commands.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-DataStudio

6.02.01

Fixed bug in `gam <UserTypeEntity> add datastudiopermissions` that caused a trap.

6.02.00

Following Jay's lead, aliases are converted to primary email addresses when adding delegates.

Added commands to display Data Studio assets and display/manage Data Studio permissions.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-DataStudio

To use these commands you must add the `Data Studio API` to your project and update your service account authorization.
```
gam update project
gam user user@domain.com check serviceaccount
```
This is a first release from me, experiment and use with caution.

6.01.09

Added support for `localfile -` in `gam <UserTypeEntity> create|update drivefile` which allows
commands/programs to output data to stdout which can then be uploaded to a Google Drive file.
```
generatedata | gam user user@domain.com create drivefile drivefilename test.csv localfile - mimetype gsheet
```

6.01.08

Following Jay's lead, cleaned up field names in `gam print chromehistory`.

Following Jay's lead, added new license SKU `Google Workspace Frontline`.

6.01.07

Following Jay's lead, added additional columns to `gam print chromehistory`.

6.01.06

Updated `gam whatis <EmailItem>` to check if `<EmailItem>` is an unmanaged account
if it is not a group/user email address or alias.

Following Jay's lead, switched all commands referencing unmanaged accounts to use
Service Account access rather than Client access. This avoids the `Invalid Scope`
issue when doing `gam oauth create`. The `Cloud Identity User Invitations API` has
been dropped from `gam oauth create` for now.

6.01.05

Added the capability to display Chrome version history.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Version-History

Added the option `verifynotinvitable` to `gam create|update alias|group|user` that causes GAM to verify
that the email address being created/updated is not that of an unmanaged account; if it is, the
command is not performed.

To use this option you must add the `Cloud Identity API` to your project and authorize
the appropriate scope: `Cloud Identity User Invitations API`.

* Unmanaged Accounts - https://github.com/taers232c/GAMADV-XTD3/wiki/Unmanaged-Accounts

You'll have to do `gam update project` and `gam oauth create` to enable this option.

Updated google-api-python-client to version 2.1.0.

6.01.04

Fixed bug in `gam report usage customer` that caused a trap.

Upgraded to Python 3.9.4.

6.01.03

Upgraded to Python 3.9.3.

Upgraded to OpenSSL 1.1.1k.

6.01.02

Updated google_auth, google_auth_httplib2, google_auth_oauthlib, googleapiclient, httplib2 libraries.

6.01.01

Updated `gam print|show chromeversions` to avoid a trap where a version was returned without a `version` field.

6.01.00

Added the capability to access two new areas.

* Chrome Installed Apps Counts - https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Installed-Apps-Counts
* Chrome Versions Counts - https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Versions-Counts

You'll have to do `gam update project` and `gam oauth create` to enable these commands.

As with any initial release, report any problems.

Improved error reporting when trying to add/remove licenses with an administrator that is not authorized to do so.

6.00.08

Fixed bug in `gam print course-materials fields <CourseAnnouncementFieldNameList>` that caused the following error:
```
Course: <CourseID>, Print Failed: Request contains an invalid argument.
```

Code cleanup for `gam print course-work` and `gam print course-materials`.

6.00.07

Added option `splitupdate` to `gam <UserTypeEntity> update calattendees` to handle replacing
an email alias with its primary email in the event attendee list.
By default, when you try to replace an email alias with its primary email, the Google Calendar API
detects that the underlying user ID is the same and doesn't change the address. The `splitupdate`
option causes GAM to make two updates to the attendee list; the first removes the alias and
the second adds the primary email.

6.00.06

Added command `gam print addresses [todrive <ToDriveAttribute>*]` that produces a
two column CSV file (headers Type, Email) that displays all group and user primary
email addresses and aliases. The types are: Group, GroupAlias, GroupNEAlias,
SuspendedUser, User, UserAlias, UserNEAlias. 'NE' is and abbreviation for NonEditable.

6.00.05

Fixed bug in `gam print vaultcounts ... everyone` which caused the following error:
```
ERROR: getUsersToModify coding error
```

6.00.04

Updated `<CalendarAttribute>` to allow specifying a list of email notification event types.

Previously, you had to specify each email notification event type individually (this still works).
```
<CalendarEmailNotificatonEventType> ::=
        eventcreation|eventchange|eventcancellation|eventresponse|agenda
<CalendarEmailNotificatonEventTypeList> ::=
        <CalendarEmailNotificatonEventType>(,<CalendarEmailNotificatonEventType>)*

<CalendarAttribute> ::=
...
        (notification clear|(email <CalendarEmailNotificatonEventTypeList>))|

gam user user@domain.con update calendar primary notification email eventchange,eventcancellation
```

6.00.03

Fixed bug in `gam calendar update event` introduced in 5.34.02 where updating an event's start or end time appeared to work
but no change was actually made.

6.00.02

Added support for stand-alone course materials; these were not previously supported by the Google Classroom API.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Courses#display-course-materials
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Courses#create-and-update-courses

To use the course materials features you must authorize the appropriate scope: `'Classroom API - Course Work/Materials'`.
```
gam oauth create
gam user user@domain.com check|update serviceaccount
```

6.00.01

Improve error handling in `gam delete|update chromepolicy` and `gam show chromepolicies`.

When showing Chrome Policies, display OU and optional printerid/appid at top of output.

6.00.00

Following Jay's lead, added the capability to manage three new areas.

* Chrome Policies - https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Policies
* Chrome Printers - https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Printers
* Unmanaged Accounts - https://github.com/taers232c/GAMADV-XTD3/wiki/Unmanaged-Accounts

You'll have to do `gam update project` and `gam oauth create` to enable these commands.

As with any initial release, proceed with care and report any problems.

Updated `gam report customer|user` to continue processing subsequent dates when Google indicates that no data is available
for a particular date.

Improved `gam report` `Got` messages so it is easier to monitor progress.

Removed extraneous `email` header in `gam report user ... aggregatebydate`.

5.35.08

Fixed bug in `gam calendar <CalendarEntity> create|import|update event` where `noreminders` was not disabling reminders.

5.35.07

Fixed bug in all `gam browser|browsertoken` commands that displayed an error like this:
```
ERROR: 400: invalid - Invalid Customer ID: customers/xxx
```

5.35.06

Fixed bug in `gam <UserTypeEntity> create filter` that caused a trap.

5.35.05

Modified how `gam cros_ou_and_children <OrgUnitItem> ...` and `gam cros_ous_and_children <OrgUnitList> ...` are processed.
The Google Directory API does not support getting all CrOS devices in an OU and its sub OUs; previously, when these options
were used, GAM made a single API call to retrieve the entire list of CrOS devices and selected the desired devices.
For customers with a small number of CrOS devices this didn't cause an issue, for customers with large numbers of CrOS devices,
this could be slow. Now, GAM makes a separate API call for the OU and each of its sub OUs to retrieve the CrOS devices.

Expanded the options to select CrOS devices by OU in `gam print cros` and `gam print crosactivity`.
```
(limittoou|cros_ou|cros_org <OrgUnitItem>)|(cros_ou_and_children|cros_org_and_children <OrgUnitItem>)|
 (cros_ous|cros_orgs <OrgUnitList>)|(cros_ous_and_children|cros_orgs_and_children <OrgUnitList>)]
```
Using `gam print cros cros_ou /Students fields ...` will be much faster than `gam cros_ou /Students print cros fields ...`
as the second form makes one API call to retrieve the CrOS device IDs and then another API call per device to get the fields.
In the first form, GAM makes a single API call to retrieve the devices and their fields.

5.35.04

Fixed bug in `gam <UserTypeEntity> delete|update filerevisions <DriveFileEntity> select last 1`
where GAM incorrectly reported `No Drive File Revisions matched` if the file had only one revision.

5.35.03

Fixed bug in permission matching where `pm domain domain.com em` would match an ACL referencing a deleted user.

Updated google-api-python-client to version 2.0.2.

5.35.02

Fixed bug in `gam <UserTypeEntity> move events` where `destination` was not recognized as a synonym for `to`.

5.35.01

Fixed bug in `gam print users` that caused a trap when `limittoou <OrgUnitItem>` and `allfields`
were both specified.

Added option `pmselect` to `gam [<UserTypeEntity>] print|show drivefileacls` and
`gam [<UserTypeEntity>] print|show teamdriveacls` to allow selection of files/Shared Drives
matching the specified permissions without filtering the permissions themselves.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Shared-Drives#display-shared-drive-access
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Shared-Drives#display-shared-drive-access
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Permissions#display-file-permissionssharing

5.35.00

Reconfigured GAM source so that GAM can be imported/called from a Python script.
* A new subfolder `gam` was created under `src`; all source files were moved there
* `gam.py` was renamed to `__init__.py`, this is what allows you to `import gam`
* `__main__.py` was created in `gam`l; it is used by the GAM executable
* A new `gam.py` was created in `src` that allows calling gam as a single .py file

If you're not using the source code, this change should have no impact.

5.34.04

Code cleanup.

5.34.03

Code cleanup.

Allow empty `annotatedAssetId` for Chromebooks; the API previously didn't allow this.

Following Jay's lead, updated hashing of passwords passed to Google.

5.34.02

Fixed bug in `gam <UserTypeEntity> update calattendees ... csv <FileName>` that caused a trap.

5.34.01

Fixed bug introduced in 5.33.00 where `gam version checkrc` incorrectly set the return code to 1
even when you have the current version of GAM.

Added new Google Workspace for Education products and SKUs.

5.34.00

Eliminated all `gam audit` commands that used the Email Audit API; use `vault` commands as replacements.

The Mac OS version specific builds (gamadv-xtd3-5.xy.wz-macos-10.vv-x86_64.tar) have been eliminated;
the all version build (gamadv-xtd3-5.xy.wz-macos-x86_64.tar) is now the only Mac OS build.
You can download the new executable with (the -b allmacos option is no longer required):
```
bash <(curl -s -S -L https://git.io/fhZWP) -l
```

5.33.00

Eliminated automatic checking for a new GAM version, `no_update_check` in `gam.cfg` is now ignored.
Previously, when `no_update_check` was `false`, a file was opened and read on every execution of GAM.
You can check for a new version with `gam version check`.

A new GAM executable (gamadv-xtd3-5.xy.wz-macos-x86_64.tar) that should run on all versions of Mac OS from 10.10 on is now being built.
For now, the version specific executables will still be built. You can download the new executable with:
```
bash <(curl -s -S -L https://git.io/fhZWP) -l -b allmacos
```

5.31.28

Added option `oneuserperrow` to `gam print crosactivity recentusers` to make the output of the recent users
easier to process.

5.31.27

Upgraded to Python 3.9.2.

5.31.26

Upgraded to OpenSSL 1.1.1j.

5.31.25

Added option `showorgunit` to the following `gam report` commands that causes a column labelled
`orgUnitPath` to be added to the output. GAM makes an additional API call to get the email addresses
of the users in `<OrgUnitPath>`.
```
gam report usage user orgunit|org|ou <OrgUnitPath> showorgunit ...
gam report <ActivityApplicationName> orgunit|org|ou <OrgUnitPath> showorgunit ...
gam report user orgunit|org|ou <OrgUnitPath> showorgunit ...
```

5.31.24

Added `todrive_upload_nodata [<Boolean>]` to `gam.cfg` and `tduploadnodata [<Boolean>]` to `<ToDriveAttribute>`.

* When `True`, the default, CSV files with no data rows will be uploaded; this is the existing behavior.
* When `False`, CSV files with no data rows will be not be uploaded; the message `No CSV data to upload`
will be displayed and the return code will be set to 77.

5.31.23

Updated `gam showsections` to display section names in sorted order.

5.31.22

Updated `gam <UserTypeEntity> get document|drivefile <DriveFileEntity>` to add `*|~` to the list
of characters in Google Drive file names that are changed to `_`; the complete list is now `\/:*|~`.
This is to prevent local file system errors.

5.31.21

Added meta-command `showsections` that displays all of the sections in gam.cfg and marks the currently selected section with a *.
```
gam showsections
$ gam showsections
Config File: /Users/admin/GamConfig/gam.cfg
  DEFAULT
  Client1
  Client2
  Client3 *
  Client4
```

5.31.20

Added option `labelmatchpattern <RegularExpression>` to `gam <UserTypeEntity> print|show messages|threads`
that causes only messages with some label that matches `<RegularExpression>` to be displayed.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Messages-Threads#display-a-selected-set-of-messages

5.31.19

Updated code to handle the following error when moving calendar events:
```
ERROR: 400: invalid - Cannot have multiple conferences of type Hangout and NamedHangout.
```

5.31.18

Updated `gam info cros <CrOSEntity>` and `gam print cros` to avoid trap caused by change in API behavior.

5.31.17

Updated `gam <UserTypeEntity> create|add teamdrive <Name>` to handle the following error:
```
ERROR: 403: insufficientFilePermissions - The user does not have sufficient permissions for this file.
```

5.31.16

Deleted option `previewupdate` from `gam <UserTypeEntity> print|show filerevisions <DriveFileEntity>`
as it served no purpose.

5.31.15

Added command to manage publishing file revisions to the web.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Revisions#manage-file-revisions-publishing

5.31.14

Fixed bug in `gam <UserTypeEntity> print filters formatjson quotechar <Character>` that caused a trap.

5.31.13

Updated `gam update|delete|info resoldsubscription` to allow SKU abbreviations.

5.31.12

Fixed bug in `gam print licenses allskus|gsuite` that produced garbage output.

5.31.11

Updated code to handle the following error when getting lists of students/teachers from courses.
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

Fixed bug in `gam <UserTypeEntity> transfer drive <UserItem> select <DriveFileItem>` that caused files to be orphaned.

Added option `mergewithtarget` to `gam <UserTypeEntity> transfer drive <UserItem> select <DriveFileItem>`
to allow transferring a folder without creating a new folder in the target user folder.
The contents of the folder, but not the folder itself, are transferred to the new owner.
```
gam user oldowner@domain.com transfer drive newowner@domain.com select name "Old Owner Folder" targetfoldername "New Owner Folder" targetuserfoldername "" mergewithtarget true
```

5.31.10

Updated code to avoid a trap when an input CSV file is not encoded in UTF-8.
You'll still get an error but not a trap.
```
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf3 in position 893: invalid continuation byte
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
```

Updated `gam print cigroups` to suppress this message,
```
Got n Cloud Identity Groups: %%first_item%% - %%last_item%%
```

5.31.09

Updated `create project` and `check|update serviceaccount` URLs to include administrator email address.

5.31.08

Enhanced `gam update course <CourseID> teacher <UserItem>` to handle special situations better.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Courses#updating-course-owner

5.31.07

Updated `gam <UserTypeEntity> print users` to handle the following error:
```
ERROR: 403: rateLimitExceeded - Quota exceeded for quota group 'default' and limit 'Queries per user per 100 seconds'
of service 'admin.googleapis.com' for consumer 'project_number:Project#Here'.
```

5.31.06

Updated `gam <UserTypeEntity> print|create filter` to make it easier to copy filters from
one user to another.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Filters

5.31.05

Improved error message generated when trying to move a calendar event to a calender without write access.

Updated all commands/options that reference License Products and SKUs to validate the values entered.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Licenses#definitions

Updated `gam create course copyfrom <CourseID>` and `gam update course <CourseID> copyfrom <CourseID>`
to remove Course Work due dates that fall before the current time; if not removed, the Course Work
can not be copied.
* `removeduedate false` - Remove due dates before the current time; this is the default
* `removeduedate|removeduedate true` - Remove all due dates

Fixed bug in `gam print courses` that caused a trap when there were no courses to print due to filtering.

5.31.04

Added a command to download a Google Document in JSON format.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Manage#download-google-documents-as-json

You'll have to do `gam update project` and `gam <UserTypeEntity> check|update serviceaccount` to enable this command.

5.31.03

Fixed bug in `gam <UserTypeEntity> move drivefile <DriveFileEntity>` that caused a trap when
an `invalidSharingRequest` error was reported by the Drive API.

Updated `gam <UserTypeEntity> transfer drive` to not try changing parents of `Shared with me` files/folders
that do not have parents in My Drive.

5.31.02

Added initial support for Chrome Browser Enrollment Token API.

* See: https://support.google.com/chrome/a/answer/9949706
This is Beta software from Google and a first release from me, experiment and use with caution.

Updated `gam <UserTypeEntity> draft|import|insert message` to disallow `content-type` header that caused a trap.
Ths value of this header is derived from other arguments and can not be explicitly set.

5.31.01

When creating an `alias`, `group` or `user`, additional informations is given when the item is a duplicate.
```
$ gam create alias techassistant user user2@domain.com
User Alias: techassistant@domain.com, User: user2@domain.com, Create Failed: Duplicate, User Alias: techassistant@domain.com, User: user1@domain.com

$ gam create group technology@domain.com
Group: technology@domain.com, Create Failed: Duplicate, Group: technology@domain.com
$ gam create group appletech@domain.com
Group: appletech@domain.com, Create Failed: Duplicate, Group Alias: appletech@domain.com, Group: technology@domain.com

$ gam create user user1@domain.com
User: user1@domain.com, Create Failed: Duplicate, User: user1@domain.com
$ gam create user techassistant@domain.com
User: techassistant@domain.com, Create Failed: Duplicate, User Alias: techassistant@domain.com, User: user1@domain.com
$ gam create user appletech@domain.com
User: appletech@domain.com, Create Failed: Duplicate, Group Alias: appletech@domain.com, Group: technology@domain.com
```

5.31.00

Removed all Cloud Print related commands,

Extended support for Cloud Identity Groups.
This is Beta software from Google and a first release from me, experiment and use with caution.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups-Memberships

5.25.20

Changed processing of `<FieldNameFilter>` when performing column row filtering to simplify specifying
field names that should match a field but none of its subfields.
If `<FieldNameFilter>` doesn't contain any of the following regular expression characters `^$*+|$[{(`,
it will be surrounded with `^$` so that it doesn't match any subfields that begin with `<FieldNameFilter>` as a prefix.
In previous versions, you had to surround `<FieldNameFilter>` with `^$` to get this behavior.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Input-Filtering#column-row-filtering
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Output-Filtering#column-row-filtering

5.25.19

Fixed bug introduced in 5.25.18  where using `todrive_noemail false` or `tdnoemail false` caused a trap.

5.25.18

The Google message id was added to the output from `gam sendemail`.
This allows you to easily get details about the message sent, e.g, the SMTP Message-ID.

Added options `(<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)*`
to `gam sendemail` that allows adding user specified headers to the message being sent.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Send-Email

5.25.17

Currently, when doing CSV row filter matching, lf you specify a regular expression for a field name that matches
several columns, the filter matches if any of the columns has a match. In the case of `notregex|notregexcs`,
the filter matches if none (not any) of the columns has a match.

This has been extended to allow specifying that the filter will match only if all of the columns have a match.
In the case of `notregex|notregexcs`, the filter matches if some (not all) of the columns have a match.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Input-Filtering
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Ouput-Filtering

5.25.16

Fixed bug in `gam <UserTypeEntity> print messages showlabels countsonly` that caused a trap.

5.25.15

Updated commands that create and update schemas to convert spaces to `_` in schema
and field names as spaces are not valid. The schema and field display names will
retain the spaces. Added options to allow specification of the schema/field display name
as independent of the schema/field name.
```
<SchemaFieldDefinition> ::=
        field <FieldName> [displayname <String>]
            (type bool|date|double|email|int64|phone|string)
            [multivalued|multivalue] [indexed] [restricted]
            [range <Number> <Number>]
        endfield

gam create|add schema|schemas <SchemaName> [displayname <String>] <SchemaFieldDefinition>+
gam update schema <SchemaName> [displayname <String>] <SchemaFieldDefinition>* (deletefield <FieldName>)*
gam update schemas <SchemaEntity> [displayname <String>] <SchemaFieldDefinition>* (deletefield <FieldName>)*
```

Updated `gam <UserTypeEntity> move drivefile <DriveFileEntity>` to move a folder
from a Shared Drive to My Drive by updating the parent rather than creating a new folder.

Upgraded to Python 3.9.1.

5.25.14

Following Jay's lead, added commands to support Contact Delegation,

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Contacts-Delegates.

You must perform `gam oauth create` and select this API to use these commands.
* Contact Delegation API (supports readonly)

This is Beta software from Google, experiment and use with caution.

Following Jay's lead, added commands to support Chrome Browser Cloud Management

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Chrome-Browser-Cloud-Management

You must perform `gam oauth create` and select this API to use these commands.
* Chrome Browser Cloud Management API (supports readonly)

This is Beta software from Google, experiment and use with caution.

5.25.13

Following Jay's lead, added commands to display and update Cloud Identity Device User Client States.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices#display-device-user-client-state

This is Beta software from Google, experiment and use with caution.

Following Jay's lead, added a command to display item counts retained in Google Vault.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault#display-vault-counts

Updated `gam <UserTypeEntity> create drivefileshortcut <DriveFileEntity>` to not create duplicate shortcuts.
A duplicate shortcut is one that is in the same folder as another shortcut of the same name pointing to the
same target file/folder.

5.25.12

Added more error handling for `gam <UserTypeEntity> process messages|threads`.

5.25.11

Google does not support `/` in group email addresses but doesn't give an error if you assign an address that contains a `/`.
The Directory API will accept such an address but the Group Settings API won't; this update maps `/` to `%2F`
so the Group Settings will accept the address.

5.25.10

Extended 5.25.09 to handle additional errors in `gam <UserTypeEntity> process messages|threads`.

5.25.09

In `gam <UserTypeEntity> delete messages|threads`, handle the following error:
```
ERROR: 400: failedPrecondition - Precondition check failed.
```

5.25.08

When getting group settings, handle the following error:
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

Added `tdsheetdaysoffset <Number>` and `tdsheethoursoffset <Number>` to `<ToDriveAttribute>`.
These allow setting timestamp offset information on a sheet (tab) that is different than the timestamp
information on the Google spreadsheet file.

5.25.07

Perform retries when Google returns an error instead of Google Sheet data when using `gsheet <UserGoogleSheet>`.
This seems to happen when you quickly execute a series of GAM commands that access the same Google Sheet to retrieve
data for each command.

When creating/copying files/folders, handle the following error:
```
ERROR: 403: teamDriveHierarchyTooDeep - The shared drive hierarchy depth will exceed the limit.
```

5.25.06

Added option `scope|scopes <APIScopeURLList>` to `gam <UserTypeEntity> update serviceaccount` to allow
specification of the desired scopes on the command line. Entering `<APIScopeURLList>` by hand would be tedious at best
but could be used in a script.

5.25.05

Added options `thismonth` and `previousmonths <Integer>` to `gam report`
to provide calendar oriented date/time ranges.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Reports

5.25.04

Updated `gam <UserTypeEntity> check|update serviceaccount` to avoid `ERROR: No Service Account Access allowed`
when getting Service Account key age and `Identity and Access Management API` is not enabled.

5.25.03

Updated `gam <UserTypeEntity> check|update serviceaccount` to add `&dn=<DomainName>` to the end
of the end of the authorization URL. This will be most useful to Google Resellers managing multiple accounts.

5.25.02

Updated `gam <UserTypeEntity> create drivefileacl` to handle the following error:
```
ERROR: 400: shareOutNotPermittedToUser - Bad Request.
```

5.25.01

Updated code in `gam report admin` to handle event parameters with no value; this is what caused the
trap fixed in 5.25.00. This update formats those parameters in the same manner as other parameters.

5.25.00

Added `csv_input_row_filter` and `csv_input_row_drop_filter` to `gam.cfg` to allow CSV row filtering of input
CSV Files.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Input-Filtering#column-row-filtering

Updated code in `gam report admin` to avoid a trap caused by a change the Report API.

5.24.14

Fixed error that didn't allow blank `tdsheet`.

5.24.13

Added option `countsonly` to `gam <UserTypeEntity> print|show groups` that causes GAM to display
the number of groups, by role, to which a user belongs rather than listing the group details.

Updated `todrive` to improve formatting of blank `tdtitle` and `tdsheet` when using `tdtimestamp true` and
`tdsheettimestamp true`. Previously, a ` - ` followed by the timestamp was appended to the title
resulting in something like this: ` - 2020-11-18T12.34.56Z`; now, the ` - ` is omitted.

Upgraded to Python 3.9.0.

5.24.12

Updated `gam <UserTypeEntity> show messages|threads saveattachments` to convert the characters `/` and `:`
to `_` in attachment names so that they can be saved.

5.24.11

Updated `gam <CrOSTypeEntity> getcommand commandid <CommandID>` to handle the following error:
```
ERROR: 404: notFound - Requested entity was not found.
```

5.24.10

Fixed bug in `gam <UserTypeEntity> copy drivefile <DriveFileEntity>` that caused a trap.

5.24.09

Fixed `gam print courses show all|students|teachers` to eliminate duplicated columns.

5.24.08

Removed restrictions in `gam <UserTypeEntity> copy|move drivefile <DriveFileEntity>` that prevented
adding ACLs to folders on Shared Drives as it was not allowed; Google now allows this.

5.24.07

Added an additional line of output to `gam version` that displays some basic configuration data.
```
Config File: /Users/Admin/.gam/gam.cfg, Section: DEFAULT, customer_id: C01234567, domain: domain.com
```

5.24.06

Corrected 5.24.05 update to properly handle an unexpected `HttpError 500` that caused a trap.

5.24.05

Updated `gam <UserTypeEntity> transfer drive` to handle an unexpected `HttpError 500` that caused a trap.

5.24.04

Updated `gam <UserTypeEntity> print|show forward` to handle the following error:
```
ERROR: 400: failedPrecondition - Precondition check failed.
```

5.24.03

Fixed bug in `gam <UserTypeEntity> print filecounts showmimetype <MimeTypeList>` that caused a trap.

5.24.02

Updated `gam calendar <CalendarEntity> move events` and `gam <UserTypeEntity> move events <UserCalendarEntity>`
to handle the following error:
```
ERROR: 403 requiredAccessLevel - You need to have writer access to this calendar.
```

5.24.01

Fixed bug introduced in 5.23.06 where `todrive tdfileid <FileID> tdaddsheet tdsheet "Sheet Title"`
caused the error:
```
ERROR: Drive File ID: <FileID>, Sheet: "Sheet Title", Not Found
```

Added code to verify that `todrive tdfileid <FileID> tdaddsheet tdsheet "Sheet Title"` does not reference
an existing sheet.

5.24.00

Added a new environment variable `GAMCFGSECTION` that selects a `[Section]` within `gam.cfg`.
This allows multiple users with distinct logins on the same computer to share `gam.cfg` but each
reference a unique `[Section]`. This might be used if you want each user to have their own GAM
project for auditing purposes. When `GAMCFGSECTION` is set, the user will not be allowed to select
a different `[Section]`.
* https://github.com/taers232c/GAMADV-XTD3/wiki/gam.cfg#multiple-users-projects-on-one-computer

Updated `gam <UserTypeEntity> delete photo` to handle `Error 500 Internal error.`

5.23.08

Added optional qualifier `not` to match patterns in `gam print groups` and `gam print|show group-members`.
The groups will be selected if the `matchpattern` does not match the `<RegularExpression>`.
```
emailmatchpattern [not] <RegularExpression>
namematchpattern [not] <RegularExpression>
descriptionmatchpattern [not] <RegularExpression>
```

Added option `useshortcuts [<Boolean>]` to `gam <UserTypeEntity> collect orphans`. By default,
GAM adds the target user folder as a parent of an orphan. This may now fail as the orphan may have parents belonging
to other users and files can now have only one parent. With `useshortcuts true`, GAM puts a shortcut to the orphan
into the target user folder and does not modify the orphan's parents. GAM will not duplicate an existing shortcut.

5.23.07

Fixed code in `gam <UserTypeEntity> transfer drive <UserItem>` that caused the following error:
```
ERROR: 403: cannotAddParent - Increasing the number of parents is not allowed
```
This was caused by the Google change effective 2020-10-01 that prevents files/folders from having
more that one parent. When transferring files from userA to userB, files owned by userC directly
in userA's My Drive (or in the top level of `select <DriveFileEntity>`) can't have their parents
changed; now, userB will get a shortcut to those files.

5.23.06

Added `todrive_sheet_timestamp [<Boolean>]` and `todrive_sheet_timeformat <String>` to `gam.cfg`.
Added `tdsheettimestamp [<Boolean>]` and `tdsheettimeformat <String>` to `<ToDriveAttribute>`.
These allow setting timestamp information on a sheet (tab) that is different than the timestamp
information on the Google spreadsheet file.

Removed option `tdaddsheettitle <String>` from `<ToDriveAttribute>`; use the existing `tdsheet <String>`
option with `tdaddsheet` to name the new sheet (tab).

** This is not a backwards compatible change, but it is simpler; I apologize for the inconvenience.**

Added option `returnlinkonly` to `gam <UserTypeEntity> create|update drivefile` that causes GAM to return just the
`webViewLink` of the created/updated file as output. This would typically be used with `localfile <FileName> mimetype gdoc|gsheet|gpresentation`
where Google converts the local file `<FileName>` to a Google document.
```
$ gam user user@domain.com create drivefile localfile local.xlsx returnlinkonly mimetype gsheet
https://docs.google.com/spreadsheets/d/12340ar1pW3GkiNlVhTFaNigkP3nZnoE5iTynjFjwxyz/edit?usp=drivesdk
```

5.23.05

Added option `tdaddsheettitle <String>` to `<ToDriveAttribute>`.  When used with `tdaddsheet`,
the new sheet (tab) can be named independently of the existing Google spreadsheet file.

5.23.04

Added option `tdaddsheet [<Boolean>]` to `<ToDriveAttribute>`.  When used with `tdfileid`,
a new sheet (tab) within an existing Google spreadsheet can be created with a `gam print todrive` command.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive#command-line-options

5.23.03

Updated `gam print teamdriveacls user <EmailAddress>` to handle the following error:
```
ERROR: 403: insufficientAdministratorPrivileges - The requesting user does not have the administrator privileges required to access shared drive
```

5.23.02

Fixed bug in `gam info group <GroupEntity> ciallfields` that caused the error:
```
ERROR: expected string or bytes-like object
```

5.23.01

Added `quick_info_user` to `gam.cfg` to control how much information requiring additional API calls is displayed with `gam info user`.
The default behavior (`quick_info_user = False`) is to display aliases, building names, groups, licenses and all custom schemas.
You use options to disable whatever additional information you don't want.

With `quick_info_user = true`, then none of the additional information is displayed by default.
You use options to enable whatever additional information you do want.

* https://github.com/taers232c/GAMADV-XTD3/wiki/Users#display-information-about-users

Added `lastknownnetwork` to `<CrOSFieldName>`.

5.23.00

Added `preview` option to `gam <UserTypeEntity> create|update|delete|sync license` commmands;
if specified, the changes will be previewed but not executed.

Added `actioncsv` option to `gam <UserTypeEntity> create|update|delete|sync license` commands.
For `create`, 'delete` and 'sync`, this will produce a CSV file with columns `user,productId,skuId,action,message`.
For `update`, this will produce a CSV file with columns `user,productId,oldskuId,skuId,action,message`.
This file shows the actions performed when processing the licenses.

Added `addonly|removeonly` options to `gam <UserTypeEntity> sync license` commands. By default, a sync will perform
add and remove operations; these options limit the operations as specified.
```
gam <UserTypeEntity> create|add license <SKUID> [product|productid <ProductID>] [preview] [actioncsv]
gam <UserTypeEntity> update license <SKUID> [product|productid <ProductID>] [from] <SKUID> [preview] [actioncsv]
gam <UserTypeEntity> delete license <SKUID> [product|productid <ProductID>] [preview] [actioncsv]
gam <UserTypeEntity> sync license <SKUID> [product|productid <ProductID>] [addonly|removeonly] [preview] [actioncsv]
```
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Licenses

Updated `commit-batch` command in batch files to take an optional argument that causes GAM to wait for user input before continuing.
* `commit-batch`
  * GAM waits for all running GAM commands to complete
  * GAM continues
* `commit-batch <String>`
  * GAM waits for all running GAM commands to complete
  * GAM prints `<String>` and waits for the user to press any key
  * GAM continues

Fixed bug in `gam <UserTypeEntity> sync license` where an attempt was made to add a license to an existing license holder.

5.22.13

Following Jay's lead, added commands to send commands to ChromeOS devices.
```
<CrOSCommand>
        reboot|
        remote_powerwash|
        set_volume <0-100>|
        wipe_users|
        take_a_screenshot

gam issuecommand cros <CrOSEntity> command <CrOSCommand> [times_to_check_status <Integer>] [doit]
gam <CrOSTypeEntity> issuecommand command <CrOSCommand> [times_to_check_status <Integer>] [doit]
gam getcommand cros <CrOSEntity> commandid <CommandID> [times_to_check_status <Integer>]
gam <CrOSTypeEntity> getcommand commandid <CommandID> [times_to_check_status <Integer>]
```
* https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices

5.22.12

Added check for more than one parent in `gam create|update|copy|move drivefile` and `gam create sheet`;
multiple file parents are no longer allowed.
* https://developers.google.com/drive/api/v3/ref-single-parent

Added option `showgroupnameslist` to `gam <UserTypeEntity> print contacts` that is used in conjunction
with `formatjson` to add the key `ContactGroupsList` with a list of contact group names to the JSON output.
This key and its values can be used when creating contacts with the `json` option to set contact groups.

5.22.11

Fixed bug where `csv_output_row_drop_filter` was not being processed when `formatjson` was specified.

5.22.10

Updated `gam user <UserItem> print driveactivity` to do additional checking to find
values for user.name and user.emailAddress. Events return a `user` if a logged in user
performed the action; events return an `impersonation` if an action was performed on behalf
of a user via the Drive API; GAM now handles `impersonation` as well as `user`.

5.22.09

Fixed bug in `gam user <UserItem> print driveactivity` where the actor user names were
incorrectly shown as the user `<UserItem>` rather than the actual user.

5.22.08

Fixed bug in `gam create device` that caused a trap.

Fixed bug in `gam print org fromparent <OrgUnitPath> showparent` that caused `ERROR: API access Denied`
when `<OrgUnitPath>` had no sub OUs.

Handle error when `gam device` commands are issued but Service Account access is not enabled.

5.22.07

Deleted options `alias|aliases <AliasList>` and `dynamic <QueryDynamicGroup>` from `gam update cigroup`
as the options are only applicable when the group is created.

5.22.06

The Drive Activity API v1 has been deprecated, thus `gam print|show driveactivity` will now
always use Drive Activity API v2. The `v2` option is ignored; the options `allevents`, `combinedevents` and `singleevents`
are ignored as they have no meaning with Drive Activity API v2.

5.22.05

Added options to `gam create|update drivefile` to manage content restrictions.
* https://gsuiteupdates.googleblog.com/2020/10/lock-files-using-the-google-drive-api.html
```
<DriveFileAttribute> ::=
        (contentrestrictions readonly false)|
        (contentrestrictions readonly true [reason <String>])|
```

Added new Workspace licenses SKUs.
* https://developers.google.com/admin-sdk/licensing/v1/how-tos/products
```
<SKUID> ::=
        wsentplus|workspaceenterpriseplus|gae|gse|enterprise|gsuiteenterprise|1010020020|
        wsbizplus|workspacebusinessplus|1010020025|
        wsentstan|workspaceenterprisestandard|'1010020026|
        wsbizstart|workspacebusinessstarter|1010020027|
        wsbizstan|workspacebusinessstandard|1010020028|
        wsess|workspaceesentials|gsuiteessentials|essentials|d4e|driveenterprise|drive4enterprise|1010060001|
        wsentess|workspaceenterpriseessentials|1010060003|
```

5.22.04

The following additions are derived from initial work by Jay.

Added commands to manage Cloud Identity groups. This is a work in progress.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Groups

5.22.03

Added options `alias|aliases <AliasList>` and `dynamic <QueryDynamicGroup>` to
`gam update group` to allow setting options on Cloud Identity groups.

5.22.02

Changed option `notify <EmailAddress>` in `gam create|update user` to `notify <EmailAddressList>`
so that notifications about account creation|update can be sent to multiple recipients.

Fixed bug where `gam config csv_output_column_delimiter "x"` was not being properly processed.

5.22.01

Handle the following error when deleting members from groups. This is an invalid message from Google,
the member is in the group but Google seems to think that it is an invalid email address. I'm not sure what
the long term solution is but this fix keeps GAM from terminating.
```
ERROR: 404: resourceNotFound - Does not exist
```

5.22.00

The following additions are derived from initial work by Jay.

Added commands to support the new Device Management API.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Cloud-Identity-Devices

To use these commands you must update your service account authorization.
```
gam user user@domain.com check serviceaccount
```

In the following places a Google Admin email address is required; by default the admin email address in `oauth2.txt` is used.
* Managing Shared Drives as an administrator.
* Executing `gam alert|alertfeedback` commands.
* Sending email when a from user is not specified
* Uploading files with `todrive` when neither `todrive_user` or `tduser` is specified.
* All `gam printer` commands when `<UserTypeEntity>` is omitted.

Added `admin_email` to `gam.cfg` which will supercede the value from `oauth2.txt`.

Added `enable_dasa` to `gam.cfg`. When True, GAM will use a Delegated Admin Service Account
for all API access. This is the initial step in getting GAM to use Service Account access for all API calls.
**This is for testing only!**

The following variables in `gam.cfg` must be set when `enable_dasa` is True: `admin_email`, `customer_id` and `domain`,
`customer_id` may not be set to `my_customer`.

5.12.10

Fixed bug introduced in 5.12.09 when removing batch processing for licenses.

5.12.09

Remove batch processing from licensing commands as Jay reports that it generates many errors.

5.12.08

Following Jay's lead, added the following command to synchronize users and licenses.
```
gam <UserTypeEntity> sync license <SKUID> [product|productid <ProductID>]
```
* GAM determines which users currently hold a license for `<SKUID>`.
* The license will be deleted for all current license holders that are not in `<UserTypeEntity>`.
* The license will be added for all users in `<UserTypeEntity>` that are not current license holders.

All license commands now use batch processing to improve performance.

5.12.07

Handle the following error when executing `gam courses <CourseEntity> create|delete|clear|sync students|teachers`.
```
ERROR: 503: serviceNotAvailable - The service is currently unavailable.
```

5.12.06

Fixed bug in `gam print groups` that caused the following error:
```
ERROR: 400: invalid - Request contains an invalid argument.
```

5.12.05

Added option `oneitemperrow` to `gam <UserTypeEntity> print asps` to have each of a
user's Application Specific Passwords displayed on a separate row.
```
gam <UserTypeEntity> print asps|applicationspecificpasswords [todrive <ToDriveAttribute>*]
        [oneitemperrow]
```

5.12.04

Added command to display Application Specific Passwords in CSV format.
```
gam <UserTypeEntity> print asps|applicationspecificpasswords [todrive <ToDriveAttribute>*]
```

5.12.03

Fixed bug in `gam print users ... groups|groupsincolumns` that caused no rows to be output
when `config csv_output_row_filter "GroupCounts:count>n` or `config csv_output_row_filter "^Groups$:count>n`
was specified.

5.12.02

Updated processing of scalar schema fields in `gam create|update user` to allow suppression
of empty values; these fields show up as `Undefined` in the Contacts directory.
It is already the case that empty values can be suppressed for multivalued fields.
```
<UserBasicAttribute> ::=
        (<SchemaName>.<FieldName> [scalarnonempty|
                                   [multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]]]
                                  <String>)
```
An empty scalar field will be defined.
```
gam update user user@domain.com SchemaName.FieldName ""
```
An empty scalar field will be suppressed.
```
gam update user user@domain.com SchemaName.FieldName scalarnonempty ""
```

5.12.01

Added code to handle the following error when an attempt is made to copy a site:
```
ERROR: 400: badRequest - The requested conversion is not supported.
```

5.12.00

Changed `regex:<RegularExpression>` and `notregex:<RegularExpression>` processing in `csv_output_row_filter`.
In prior versions, the `<RegularExpression>` was processed in a case sensitive manner; in many cases this is
probably not desirable; e.g., matching file names which are case insensitive.

Now, `<RegularExpression>` is processed in a case insensitive manner. **This is a change in behavior.**
To get the prior case sensitive processing, use `regexcs:<RegularExpression>` and `notregexcs:<RegularExpression>`.

5.11.06

Starting from preliminary code from Jay, added commands to manage administrative roles.
```
gam create adminrole <String> privileges all|all_ou|<PrivilegesList> [description <String>]
gam update adminrole <RoleItem> [name <String>] [privileges all|all_ou|<PrivilegesList>] [description <String>]
gam delete adminrole <RoleItem>
```

Added options `signout` and `turnoff2sv` to `gam <UserTypeEntity> deprovision` to sign out a user
and turn off their 2-Step Verification when deprovisioning.

5.11.05

Added a command to sign a user out of all web and device sessions and reset their sign-in cookies.
The user will have to sign in by authenticating again.
```
gam <UserTypeEntity> signout
```

Added a command to turn off 2-Step Verification for a user.
If successful this call will turn off 2-Step Verification and also remove all registered second steps on the user account.
This call will fail if the user is not enrolled in 2-Step Verificationin or has 2-Step Verification enforced, or is enrolled in the Advanced Protection Program.
```
gam <UserTypeEntity> turnoff2sv
```

5.11.04

Added `todrive_clearfilter` to `gam.cfg` and `tdclearfilter` to `<ToDriveAttribute>` that cause GAM to
clear the spreadsheet basic filter when uploading data to an existing sheet in an existing file.
When False, the current/default behavior, the data suppressed by an existing filter is not replaced
by the uploaded data. This might be desirable if you wanted to compare the previous and current data,
but in general you probably want a value of True so that the uploaded data completely replaces the existing data.

5.11.03

Added additional retries to `gam course add|sync teachers|students` when Google reports that the teacher|student
email address is not found. In certain (not well defined) circumstances Google reports valid email addresses
as not found.

5.11.02

Changed the prompt for a login email address for all `gam project` commands to reflect that
what is required is a GCP project manager email address. For most cases, this will be a G Suite super admin but in
some cases GCP and G Suite management is separated and a GCP project manager email address is required.
```
$ gam show projects filter gam
Enter your G Suite admin or GCP project manager email address authorized to manage project(s): filter gam?
$ gam update project
Enter your G Suite admin or GCP project manager email address authorized to manage project(s): gam-project-abc-123-xyx?
```

Added option `scalarsfirst` to `gam print users` that, when column headers are sorted, causes
the scalar user fields to appear before the user fields with repeating values.

5.11.01

Improved performance of `gam print groups ciallfields|(cifields <CIGroupFieldNameList>)`.

Handled bug in Cloud Identity Groups API where groups with `whoCanJoin INVITED_CAN_JOIN` can't be accessed by the API.

This is Beta software from Google, use with caution.

5.11.00

Added options `ciallfields` and `cifields <CIGroupFieldNameList>` to `gam info|print groups`.
These allow display of `Cloud Identity Groups` information.
* https://cloud.google.com/identity/docs/groups
* https://gsuiteupdates.googleblog.com/2020/08/new-api-cloud-identity-groups-google.html

Added option `makesecuritygroup` to `gam update groups` to update a Google Group to a Security Group.
* https://gsuiteupdates.googleblog.com/2020/09/security-groups-beta.html
Warning: A Security Group cannot be changed back to a Google Group.

To use these features you must add the Cloud Identity Groups API to your project and authorize
the appropriate scope.
```
gam update project
gam oauth create
```

This is Beta software from Google, use with caution.

5.10.02

Improve `Bad Gateway` API error handling.

5.10.01

Added `csv_output_row_drop_filter` to `gam.cfg` to allow CSV row filtering by specifying filters
that cause the row to be dropped if any of the filters match.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Print-Filtering#column-row-filtering

5.10.00

Added `multiprocess_pool_limit` to `gam.cfg`; it controls how GAM passes commands
to the multiprocessing pool. This is a special use case for testing.
* `-1` - Pass all commands to the multiprocessing pool immediately
* ` 0` - Pass commands to the multiprocessing pool in batches of size `num_threads`; this the default
* `>0` - Pass commands to the multiprocessing pool in batches of the indicated size

5.09.02

Added option `showdayofweek` to `gam calendar <CalendarEntity> info|show|print events` and
`gam <UserTypeEntity> info|show|print events <UserCalendarEntity>` to display the day of week
when event start and end times are displayed.

5.09.01

Fixed bug `gam <UserTypeEntity> draft|import|insert message` where `htmlmessage`, `htmlfile` and `ghtml`
were not properly processed and the HTML code was handled as plain text.

5.09.00

Update to new Google site for authorizing Service Account scopes.

5.08.22

Extended code to handle the following error when adding/removing aliases/teachers to courses:
```
429: quotaExceeded - Quota exceeded for quota metric 'Requests' and limit 'Requests per minute per user' of service 'classroom.googleapis.com'
```

5.08.21

Added code to handle the following error when adding students to courses:
```
429: quotaExceeded - Quota exceeded for quota metric 'Requests' and limit 'Requests per minute per user' of service 'classroom.googleapis.com'
```

5.08.20

Updated maximum value for `num_threads` and `num_tbatch_threads` in `gam.cfg` to 1000. This is a special use case,
do not use values much higher than 20 in normal circumstances.

5.08.19

Fixed bug in `gam update user <UserItem> createifnotfound` that gave the following error even though
all of the required fields were specified.
```
Update Failed: Unable to create not found user, some required field (givenName, familyName, password/notfoundpassword) not present
```

5.08.18

Updated `gam [<UserTypeEntity>] print drivefileacls <DriveFileEntity>` to display output
even if `<DriveFileEntity>` doesn't have any ACLs.
```
Owner,id,permissions
user@domain.com,abcyKMQf_RK8iUk9xyz,0
```

5.08.17

Improved error handling in `gam create vaultexport matter <MatterItem>` of `quotaExceeded - Exceeded running export limit of 20 concurrent exports.`.

5.08.16

Updated code in `gam <UserTypeEntity> get drivefile <DriveFileEntity> csvsheet <SheetEntity>` and `gsheet(:<FieldName>)+ <UserGoogleSheet>`
to handle unexpected data in Spreadsheet URL.

5.08.15

Fixed bug in `gam courses <CourseEntity> clear|sync` that misinterpreted `<CourseEntity>` when it was a course alias containing a space.

5.08.14

Suppress `Not authorized to access this feed` error message in `gam [<UserTypeEntity>] print|show sites roles all|<SiteACLRoleList>`;
users with role reader can't access the site ACLs to get the roles and the message is misleading.

5.08.13

Added `exportlinks` to `<DriveFieldName>`.

5.08.12

Updated `gam report users` to create a column `accounts:disabled_time` from the timestamp in the column `accounts:disabled_reason`.
This makes it possible to filter on the time. For example, to see all users suspended more than a year ago:
```
gam config csv_output_row_filter "accounts.is_suspended:boolean:true,accounts.disabled_time:date<-1y" report user user all parameters accounts:is_suspended,accounts:disabled_reason
```

5.08.11

Handle `ERROR: 403: requiredAccessLevel - You need to have owner access to this calendar.` in
`gam <UserTypeEntity> modify|remove calendars`.

5.08.10

Fixed bug in `gam calendars <CalendarEntity> <Command> event` commands where service account access was not used
when `<CalendarEntity>` specified a user's primary calendar.
*  `<Command>=add` - The event creator would be the administrator rather than the user
*  `<Command>=update` - Some fields in the event were not updated, e.g., reminder

5.08.09

Added option `rangelist <SpreadsheetRangeList>` to gam <UserTypeEntity> clear|info|print|show sheetrange`.
This allows specifying multiple ranges with a single argument.

5.08.08

Added option `valuerangesonly` to `gam <UserTypeEntity> print|show sheetrange` which, in
conjunction with `formatjson` limits the display to just the `valueRanges` data. This will
make it simpler to capture the sheetrange data, modify it, and update the sheet with the modified data.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Spreadsheets#display-values-in-a-spreadsheet

Added `oauthuser` to `<UserTypeEntity>`; it represents the admin email address from `oauth2.txt`.

This will typically be used when multiple customers/domains are defined in `gam.cfg`.
For example, to get information about the admin.
```
$ gam oauth info
Client OAuth2 File: /GamConfig/oauth2.txt
...
G Suite Admin: admin@domain.com
Expires: 2020-07-29T14:26:50-07:00

$gam oauthuser info user
User: admin@domain.com
  Settings
...
```

5.08.07

Fixed bug in `gam print group-members recursive noduplicates` where a groups members would not be displayed if it
was processed as a subgroup of another group before it was processed as a top level group.

Handle `ERROR: 400: badRequest - Bad Request` in `gam <UserTypeEntity> transfer drive <UserItem>`.

5.08.06

Improved error handling in `gam create|update course ... copyfrom <CourseID>` when trying to copy links
to inaccessible materials files.

Updated definition of `<RowValueFilter>` in `config csv_output_row_filter` to avoid a parsing error.
The two elements in a range must now be separated by a forward slash `/`, not by a space as this caused the error.
```
<RowValueFilter> ::=
        count<Operator><Number>|
        countrange=<Number>/<Number>|
        countrange!=<Number>/<Number>|
        date<Operator><Date>|
        daterange=<Date>/<Date>|
        daterange!=<Date>/<Date>|
        time<Operator><Time>|
        timerange=<Time>/<Time>|
        timerange!=<Time>/<Time>|
        boolean:<Boolean>|
        regex:<RegularExpression>|
        notregex:<RegularExpression>
```
5.08.05

Fixed bug in `config csv_output_row_filter "<FieldName>:date<Operator><Date>"` that caused a trap.

5.08.04

Updated code in `gam <UserTypeEntity> collect orphans` to avoid `Temporary error: internalError - Internal Error`.

5.08.03

Added option `countsrowfilter` to `gam <UserTypeEntity> print filelist ... countsonly` that causes
GAM to apply `config csv_output_row_filter` to the file counts rather than the file details.

Display file counts for users with files of size greater that 100MB, `csv_output_row_filter`
is applied to the file details.
```
gam config csv_output_row_filter "size:count>100000000" all users print filelist countsonly fields size
```
Display file counts for users with more than 100 `video/mp4` files, `csv_output_row_filter`
is applied to the file counts.
```
gam config csv_output_row_filter "video/mp4:count>100" csv_output_header_filter "Owner,video/mp4" all users print filelist countsonly countsrowfilter
```

Fixed bug in processing `csv_output_row_filter "field:regex:^$"` where a row without the field column would not match.
It should match as the filter is trying to match an empty field.

Upgraded to Python 3.8.5.

5.08.02

Handle `ERROR: 409: conflict - Conflicting requests. Please try again` when adding members to groups.

5.08.01

Simplified `gam csv` recoding.

5.08.00

Recoded `gam csv` processing to avoid hangs, particularly on Windows.

Fixed code in `gam info drivefileacl ... showtitles` and `gam print|show drivefileacls ... showtitles`
to scucessfully get the Team Drive name.

5.07.01

Added option `showpermissionslast` to `gam <UserTypeEntity> print filelist` which causes GAM
to display all `permissions` fields as the right-most columns in the CSV file. This option does not apply
when `formatjson` is specified.

5.07.00

In versions of GAM before `5.07.00`, when you did `gam <UserTypeEntity> update users password random`
and `<UserTypeEntity>` specified multiple users, all of them were assigned the same random password;
this is the same behavior as in Standard GAM. Additionally, there was a bug where the same notification
information was sent for all users when `notify <EmailAddress>` was specified; this is fixed.

If you would like each of the users in `<UserTypeEntity>` to be assigned a unique random password, specify `password uniquerandom`.

Added option `no_action_if_alias` to `gam <UserTypeEntity> update|delete|suspend|unsuspend users`; the specified action
will not be performed if `<UserTypeEntity>` specifies an alias rather than a primary email address.

5.06.12

Fixed bug in `gam sendemail` where PDF attachements weren't properly encoded.

5.06.11

Added option `eventrowfilter` to `gam report <ActivityApplictionName> ... countsonly` that causes
GAM to apply `config csv_output_row_filter` to the event details rather than the event counts.
For example, you're interested in files with extension `xyz` created yesterday.
```
Details for each file
gam config csv_output_row_filter "doc_title:regex:\.xyz" report drive event create yesterday

Number of files by each user
gam config csv_output_row_filter "doc_title:regex:\.xyz" report drive event create yesterday countsonly eventrowfilter

Number of files summarized across all users
gam config csv_output_row_filter "doc_title:regex:\.xyz" report drive event create yesterday countsonly summary eventrowfilter
```

5.06.10

Fixed bug that caused trap in `gam print course-work ... showtopicnames`.

5.06.09

Handle `ERROR: 500: internalError - Internal error encountered.` in `gam <UserTypeEntity> update license`.

5.06.08

Fixed bug in `gam course <CourseID> sync students` that caused a trap.

Handle `LookupError: unknown encoding` trap in `gam print messages`.

5.06.07

Added option `showtopicnames` to `gam print course-work` which causes GAM to include
the column `topicName` in the output. An additional API call per course is required
to get the `topicId` to `topicName` map.

Upgraded to Python 3.8.4.

5.06.06

Added option `makefirstteacherowner` to the following commands:
```
gam course <CourseID> create|add teachers [makefirstteacherowner] <UserItem>
gam course <CourseID> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
gam courses <CourseEntity> create|add teachers [makefirstteacherowner] <UserTypeEntity>
gam courses <CourseEntity> sync teachers [addonly|removeonly] [makefirstteacherowner] <UserTypeEntity>
```
In each command the only/first user in `<UserItem>` or `<UserTypeEntity>` will be updated to be the
owner of the Course(s).

5.06.05

Added option `timerangeorder ascending|descending` to `gam print cros|crosactivity`. By default, the
Google Directory API returns `activeTimeRanges` for CrOS devices in ascending (oldest to newest) order.
Specifying `timerangeorder descending` causes GAM to re-order `activeTimeRanges` in descending (newest to oldest) order.
This makes it easy to get the `N` most recent values with `activetimeranges listlimit N timerangeorder descending`.

Added option `ignorenullpassword` to `gam create|update user` to cause GAM to ignore options like `password ""` or
`password ~password` where the CSV entry `password` is null. This would typically be used when processing CSV files
where only selected user's passwords are being updated.

5.06.04

Handle `ERROR: 400: invalidArgument - Request contains an invalid argument.` in `gam print|show alerts`.

5.06.03

Added option `lograndompassword <FileName>` to `gam create|update user`. When this option
and `password random` or `notfoundpassword random` are specified, the user email address and random
password are appended to `<FileName>`. When bulk creating/updating users, this lets you log the
random passwords without have to send a notification email.

5.06.02

Fixed bug where `csv_output_header_drop_filter` and `csv_output_header_filter` were not properly
processed when `formatjson` was specified in a print command.

Added option `addpathstojson` to `gam <UserTypeEntity> print filelist`. When `filepath|fullpath`,
`formatjson` and `addpathstojson` are all specified, the path information will be included in the
JSON data rather than as additional columns.

Fixed `gam <UserTypeEntity> show fileinfo <DriveFileEntity>` to properly include path information
in the JSON data when `filepath` and `formatjson` are specified.

5.06.01

Fixed bug in `gam info user <UserItem> nolicenses` that caused a trap.

5.06.00

Update google_auth, google_auth_httplib2, google_auth_oauthlib, googleapiclient, httplib2 libraries.

5.05.12

Updated `gam info domain` to get the first available user/license count data. The Reports API seems
to be giving misleading messages that only partial data is available when, in fact, all of the data is available.
Thus, GAM is backing up to an earlier date unnecessarily.

5.05.11

Added `todrive_timeformat` to `gam.cfg` and `tdtimeformat <String>` to `<ToDriveAttribute>`to allow
customization of the timestamp format used in file names when files are uploaded with `todrive`.
* See: https://docs.python.org/3/library/datetime.html#strftime-strptime-behavior

5.05.10

Fixed bug in `gam <UserTypeEntity> print|show messages` that caused a trap.

Fixed bug in `gam <UserTypeEntity> check|update serviceaccount`.

5.05.09

Added option `returnidonly` to `gam <UserTypeEntity> copy drivefile <DriveFileEntity>` and
`gam <UserTypeEntity> update drivefile <DriveFileEntity> copy` that causes GAM to return just the
file ID of the copied file as output. This will be useful in scripts that copy a file and then
want to perform subsequent GAM commands on the copied file. When copying folders, the option is only useful
when copying a folder without recursion. This file ID will only be valid when the return code
of the command is 0; program accordingly.

5.05.08

Added option `writeurltofile` to `gam <UserTypeEntity> check|update serviceaccount` to have
GAM write the authorization URL into the file `gamsvcaccturl.txt` in the folder with the GAM executable.
This is useful for older versions of Command Prompt and PowerShell that can't properly copy/paste multi line strings.

5.05.07

Fixed bug in `gam info user` where extraneous license information was displayed.

5.05.06

Added `topicid` to `<CourseWorkFieldName>`.

5.05.05

Fixed bug in `gam <UserTypeEntity> print filelist|filecounts` where files without permissions, shortcuts for example,
were displayed/counted when a permission match was defined.

Updated code to avoid a trap in `gam <UserTypeEntity> update drivefile <DriveFileEntity> ... csvsheet <SheetEntity>`;
the Google Sheets API was not returning the sheetId in a call where GAM expected it.

Following Jay's lead, added `deprovision_upgrade_transfer` to `<CrOSAction>`.

5.05.04

Fixed bug in `gam <UserTypeEntity> print filelist` where using `query:"XXX"` would improperly
downshift `XXX'; using `query "XXX"` worked properly.

5.05.03

Added command to list all of the groups to which a user directly belongs. There are three columns:
* `User` - The user email address
* `Groups` - The number of groups
* `GroupsList` - The `delimiter <Character>` separated list of group email addresses
```
gam <UserTypeEntity> print groupslist [domain <DomainName>] [todrive <ToDriveAttribute>*]
        [delimiter <Character>] [quotechar <Character>]
```
For example, to find all students that aren't in any groups:
```
gam config csv_output_row_filter "Groups:count=0" ou /Students print groupslist
```

5.05.02

Fixed bug in `gam <UserTypeEntity> print filelist` that caused a trap when `filepath` was specified but `name` was not included in `fields`.

5.05.01

Allow `querytime.* <Time>` option in conjunction with `selectsubquery <QueryDriveFile>`
in `gam <UserTypeEntity> print filelist`. For example, you can identify all Meet recordings
within a particular time period, in this case, all recordings older than 30 days.
```
gam user user@domain.com print filelist select name "Meet Recordings" querytime30d -30d selectsubquery "modifiedTime<'#querytime30d#'" fields id,name
```
5.05.00

Google Docs and Drive Files can be used to specify notes, messages and signatures.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Command-Data-From-Google-Docs-Sheets

Added option `aliasesincolumns` to `gam print courses` that alters the display of course aliases.
When the `aliases` option is used, all aliases are displayed in the single column `Aliases`
separated by a delimiter. As aliases can contain spaces, this format could make the data hard to interpret.
When `aliasesincolumns` is specified, the `Aliases` column contains the number of aliases and `Aliases.0`, `Aliases.1`, ...
contain the individual aliases.

5.04.11

Added option `returnurlonly` to gam <UserTypeEntity> get profilephoto` that causes GAM to return just the URL
of the profile photo.

Following Jay's lead, switched to using the Service Usage API when enabling project APIs.

Fixed bug in `gam course <CourseID> sync` that caused spurious results when `<CourseID>` was an alias
without the leading `d:`.

5.04.10

Added command to get a user's profile photo.
```
`gam <UserTypeEntity> get profilephoto [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>] [noshow]
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Photo

5.04.09

Following Jay's lead, added options `base64-md5` and `base64-sha1` to `gam create|update user` as alternative
methods of specifying the `password` format. This allows pulling md5 and sha-1 passwords stored in OpenLDAP format
into G Suite. This command sets the user password to "helloworld".
```
gam update user user@example.com password "{SHA}at+xg6SiyUovktq1redipHiJpaE=" base64-sha1
```

Added option `notifypassword <String>` to `gam create|update user` that allows providing a plain text password to
be sent in a notification when a hashed password is specified on the command line.

5.04.08

Finally, fixed `gam config no_browser true oauth create` to write correct data to file `gamoauthurl.txt` so that the
authorization URL can be copied from the file rather than from the screen.

5.04.07

Once again, fixed `gam config no_browser true oauth create` to write correct data to file `gamoauthurl.txt` so that the
authorization URL can be copied from the file rather than from the screen.

5.04.06

Fixed `gam config no_browser true oauth create` to write correct data to file `gamoauthurl.txt` so that the
authorization URL can be copied from the file rather than from the screen.

5.04.05

Fixed `gam config no_browser true oauth create` to write file `gamoauthurl.txt` so that the
authorization URL can be copied from the file rather than from the screen.

5.04.04

Added command to check the validity of drive file shortcuts.
```
gam <UserTypeEntity> check drivefileshortcut <DriveFileEntity>
        [csv [todrive <ToDriveAttribute>*]]
```

5.04.03

Added additional error handling when managing licenses.

5.04.02

Added option `copymaterialsfiles [<Boolean>]` to `gam create|update course copyfrom`.
When used in conjunction with `announcementstates` and `workstates`, any files referenced by materials
in announcements or class work in the `copyfrom` course will be copied to the course being created/updated;
by default, links to those files will be copied. You must verify that the teacher of the course being created/updated
has access to the files in the `copyfrom` course. Files can only be copied to a course that is ACTIVE;
GAM will adjust the course state as necessary.

5.04.01

Starting from code by Eduardo Mazolini submitted to Jay, added `group_inde <GroupItem>` and `groups_inde <GroupList>`
to `<UserTypeEntity>`. These represent all users, regardless of suspension status, from the specified groups and their subgroups.
They are equivalent to:
```
group_users <GroupItem> members managers owners includederivedmembership end
group_users <GroupItemList> members managers owners includederivedmembership end
```

5.04.00

Expanded options for selecting collections of files with `gam <UserTypeEntity> print filelist`.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files-Display

Updated `gam <UserTypeEntity> print filelist filepath|fullpath` to include additional path information.
Each path will start with:
* `My Drive` - Files on My Drive that are not orphans
* `Orphans` - Files on My Drive that are orphans
* `SharedWithMe` - Files shared with the user that have no parent on My Drive
* `SharedDrive` - Files on Shared Drives

Added options `enforcesingleparent <Boolean>` and `movetonewownersroot <Boolean>`
to the relevant `create|update drivefile` and `create drivefileacl` commands to allow testing of an upcoming Google Drive change.
* See: https://developers.google.com/drive/api/v3/ref-single-parent
Do NOT set `enforcesingleparent true` until you throughly understand its ramifications.
This is a work in progress, I'm testing using `enforcesingleparent` with other commands like `copy|move drivefile'
and 'transfer drive`.

5.03.41

Added option `convertparents` to `gam <UserTypeEntity> create|add drivefileshortcut <DriveFileEntity>`; this option causes
GAM to convert all but the last parent reference in `<DriveFileEntity>` to shortcuts.
Previuosly, if you didn't specify the `shortcutname <String>` option, the shortcut was named `Shortcut to <DriveFileName>`
where `<DriveFileName>` is the name of each file referenced in `<DriveFileEntity>`. Now, to be consistent with Google Drive,
the shortcut will be named `<DriveFileName>`. `<String>` can contain the string `#filename#` which will be replaced with
`<DriveFileName>`; this allows you to get the previous behavior with `shortcutname "Shortcut to #filename#"`.

5.03.40

Fixed `gam download vaultexport|export` to properly handle the `targetname <FileName>` option.
Previously, all of the top level files downloaded were given the same `<FileName>` and overwrote each other.
Now, the extensions of the top level files will be appended to `<FileName>` so that
distinct files are downloaded and written. Additionally, `<FileName>` can contain the strings `#objectname#`, `#filename#`
and `#extension#` which will be replaced by the values from the orignal object names to construct a complete top level name.

5.03.39

Added option `includederivedmembership` to `group_users|group_users_ns|group_users_susp <GroupList>` as an
alternative to the `recursive` option.
* `recursive` - Expand subgroups but do not expand a member of type CUSTOMER (all users in a domain)
* `includederivedmembership` - Expand subgroups and  expand a member of type CUSTOMER (all users in a domain)

5.03.38

Improved performance of `group_users|group_users_ns|group_users_susp <GroupList>` when `recursive` is specified.

5.03.37

Updated `gam <UserTypeEntity> get drivefile` to properly set the end-of-line character on Windows
when the `gsheet|csvsheet <SheetEntity>` option was used to download a Google Sheet.

5.03.36

Added option `groupsincolumns` to `gam print users` as an alternative to the `groups` option.

With `groups', there will be two columns displayed: `GroupsCount` and `Groups`.
* `GroupsCount` - The number of groups to which the user belongs
* `Groups` - A list of group email addresses

With `groupsincolumns', there will be multiple columns displayed: `Groups` and `Groups.<Number>`.
* `Groups` - The number of groups to which the user belongs
* `Groups.<Number>` - A single group enail address

5.03.35

Fixed bug in `gam print|show projects` that caused a trap.

5.03.34

Updated code to properly handle `gam.cfg` section selection in conjunction with `csv` processung.
This command structure now operates as expected; `gam.cfg` `<SectionName>` is used for all processing.
```
gam select <SectionName> ... csv <FileName> ... gam ...
```
Previously, you had to do either of the following to get `gam.cfg` `<SectionName>` to be used for all processing.
```
gam select <SectionName> save ... csv <FileName> ... gam ...
gam csv <FileName> ... gam select <SectionName> ...
```

5.03.33

Fixed bug in `gam print projects` that caused a trap when `showiampolicies` was used.

5.03.32

Fixed code in `gam <UserTypeEntity> create drivefile` to allow the `parentid` option to specify a Shared Drive.

Added option `states all|active|deleterequested` to `gam print|show projects` that allows selection of
projects to display.

Added option `showiampolicies 0|1|3` to `gam print|show projects` that adds project policy
information to the display. This requires an additional API call per service account.

* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#display-projects

5.03.31

Added option `showsakeys all|system|user` to `gam print|show svcaccts` that adds service account
key information to the display. This requires an additional API call per service account.

5.03.30

Updated code in `gam report usageparameters` to avoid a trap due to a Google API change.

5.03.29

Following Jay's lead, cleaned up code for `gam report`; in particular, backing up to earlier dates to find data.

5.03.28

Updated code in `gam info domain` to perform retries when getting license information to
avoid this warning: `WARNING: No User counts data available.`

5.03.27

Added option `formatjson` to `gam <UserTypeEntity> show fileinfo`.

5.03.26

Updated code to properly handle specifying an expiration time when creating a drive file ACL.
GAM must first create the ACL and then update it with the expiration time.

5.03.25

Fixed bug that caused a trap in `gam <UserTypeEntity> show calendars showdeleted`.

5.03.24

Fixed bug that caused a trap in `gam <UserTypeEntity> create|update drivefile` when `localfile <FileName>` was used and `<FileName>` started with `~`.

5.03.23

Added options `createdtime <Time>` and `modifiedtime <Time>` to `gam <UserTypeEntity> create drivefile`
to allow setting these values.

Added option `preservefiletimes` to `gam <UserTypeEntity> create|update drivefile` that, when used with
`localfile <FileName>`, will set the createdtime and modifiedtime values from the local file.

On some Linux systems getting the createdtime is problematic.
* See: https://stackoverflow.com/questions/237079/how-to-get-file-creation-modification-date-times-in-python/39501288#39501288

5.03.22

Added option `includederivedmembership` to `gam print groups` that is effective when
any of the options `roles`, 'members', 'managers' or `owners` is used.
The `includederivedmembership` option causes the API to expand type GROUP and type CUSTOMER
members to display their constituent members while still displaying the original member.

Added option `totalcount` to `gam print groups` that is effective when
any of the options `countsonly`, 'memberscount', 'managerscount' or `ownerscount` is used.
A column 'TotalCount' that is the total number of members in a group will be included.

The following command combines these two options to give you a listing of all of your groups
with their membership counts. The counts will be higher than expected as the API returns
both a group and its members.
```
gam print groups roles member,manager,owner countsonly totalcount includederivedmembership
```

5.03.21

Added code to wait for Service Account creation to complete in `gam create project` to avoid this error:
```
ERROR: 404: Requested entity was not found. - 404
```

5.03.20

Fixed bug that improperly set return code to 60 in `gam <UserTypeEntity> create|add drivefile`.

5.03.19

Added suboption `summary none|only|plus` to option `countsonly` in `gam <UserTypeEntity> print filelist`
that specifies display of a summarization of file counts across all users specified in the command.
* `none` - No summary is displayed; this is the default
* `only` - Only the summary is displayed, no individual user file counts are displayed
* `plus` - The summary is displayed in addition to the individual user file counts
These are the same options as in `gam <UserTypeEntity" print filecounts` but `print filelist` offers
mush more powerful file selection capabilities.

Following Jay's lead, enhanced `gam oauth create` to allow specification of the desired
scopes on the command line. Entering `<APIScopeURLList>` by hand would be tedious at best
but could be used in a script.
```
gam oauth|oauth2 create|request [admin <EmailAddress>] [scopes <APIScopeURLList>]
```
5.03.18

Fixed bug in `gam print ownership` where data was not being returned in CSV file.

5.03.17

Fixed bug in `gam <UserTypeEntity> print drivesettings` that caused a trap.

5.03.16

Handle `ERROR: Authentication Token Error - invalid_grant: The account has been deleted`

This message relates to users recently deleted; they are still defined.

This occurs when a user is specified as `uid:<String>` and `<String>` does not represent a valid user.
This can occur when doing `gam print course-work|course-submissions` where the owner of a course
has been deleted as GAM only gets the course owner in the form `uid:<String>` from the Classroom API.

5.03.15

Added `compact` option to `gam <UserTypeEntity> print sendas|signature|vacation` that causes GAM to strip
embedded carriage returns and newlines from the uploaded signature/vacation message.
This makes these values easier to process in the CSV file.

5.03.14

Handle `ERROR: Authentication Token Error - invalid_request: Invalid impersonation &quot;sub&quot; field`

This message relates to users that are no longer defined.

This occurs when a user is specified as `uid:<String>` and `<String>` does not represent a valid user.
This can occur when doing `gam print course-work|course-submissions` where the owner of a course
has been deleted as GAM only gets the course owner in the form `uid:<String>` from the Classroom API.

5.03.13

Improved error reporting when accessing group settings.

Fixed bug in `gam <UserTypeEntity> print spreadsheets` that caused a trap when multiple sheets were specified.

5.03.12

Added additional error handling when accessing courses.

5.03.11

Upgraded to googleapiclient 1.8.2.

5.03.10

Added option `showdepth` to `gam <UserTypeEntity> print filelist`. When used with `filepath` or `fullpath`, GAM
will display a `depth` column. Files/folders directly in `My Drive` are at depth 0, the depth increases by 1
for each containing folder. For files with multiple parents, the maximum depth is displayed.

5.03.09

Upgraded to OpenSSL 1.1.1g.
Upgraded to google-auth 1.14.1.

Added attributes to allow specifying calandar and event colors by name.
```
<CalendarColorName> ::=
        amethyst|avocado|banana|basil|birch|blueberry|
        cherryblossom|citron|cobalt|cocoa|eucalyptus|flamingo|
        grape|graphite|lavender|mango|peacock|pistachio|
        pumpkin|radicchio|sage|tangerine|tomato|wisteria|
<CalendarAttribute> ::=
        ...
        (color <CalendarColorName>)|
        ...
<EventColorName> ::=
        banana|basil|blueberry|flamingo|graphite|grape|
        lavender|peacock|sage|tangerine|tomato
<EventAttribute> ::=
        ...
        (color <EventColorName>)|
        ...
```

5.03.08

Enhanced error handling in `gam <UserTypeEntity> update|delete smime` when invalid data is entered.

Enhanced `gam print|show smimes` to allow more selection options as to which S/MIME configurations to display.
```
gam <UserTypeEntity> show smimes
        [primary|default|(sendas|sendasemail <EmailAddress>)]
gam <UserTypeEntity> print smimes [todrive <ToDriveAttribute>*]
        [primary|default|(sendas|sendasemail <EmailAddress>)]
```

5.03.07

Updated `gam update verify` to avoid getting: `ERROR: A failure in the SSL library occurred (_ssl.c:1108)`

5.03.06

Fixed bug in `gam <UserTypeEntity> update calattendees` where `replacestatus` and `updatestatus` were not
properly updating the attendee status.

Added `returnidonly` to `gam [<UserTypeEntity>] create teamdrive` that causes GAM to return just the
ID of the created Team Drive as output. This will be useful in scripts that create a Team Drive and then
want to perform subsequent GAM command on the Team Drive. This ID will only be valid when the return code
of the command is 0; program accordingly.
```
Linux/MacOS
teamDriveId=`gam user user@domain.com create teamdrive ... returnidonly`
Windows PowerShell
$teamDriveId = & gam user user@domain.com create teamdrive ... returnidonly`
```

Handled Google delays in `gam [<UserTypeEntity>] create teamdrive` when trying to set Team Drive restrictions
or hiding the Team Drive after it has been created.

5.03.05

Fixed bug where `gam <UserTypeEntity> print filelist ... countsonly todrive` did not upload the CSV file to Google Drive.

5.03.04

Allow relative dates in `skipdates` in `gam report usage`; e.g., `skipdates -10d:-5d`.

5.03.03

Improved error handling when parsing `skipdates` in `gam report usage`; made report title dates match actual dates used.

Updated error handling in `gam update verify|verification <DomainName> cname|txt|text|site|file`.

5.03.02

Handle `ERROR: 429: 429 - Quota exceeded for quota group 'ReadGroup' and limit 'Read requests per user per 100 seconds' of service 'sheets.googleapis.com' for consumer 'project_number:#####'.`

5.03.01

Fixed bug in `gam report usage` where `skipdates` were not processed and then enhanced `skipdates` to allow date ranges `<Date>:<Date>`.

5.03.00

Fixed bug in `gam report usage user` that caused a trap.

Added option `showparentsidsaslist` to `gam <UserTypeEntity> show fileinfo` and `gam print filelist` that causes GAM to
display the parents of a drive file/folder as a list of IDs rather that discrete entities.
In `gam show fileinfo` you will see:
```
parentsIds: ABCDE-EvX8uQ6H5tqZ73b2oAT4IIcK-JZ 012jnewfiM5G8S0lpNU05R0NCNHc
```
In `gam print filelist` you will see:
```
...,parents,parentsIds,...
...,2,ABCDE-EvX8uQ6H5tqZ73b2oAT4IIcK-JZ 012jnewfiM5G8S0lpNU05R0NCNHc,...
```

A significant Drive File change is coming later this year regarding files with multiple parents.
* See: https://developers.google.com/drive/api/v3/multi-parenting

A new command has been added to create Drive File shortcuts.
```
gam <UserTypeEntity> create|add drivefileshortcut <DriveFileEntity> [shortcutname <String>]
        [<DriveFileParentAttribute>]
        [csv [todrive <ToDriveAttributes>*]] [returnidonly]
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files#create-shortcuts

In `<MimeTypeShortcut>` `gshortcut` now refers to the new shortcuts and `g3pshortcut` to the previous third-party shortcuts.

Added items to `<DriveFileQueryShortcut>` that can be used in `gam print filelist|filecounts|filetree`:
```
all_shortcuts | all_3p_shortcuts |
my_shortcuts | my_3p_shortcuts |
others_shortcuts | others_3p_shortcuts
```

5.02.04

Fixed race condition on Windows involving locking `oauth2.txt.lock`.
ERROR: [WinError 2] The system cannot find the file specified: 'C:\\GAMConfig\\oauth2.txt.lock'

5.02.03

Fixed bug where `query:<QueryDriveFile>` was not recognized on the command line.

Fixed bug where `csv_output_header_drop_filter` caused a trap when a CSV file was processed.

Added command to get Google Spreadsheet data in CSV format.
```
gam <UserTypeEntity> print sheet <DriveFileEntity> [todrive <ToDriveAttribute>*]
        [fields <SpreadsheetFieldList>] (range <SpreadsheetRange>)* [includegriddata [<Boolean>]]
        [formatjson] [quotechar <Character>]
```

5.02.02

Added `returnidonly` to `gam <UserTypeEntity> create drivefile` that causes GAM to return just the
file ID of the created file as output. This will be useful in scripts that create a file and then
want to perform subsequent GAM command on the file. This file ID will only be valid when the return code
of the command is 0; program accordingly.
```
Linux/MacOS
fileId=`gam user user@domain.com create drivefile ... returnidonly`
Windows PowerShell
$fileId = & gam user user@domain.com create drivefile ... returnidonly`
```

5.02.01

Added `csv_output_header_drop_filter` to `gam.cfg` to allow CSV header filtering by exclusion.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Print-Filtering#column-header-filtering

Thanks to @bousquf for the following enhancement. You want to send a message from an authorized group
but a group email address can't be used in the Gmail API as the sender.

Added the option `mailbox <EmailAddress>` to `gam sendemail` to allow specifying the sender email address used in the Gmail API as different from `from <EmailAddress>`.

For example:
```
gam sendemail destination@email.com from "IT Group <group@domain.com>" mailbox user@domain.com subject "test subject" message "text body" ...
```

5.02.00

THERE IS A DEFAULT BEHAVIOR CHANGE WHEN UPDATING ATTENDEES IN EVENTS - READ CAREFULLY.

The default behavior of `gam calendar <CalendarEntity> update events` and `gam <UserTypeEntity> update events <UserCalendarEntity>`
has been changed regarding attendees. In versions of GAM before `5.02.00`, updating attendees in calendar events was complicated because you had to
supply the complete attendee list even if you just wanted incremental changes.
The default behavior now is to allow incremental changes to the attendees list;
the current attendee list is downloaded and the specified changes are applied.

The `replacemode` option invokes the previous behavior from versions before `5.02.00`; the current attendee list is replaced.

The following options have been added to allow removal of attendees:
* `clearattendees` - Clear all current attendees from the attendee list
* `removeattendee <EmailAddress>` - Remove a single attendee from the attendee list
* `selectremoveattendees <UserTypeEntity>` - Remove a selected collection of attendees from the attendee list

Added option `replacedescription <RegularExpression> <String>` to the same `update events` commands. This allows you to make changes
to the event description rather than re-entering it. The option can be repeated to make several changes.

Updated option `query <QueryDriveFile>` in `gam print filelist|filecounts|filetree` to avoid a potential problem.
In these commands, the default query is `'me' in owners`; when you specify `query "query-clause"`, they are combined with
`and` resulting in `'me' in owners and query-clause`. OK so far. If, however, you specify `query "query-clause or query-clause"`,
the end result is `'me' in owners and query-clause or query-clause` which almost certainly is not what you want. Now, parentheses
are used and the result is `'me' in owners and (query-clause or query-clause)`. For full control over the query,
use the `fullquery <QueryDriveFile>` option.

Added an additional service account scope `Classroom API - Profile Emails` so that student profile email addresses
are displayed in `gam print course-submissions showuserprofile`. After upgrading issue the following command
to enable this scope.
```
gam <UserTypeEntity> update serviceaccount
```

Starting from initial code from Jay, added commands to get customer and user usage reports over a date range.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Reports

5.01.09

Fixed bug that caused a trap in tag replace processing when setting a signature.

5.01.08

Added options `tdbackupsheet (id:<Number>)|<String>` and `tdcopysheet (id:<Number>)|<String>` to `<ToDriveAttribute>`.
When you're using `tdfileid <DriveFileID> tdsheet (id:<Number>)|<String> tdupdatesheet` with `todrive` to update a sheet in a spreadsheet:
* `tdbackupsheet (id:<Number>)|<String>` causes the current sheet data to be copied and pasted to another existing sheet before the sheet is updated
* `tdcopysheet (id:<Number>)|<String>` causes the updated sheet data to be copied and pasted to another existing sheet after the sheet is updated
Suppose you have a spreadsheet with sheets `Monday` ... `Friday`, `Backup Monday` ... `Backup Friday` and `Latest`.
Each day you run a report to update the current day sheet (`Tuesday`), you want to backup the data first (`Backup Tuesday`) and
you want the updated data copied to `Latest` so you don't have to remember what the day of the week is.
```
gam redirect csv - todrive tdfileid <DriveFileID> tdupdatesheet tdsheet Tuesday tdbackupsheet "Backup Tuesday" tdcopysheet "Latest" ...
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive#command-line-options

5.01.07

Handle `ERROR: 404: notFound - Requested entity was not found.` in `gam show peopleprofile`.

5.01.06

Fixed bug in `gam print course-submissions showuserprofile` that caused a trap.

5.01.05

Code cleanup for calendar event processing.

Code cleanup for course alias processing.

Added option `logdrivefileids [<Boolean>>]` to `gam create|update course copyfrom`.
This is a special purpose option added for research purposes.

5.01.04

Improved error handling when listing groups with an invalid `userKey` parameter; this is a rare event.

5.01.03

Added commands to add and remove topics to courses.
```
gam course <CourseID> create|add topic <CourseTopic>
gam course <CourseID> remove topic <CourseTopicID>
gam courses <CourseEntity> create|add topic <CourseTopicEntity>
gam courses <CourseEntity> remove topic <CourseTopicIDEntity>
```

Added option `mapsharemodestudentcopy edit|view` to `gam create|update course copyfrom`.
Drive files with `shareMode` `Each student will get a copy` don't seem to be able to be copied;
this option maps that `shareMode` to `Students can edit file` or `Students can view file`.
When this option is not used, no `shareMode` mapping is performed.

Added additional error handling to `gam create|update course copyfrom`.

Code cleanup.

5.01.02

Fixed bug in `gam create|update user` where linefeed `\n` was not properly processed in `message <String>`.

5.01.01

Added option `consolidationstrategy legacy|none` to `gam <UserTypeEntity> print|show driveactivity`; the default is `none`.
This option is only effective when option `v2` is specified.

Added option `idmapfile <FileName>|(gsheet <UserGoogleSheet>) [charset <String>] [columndelimiter <Character>] [quotechar <Character>]`
to `gam <UserTypeEntity> print|show driveactivity`.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Activity-Settings#display-drive-activity

Added option `matchfield hangoutlink <RegularExpression>` to `<EventMatchProperty>` so you can search for events with a specific Hangout Link.

Added additional error handling to `gam create|update course copyfrom`.

5.01.00

Upgraded to Python 3.8.2 and OpenSSL 1.1.1e.

Added synonyms `endtime, starttime, originalstarttime` for `end, start, originalstart` in `<EventAttribute>` and `<EventFieldName>`.

Added option `groupingstrategy driveui|none` to `gam <UserTypeEntity> print|show driveactivity`; the default is `none`.
This option is only effective when option `v2` is not specified.

Added options `allevents|combinedevents|singleevents` to `gam <UserTypeEntity> print|show driveactivity` to allow selection
of the type of events to display. The default is `combinedevents`, the only events displayed in previous versions.
This option is only effective when option `v2` is not specified.


5.00.11

Changed code to shorten the public key lifetime in `gam create|use project` to stay within a Google limit.
The old lifetime value caused this error:
```
ERROR: 400: 400 - The given public key has a lifetime of 315,446,400 seconds, which is longer than the max allowed lifetime of 315,360,000 seconds as specified in resource settings.
```

5.00.10

Google changed the `Application type` option when creating a project; previously you chose `Other`, now you choose `Desktop App`.

Fixed bug in `gam transfer drive` where action messages were incorrect.

5.00.09

Fixed issue where excessive API cache files were being generated. Issue the following command
to set the optimal API caching scheme.
```
gam select default config cache_discovery_only true no_cache false save verify
```
You should clear the gamcache folder (indicated by `cache_dir` above) after updating to this version.
Delete all files in this folder; do not delete the folder itself, just its contents.

5.00.08

Added option `tdcellwrap clip|overflow|wrap` to `todrive` options to allow specification of the
cell wrapping strategy in Google spreadsheets.

Added option `selectattendees [<AttendeeAttendance>] [<AttendeeStatus>] <UserTypeEntity>` to `<EventAttribute>`.
This simplifies adding multiple attendees to an event.

5.00.07

Fixed bug in `gam report accesstransparency|gcp` where event names were not properly passed to the API.

Fixed bug in `gam batch|tbatch|csv showcmds` where the timestamp was constant. The timestamp now shows milliseconds.

5.00.06

Fixed bug in `gam update groups <GroupEntity> update preview`` that caused a trap.

5.00.05

`gam <UserTypeEntity> print users` uses Google Directory API batches to improve performance when retrieving user data.
In some cases Google returns the following error:
```
googleapiclient.errors.HttpError: <HttpError 302 when requesting https://www.googleapis.com/batch/admin/directory_v1 returned "Found">```
```
At the moment it's not clear to me how to handle this error so I'm providing a workaround; if you experience this error
do the following:
```
gam config batch_size 1 save
```

5.00.04

Fixed bug in `gam transfer drive` that caused a trap.

5.00.03

Added commands to display Google people/person profile information.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-People-Profile

Upgraded `googleapiclient` library to `1.7.12`.

Fixed bug in `gam print groupmembers` where the `peoplelookup` option would cause an error.

5.00.02

Updated `httplib2` library to `0.17.0` and updated code to work around issue in library where uploading files > 100MB failed.

5.00.01

Updated code to account for Google API change that prevented clearing a user's recovery phone.

5.00.00

Replaced the deprecated `oauth2client` library with the `google-auth` library.
This change requires a one-time update of the client access file `oauth2.txt`; GAM will continue
to use the old version of `oauth2.txt` until you perform the update. There is a small performance
impact until the update is performed. However, you can't use the updated version of `oauth2.txt`
in prior versions of GAM; if you want to run GAM `5.00.00` and prior versions of GAM,
do not perform the update until you no longer need to run the prior versions of GAM.

If you are running any GAM version `4.85.00` or later, perform the following command
to perform the update.
```
gam oauth refresh
```
If you are running any GAM version before `4.85.00`, perform the following command
to perform the update.
```
gam oauth update
```

The following command has been deleted as it is no longer required:
```
gam oauth|oauth2 import <FileName>
```

Fixed bug in `gam <UserTypeEntity> print users` where the `issuspended` option was ignored.

Added option `limittoou <OrgUnitItem>` to `gam print users` to limit the display to those users
directly in the OU `<OrgUnitItem>`.

4.99.28

Fixed bug in `gam print filecounts` that caused a trap:
```
UnboundLocalError: local variable 'teamDriveId' referenced before assignment
```

4.99.27

In `gam print cros` you can specify the property to use for sorting results.
```
orderby <CrOSOrderByFieldName> [ascending|descending]
```
Currently, there is a Google API bug that gives erroneous results when you specify `ascending`.
Unfortunately, if you don't specify `ascending|descending`, GAM uses `ascending`.
GAM now uses `descending` as the default to avoid the bug.

4.99.26

Fixed a bug where a comment line in a GAM batch file that contained an unmatched quote caused an error.

4.99.25

When you perform `gam print users` with the following `todrive` options to update a sheet within a Google Sheets file:
`tdfileid <DriveFileID> tdsheet <SheetEntity> tdupdatesheet`
and your data includes international phone numbers that start with a plus sign, Google Sheets generates a `Formula parse error`
for those phone numbers. Use option `quoteplusphonenumbers` to have GAM add a single quote at the front
of phone numbers that begin with a plus sign to cause Google Sheets to interpret the numbers as plain text. The single
quote remains with the phone number. This option is not required when you're not updating a sheet as the error does not occur.

4.99.24

Added `hangoutsmeet` to `<EventAttribute>` so `gam calendar add event` and `gam calendar update events` can add Hangouts/Meet links
to events with having to use the `json` option.

4.99.23

Added `clearhangoutsmeet` to `<EventUpdateAttribute>` so `gam calendar update events` can remove Hangouts/Meet links from events.

4.99.22

Allow calendar events with `Hangouts/Meet` links to be created.

4.99.21

Improved performance of `gam print filelist` when `query` and `showmimetype`` options are used.

Added `explicitlytrashed` and `trashed` to `<FileTreeFieldName>` so that files/folders in the trash
can be identified in `gam print/show filetree`.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files#display-file-tree

4.99.20

Fixed error handling for invalid drive queries.

4.99.19

When processing `replace <Tag> <UserReplacement>` in HTML, avoid areas that shouldn't have GAM tags,
`<head>.*</head>' and `<script>.*</script>`.

4.99.18

Handle error in `gam print licenses` due to invalid product ID.

4.99.17

Fixed coding errors in `gam tbatch`.

4.99.16

Added `showcmds` option to `gam csv` to allow monitoring of execution processing.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Bulk-Processing

4.99.15

Instruct user to perform `gam update project` when permission is denied to access service account keys.

4.99.14

Improve error handling in `gam check serviceaccount` when checking the age of the private key in `oauth2service.json`.

4.99.13

Following Jay's lead, updated `gam check serviceaccount` to check the age of the private key in `oauth2service.json`.
GAM will warn you if the key is more than 30 days old. Google recommends rotating the key on a regular basis which
can be done with `gam update|rotate sakey`.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#update-an-existing-service-account-key

Fixed bug in `gam print/show messages` where `showlabels useronly` option was not suppressing system labels.

4.99.12

Handle `permissionDenied` error when processing delegates.

4.99.11

Updated `gam print/show messages` to display message labels and counts.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Messages-Threads#display-messagesthreads

4.99.10

Updated `gam create/update sheet` and `gam append/update sheetrange` to be able to read JSON data from
a file as well as the command line.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Spreadsheets

4.99.09

Following Jay's lead, simplified `gam create project` and `gam <UserTypeEntity> check serviceaccount`.
When creating a project, the initial screen where you entered the `Application name` and clicked `Save`
has been eliminated. The `Application name` defaults to `GAM` but you can change it with the `appname <Sring>` option.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#create-a-new-project-for-gam-authorization

When `check serviceaccount` requires you to authorize scopes, the URL that you enter now fills in
the `Client Name` and `One or More API Scopes` fields, you just click `Authorize`; you don't have to cut and paste
these values.

Updated `gam.cfg` `csv_output_row_filter` to allow range checking on counts, dates, and times.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Print-Filtering#column-row-filtering

For example, to list files a user created in the last six months of 2019:
```
gam config csv_output_row_filter "'createdTime:daterange=2019-07-01 2019-12-31'" user user@domain.com print filelist fields id,name,createdtime
```

4.99.08

Added `actioncsv` option to `gam update groups`. This will produce a CSV file with columns `group,email,role,action,message`
that shows the actions performed when updating the group.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups-Membership

4.99.07

Added error checking to handle badly-formatted oauth2.txt files.

4.99.06

Added additional options, 'chat' and `gcp`, and `jamboard` to `<ActivityApplicationName>` for `gam report` command.

4.99.05

Code cleanup.

4.99.04

Fixed bug in `gam audit uploadkey` that caused a trap.

4.99.03

Following Jay's lead, update default password encryption in `gam create/update user`.

4.99.02

Updated code to handle Directory API issue that prevents looking up the orgUnitId of OU /.
This affected `gam report` if you used the `orgunit /` option.
This affected `gam create admin <UserItem> <RoleItem> org_unit /`.

4.99.01

Updated `gam.cfg` `csv_output_row_filter` processing so that field names can contain colons.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/CSV-Print-Filtering#quoting-rules

4.99.00

Reworked code to use Python 'f' strings for most formatting; this feature was added in Python 3.6.
If you are using the source version of GAM and have Python 3.5 or lower, you cannot use this version.
There is no impact if you are using the executable version of GAM as it includes Python 3.8.1.

Added options to `gam show messages|threads` to allow downloading attachments.
```
[saveattachments [attachmentnamepattern <RegularExpression>]] [targetfolder <FilePath>] [overwrite [<Boolean>]]
```
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Messages-Threads#download-attachments

4.98.17

Fixed bug in `gam print/show matters` that caused a trap.

4.98.16

Added `fields <VaultMatterFieldNameList>` option to `gam info vaultmatter` and `gam print/show vaultmatters`.

4.98.15

Fixed bug that caused a trap in `gam print/show teamdriveacls` when `checkgroups` was used without `user <EmailAddress>`.

4.98.14

Code cleanup.

4.98.13

Verify that `tls_min_version` and `tls_max_version` in `gam .cfg` have allowble values.
```
''|tlsv1|tlsv1_0|tlsv1.0|tlsv1_1|tlsv1.1|tlsv1_2|tlsv1.2|tlsv1_3|tlsv1.3
```

4.98.12

Updated `httplib2` library from 0.13.0 to 0.16.0.

4.98.11

Updated `googleapiclient` library from 1.7.8 to 1.7.11.

4.98.10

Added additional error checking when reading JSON data from Google APIs as Google seems to be returning poorly formatted errors.
For example, "ERROR: Expecting value: line 1 column 1 (char 0)".

4.98.09

Eliminated extraneous columns generated by `gam print filelist` when there were no data rows.

4.98.08

Eliminated `admincreated` as a settable option in `gam update group`; it is read-only.

4.98.07

Fixed bug that caused a trap in `gam <UserTypeEntity> sendemail`.

Improved error reporting when GAM uses SMTP to send email.

4.98.06

Added output confirming that email was sent when using SMTP to send email.

4.98.05

Fixed bug that caused a trap in `gam update group csvkmd ...`.

4.98.04

Added ability to have GAM send email via SMTP.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Send-Email#use-smtp-to-send-messages

4.98.03

Fixed bug that caused a trap when specifying `fields <FieldsList>`.

4.98.02

Added `adminaccess|asadmin` option to `gam <UserTypeEntity> create teamdrive` so that when a Team Drive is created with restrictions,
admin access can be set if desired. Admin access must be used to set `restrictions.adminmanagedrestrictions` and the user
specified in `<UserTypeEntity>` must be a domain administrator.

4.98.01

Added new forms of commands to check Service Account scopes that are
equivalent to the old forms; the old forms are still defined.
```
New
gam check svcacct <UserTypeEntity> (scope|scopes <APIScopeURLList>)*
gam update svcacct <UserTypeEntity>

Old
gam <UserTypeEntity> check serviceaccount (scope|scopes <APIScopeURLList>)*
gam <UserTypeEntity> update serviceaccount
```

4.98.00

Added options `saname <ServiceAccountName>`, `sadisplayname <ServiceAccountDisplayName>` and `sadescription <ServiceAccountDescription>`
to `gam create/use project` to allow specification of Service Account characteristics.
```
gam create project [admin <EmailAddress>] [project <ProjectID>]
        [projectname <ProjectName>] [parent <String>]
        [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>]
        [sadescription <ServiceAccountDescription>]
gam use project [admin <EmailAddress>] [project <ProjectID>]
        [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>]
        [sadescription <ServiceAccountDescription>]
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#manage-projects

Added commands to manage Service Accounts.
```
gam create|add svcacct [<EmailAddress>] [current|gam|<ProjectID>|(filter <String>)]
        [saname <ServiceAccountName>] [sadisplayname <ServiceAccountDisplayName>]
        [sadescription <ServiceAccountDescription>]
gam delete svcacct [<EmailAddress>] [current|gam|<ProjectID>|(filter <String>)]
        (saemail <ServiceAccountEmail>)|(saname <ServiceAccountName>)|(sauniqueid <ServiceAccountUniqueID>)
gam show svcaccts [<EmailAddress>] [all|current|gam|<ProjectID>|(filter <String>)]
gam print svcaccts [<EmailAddress>] [all|current|gam|<ProjectID>|(filter <String>)]
        [todrive <ToDriveAttributes>*] [formatjson] [quotechar <Character>]
```
Note: this form of the command to add a Service Account has been replaced by the form show above:
```
gam addsvcacct project [<EmailAddress>] [current|gam|<ProjectID>|(filter <String>)]
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#manage-service-accounts

Starting from Jay's initial concept, added commands to manage Service Account keys.
```
gam create sakey [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|(localkeysize 1024|2048|4096)]
gam update sakey [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|(localkeysize 1024|2048|4096)]
gam replace sakeys [(algorithm KEY_ALG_RSA_1024|KEY_ALG_RSA_2048)|(localkeysize 1024|2048|4096)]
gam delete sakeys <ServiceAccountKeyList>+ [doit]
gam show sakeys [all|system|user]
```
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#manage-service-accounts-keys

To use these commands you must update your gam project and service account authorization.
```
gam update project
gam user user@domain.com check serviceaccount
```

4.97.20

Added options `<TeamDriveRestrictionsSubfieldName> <Boolean>` and `hide <Boolean>`
to `gam create teamdrive` so that a Team Drive can be created and have its restrictions and
visibility set in a single Gam command.
```
<TeamDriveRestrictionsSubfieldName> ::=
        restrictions.adminmanagedrestrictions|
        restrictions.copyrequireswriterpermission|
        restrictions.domainusersonly|
        restrictions.teammembersonly
gam <UserTypeEntity> create|add teamdrive <Name>
        [(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
        (<TeamDriveRestrictionsSubfieldName> <Boolean>)*
        [hide <Boolean>]
```
4.97.19

Fixed bug that caused a trap in `gam print group-members group group@example.com recursive`.

Updated `gam create/delete/update events` to not stop when a `forbidden` error occurs.

4.97.18

Added option `excludetrashed` to `gam print/show filetree` to suppress display of files in the trash.
This includes file that have been explicitly trashed and files that have been recursively trashed
from a prent folder.

4.97.17

Added options `json [charset <Charset>] <JSONData>` and `json file <FileName> [charset <Charset>]` to
`<EventAttribute>` that is used by `gam create/import/update event`. This allows the JSON data written by
`gam print events formatjson` to be used as input to these commands.

4.97.16

Thanks to Jay, the `gam create project` steps are now simpler.

4.97.15

Fixed `gam <UserTypeEntity> print teamdrives` to show `role` as in prior versions.

4.97.14

Update instructions for creating a project as Google has changed the flow slightly.

4.97.13

Added option `formatjson` to `gam print teamdriveacls`.

Added field `basicpermissions` to `<DriveFieldName>` which is equivalent to:
```
permissions.allowFileDiscovery,
permissions.deleted,
permissions.domain,
permissions.emailAddress,
permissions.expirationTime,
permissions.id,
permissions.role,
permissions.type
```
In particular, this omits these fields:
```
permissions.displayName,
permissions.permissionDetails,
permissions.photoLink,
permissions.teamDrivePermissionDetails
```
This allows you to select the essential permission fields without enumerating them. Of course,
you can specify `permissions` to get all of the fields, enumerate the specific fields you want or
specify `basicpermissions` and additional permission fields, e.g., `permissions.displayName`.

4.97.12

Added option `formatjson` to `gam print filelist`.

4.97.11

Corrected code where permissions fields were unnecessarily downloaded in `gam print filecounts/filelist/filepaths/filetree`.

4.97.10

Added option `todrive <ToDriveAttribute>*` to `redirect csv` to allow setting of `todrive` options as part of the redirect.
 If you are doing `redirect csv <FileName> multiprocess`, it is more efficient to specify `todrive <ToDriveAttribute>*` as part of
the redirect as verification of the `todrive` settings, which can invole several API calls, is done once rather than in each of the subprocesses.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive#redirect-csv

Added option `tdupdatesheet [<Boolean>]` to `todrive` options. When used with `tdfileid` and `tdsheet`,
a specific sheet within a Google spreadsheet can be updated with a `gam print todrive` command.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive#command-line-options

Added options `gsheet|csvsheet <SheetEntity>`, `charset <CharSet>` and `delimiter <Character>` options
to `gam update drivefile`. This allows updating a specifc sheet within Google spreadsheet.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files#update-files

Added options `json [charset <Charset>] <JSONData>` and `json file <FileName> [charset <Charset>]` to
`<DriveFilePermissionEntity>` and `<DriveFilePermissionIDEntity>` that are used by `gam create permissions`
and `gam delete permissions`. This allows the JSON data written by `gam print drivefileacls formatjson` to
be used as input to these commands.

Added options `<PermissionMatch>* [<PermissionMatchAction>]` to
`gam create permissions` and `gam delete permissions`. This allows you to specify which permissions
in the JSON data to process or skip.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Permission-Matches#permission-selection
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Permissions#manage-file-permissionssharing

Added options `<PermissionMatch>* [<PermissionMatchAction>]` to
`gam print/show drivefileacls`. This allows you to specify which permissions to display or skip.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Permission-Matches#permission-selection

4.97.09

Added `<RecipientEntity> ::= <EmailAddressEntity> | (select <UserTypeEntity>)` which is used in
`gam sendemail` to allow more choices in specifying recipients.
For example:
```
gam sendemail select groups sales@domain.com,marketing@domain.com from salesmgr@domain.com subject "Sales Meeting Agenda" textfile MeetingAgenda.txt
```

4.97.08

Restored support for Drive Activity API v1 in `gam print/show driveactivity`.

Setting `recoveryphone ""` in `gam update user` will now clear the user's recovery phone number.

4.97.07

Fixed bug in `gam print drivefileacls formatjson` that caused a trap.

4.97.06

Fixed bug where using `todrive` gave an inappropriate `Service not applicable/Does not exist` error.

4.97.05

Added option `excludetrashed` to `gam copy drivefile`; this prevents files/folders in the trash
from being copied.

4.97.04

In `gam copy/move drivefile`, do not copy permissions marked `deleted`.

4.97.03

Added additional Service Account scopes to `gam update serviceaccount` so that a user can be given access
to the Drive and Sheets APIs for use with `todrive` without gaining access to other user's files/sheets.
```
'Gmail API - Send Messages - including todrive'
```
* https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization

4.97.02

Fixed a bug where an `{RT}` or `{RTL}` with no closing `{/RT}` or `{/RTL}` would cause a loop.
The following sequence should end with `{/RTL}` not `{RTL}`
```
{RTL}{RT}Office: {officephone} {/RT}{RT}Mobile: {mobilephone}{/RT}<br />{RTL}
```
The unpaired item will be replaced with `ERROR(RT)` or `ERROR(RTL)` so the error can be detected.

4.97.01

Fixed a bug where a command of the following form did not use "~" as the column delimiter for outfile.csv.
```
gam redirect csv outfile.csv multiprocess columndelimiter "~" csv infile.csv gam ... print ...
```

4.97.00

Support for Drive Activity API v1 in `gam print/show driveactivity` has been dropped.

Updated `csv_output_row_filter "<FieldNameFilter>:boolean:<Boolean>"` to properly select fields
even if the field is a string rather than a Boolean; in particular, this applies to group settings.

Added command that adds additional service accounts to a project.
```
gam addsvcacct project [<EmailAddress>] [gam|<ProjectID>|(filter <String>)]
        name <ServiceAccountName> [displayname <String>]
```
Added command that allows selection of Service Account scopes.
```
gam <UserTypeEntity> update serviceaccount
```
These new commands allow you to more easily provide limited access to additional GAM users.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization

4.96.20

Handle `Too Many Requests` error when processing contacts.

4.96.19

Removed debugging code that caused `gam create resoldcustomer` to throw an exception.

4.96.18

Added the ability to select fields with `gam info/show/print vaultexport/vaulthold`.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Vault

Added optional `<UserTypeEntity>` to all `gam printer/printjob` commands to allow selection of a printer owner.
Previously, all such commands could only access printers owned by the user in `oauth2.txt`.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Printers
* https://github.com/taers232c/GAMADV-XTD3/wiki/Print-Jobs

To use this option you must update your Service Account authentication:
* `gam user user@domain.com check serviceaccount`

4.96.17

Improved/corrected `gam <UserTypeEntity> add/sync groups`.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Group-Membership

Updated `gam <UserTypeEntity> print/show groups` to include status and delivery settings.

Added command to update a user's group roles and delivery settings..
```
gam <UserTypeEntity> update groups ([<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)+
```
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Group-Membership

4.96.16

Improved/corrected `gam <UserTypeEntity> add/sync groups`.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Group-Membership

4.96.15

Added `group <GroupRole> <GroupList>` option to `gam create/update user` to add a user to groups when they are created.
For `gam update user` this only applies if `createifnotfound` is specified and the user has to be created.
```
gam create user salesmanager@domain.com firstname Sales lastname Manager ou /Staff password MakeQuota groups owner sales@domain.com groups member managers@domain.com,staff@domain.com
```

Added command to synchronize a user's group membership.
```
gam <UserTypeEntity> sync groups ([<GroupRole>] <GroupEntity>)+
```
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Group-Membership

4.96.14

Added `notfoundpassword random|<Password>` option to `gam update user` which is used in conjunction with
the `createifnotfound` option to create a user during an update.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Manage#special-case-processing-for-update-user

4.96.13

Added command to print backup verification codes to a CSV file.
```
gam <UserTypeEntity> print backupcodes|verificationcodes [todrive <ToDriveAttributes>*] [delimiter <Character>]
```

4.96.12

Handle bogus error `ERROR: 403: cannotUpdatePermission - The authenticated user does not have the required access to update the permission.`
The API generates this error when you update an ACL on a Tean Drive with its current role.
```
# Create initial ACL: succeeds
$ gam add drivefileacls teamdrive "Test TeamDrive" user testuser@domain.com role reader
User: admin@domain.com, Add 1 Drive File/Folder ACL
  User: admin@domain.com, Drive File/Folder ID: 00002YhXYo2zyUkZZZZ, Permission ID: testuser@domain.com, Added
  Test Test User
    id: 00008704419089109999
    type: user
    emailAddress: testuser@domain.com
    domain: domain.com
    role: reader
    permissionDetails:
      role: reader
      type: member
      inherited: False
    deleted: False

# Update to same role: fails
$ gam update drivefileacls teamdrive "Test TeamDrive" testuser@domain.com role reader
User: admin@domain.com, Update 1 Drive File/Folder ACL
  User: admin@domain.com, Drive File/Folder ID: 00002YhXYo2zyUkZZZZ, Update Failed: The authenticated user does not have the required access to update the permission.

# Update to new role: succeeds
$ gam update drivefileacls teamdrive "Test TeamDrive" testuser@domain.com role writer
User: admin@domain.com, Update 1 Drive File/Folder ACL
  User: admin@domain.com, Drive File/Folder ID: 00002YhXYo2zyUkZZZZ, Permission ID: 00008704419089109999, Updated
  Test Test User
    id: 00008704419089109999
    type: user
    emailAddress: testuser@domain.com
    domain: domain.com
    role: writer
    permissionDetails:
      role: writer
      type: member
      inherited: False
    deleted: False

# Update to same role: fails
$ gam update drivefileacls teamdrive "Test TeamDrive" testuser@domain.com role writer
User: admin@domain.com, Update 1 Drive File/Folder ACL
  User: admin@domain.com, Drive File/Folder ID: 00002YhXYo2zyUkZZZZ, Update Failed: The authenticated user does not have the required access to update the permission.
```

4.96.11

Updated `gam update labels merge` and `gam delete labels` to process labels in reverse hierarchial order to avoid deleting
a parent label before all of its child labels are deleted.

4.96.10

Fixed `gam update labels merge` to do special encoding of label query when finding messages to re-label.
Prior to the fix, labels containing `(` and `{` were not found.

4.96.09

Added `countsonly` option to `gam print/show contacts`; this causes Gam to display the number of contacts
but no contact details.

4.96.08

Any command line argument that starts with `teamdrive` may also be given as `shareddrive`.
shareddrive
shareddrives
shareddriveacls
shareddriveadminquery
shareddrivefilename
shareddriveid
shareddriveinfo
shareddrivename
shareddriveparent
shareddriveparentid
shareddriveparentname
shareddrivequery
shareddrivethemes

4.96.07

Use administrator access to get Shared(Team) Drive names in `gam print filelist` and `gam show fileinfo`.
This handles an exceptional case where a user has access to a file on a Shared Drive but no access to the Shared Drive itself.

4.96.06

Added `drivename` to `<DriveFieldName>`; this allows you to display Shared(Team) Drive names in `gam print filelist`
and `gam show fileinfo`. If you use `allfields` instead of a field list, use `showdrivename` to display Shared(Team) Drive names.
An additional API call is required to get each Shared(Team) Drive name; the names are cached so there is only one additional
API call per Shared(Team) Drive.

For example:
gam user user@domain.com show fileinfo name "Test File" fields id,name,driveid,drivename
gam user user@domain.com show fileinfo name "Test File" allfields showdrivename
gam user user@domain.com show fileinfo name "Test File" showdrivename
gam user user@domain.com print filelist corpora onlyteamdrives fields id,name,driveid,drivename
gam user user@domain.com print filelist corpora onlyteamdrives allfields showdrivename

When you execute a `gam print filelist` command with a query or permission match, there may be no files output;
in this case, there is only a header row: `Owner'. Subsequent gam commands to process the file will fail.

$ gam redirect csv ./Files.csv user user@domain.com print filelist query "name contains 'abcd'" fields id,name
Getting all Drive Files/Folders that match query ('me' in owners and name contains 'abcd') for user@domain.com
Got 0 Drive Files/Folders that matched query ('me' in owners and name contains 'abcd') for user@domain.com...
$ more Files.csv
Owner
$ gam csv Files.csv gam user ~Owner show fileinfo ~id permissions
Command: /Users/admin/bin/gam csv Files.csv gam user ~Owner show fileinfo >>>~id<<< permissions

ERROR: Header "id" not found in CSV headers of "Owner".
Help: Syntax in file /Users/admin/bin/gam/GamCommands.txt
Help: Documentation is at https://github.com/taers232c/GAMADV-XTD3/wiki

Now, the fields you select will be output on the header row and the subsequent command will not fail.

$ gam redirect csv ./Files.csv user user@domain.com print filelist query "name contains 'abcd'" fields id,name
Getting all Drive Files/Folders that match query ('me' in owners and name contains 'abcd') for user@domain.com
Got 0 Drive Files/Folders that matched query ('me' in owners and name contains 'abcd') for user@domain.com...
$ more Files.csv
Owner,id,name
$ gam csv Files.csv gam user ~Owner show fileinfo ~id permissions
$

If you specify `allfields`, a predefined set of headers are output.

$ gam redirect csv ./Files.csv user user@domain.com print filelist query "name contains 'abcd'" allfields
Getting all Drive Files/Folders that match query ('me' in owners and name contains 'abcd') for user@domain.com
Got 0 Drive Files/Folders that matched query ('me' in owners and name contains 'abcd') for user@domain.com...
$ more Files.csv
Owner,id,name,owners.0.emailAddress,permissions,permissions.0.allowFileDiscovery,permissions.0.deleted,permissions.0.displayName,permissions.0.domain,permissions.0.emailAddress,permissions.0.expirationTime,permissions.0.id,permissions.0.permissionDetails,permissions.0.photoLink,permissions.0.role,permissions.0.teamDrivePermissionDetails,permissions.0.type

You can also specify the headers you want in the case that there are no files selected; your script could test for this value.

$ gam redirect csv ./Files.csv user user@domain.com print filelist query "name contains 'abcd'" allfields nodataheaders "BadNews-NoData"
Getting all Drive Files/Folders that match query ('me' in owners and name contains 'abcd') for user@domain.com
Got 0 Drive Files/Folders that matched query ('me' in owners and name contains 'abcd') for user@domain.com...
$ more Files.csv
BadNews-NoData

4.96.05

Fixed `gam <CrOSTypeEntity> print cros deviceid` and `gam <UserTypeEntity> print users primaryEmail`
to not make additional/unnecessary API calls; this imprroves their performance.

4.96.04

Enhanced member matching in `gam info/print groups` and `gam print/show group-members` by allowing
matching customer IDs as well as email addresses. The API directly supports listing groups which have a specific user or group member,
but not groups that have a member of type CUSTOMER (all users in a domain). This coommand prints all groups with customer ID "C0123456"
as a member; GAM has to call the API for every group to check for the customer ID member.

gam config csv_output_row_filter "MembersCount:count>0" print groups memberemaildisplaypattern "C0123456" members


4.96.03

Code cleanup.

4.96.02

Include filename in error messages concerning file I/O errors.

4.96.01

For backwards compatibility with Basic Gam, in `gam create/update sendas`, allow a signature file to be specified as `signature|sig file <FileName> [charset <CharSet>]`.

4.96.00

Build with Python 3.8.0.

4.95.12

Added check in `gam version` to detect when a 32-bit version of GAM is running on a 64-bit version of Windows.

4.95.11

Fixed a trap that occurred when a `gam print filelist` command had a query containing {}.

4.95.10

Fixed `ERROR: Object of type UUID is not JSON serializable` error in `gam create building`.

4.95.09

Output additional license info with `gam info domain`. These values are displayed:

accounts:gsuite_basic_total_licenses
accounts:gsuite_basic_used_licenses
accounts:gsuite_enterprise_total_licenses
accounts:gsuite_enterprise_used_licenses
accounts:gsuite_unlimited_total_licenses
accounts:gsuite_unlimited_used_licenses
accounts:vault_total_licenses

4.95.08

Handle `permissionDenied` error in `gam update project`.

4.95.07
These commands have been deleted as the API is being deprecated.

gam <UserTypeEntity> arrows <Boolean>
gam <UserTypeEntity> pagesize 25|50|100
gam <UserTypeEntity> shortcuts <Boolean>
gam <UserTypeEntity> snippets <Boolean>
gam <UserTypeEntity> utf|utf8|utf-8|unicode <Boolean>
gam <UserTypeEntity> webclips <Boolean>

4.95.06

Added option `oneappperrow` to `gam print mobile`; this causes each mobile device application
to be displayed on a separate row with all of the other mobile device fields. By default,
all applications are displayed on one row which can make an excessively long field.

4.95.05

Handle `fileWriterTeamDriveMoveInDisabled` error in `gam move drivefile`.

4.95.04

Added option `types <GroupTypeList>` to `gam info group` and `gam print groups`;
only members with type in `<GroupTypeList>`will be displayed. By default, members of all types are displayed.

Added option `memberemaildisplaypattern|memberemailskippattern <RegularExpression>` to `gam info group` and `gam print groups`
to allow displaying members based on their email address.
* `memberemaildisplaypattern <RegularExpression>` - Members with email addresses that match `<RegularExpression>` will be displayed; others will not be displayed
* `memberemailskippattern <RegularExpression>` - Members with email addresses that match `<RegularExpression>` will not be displayed; others will be displayed

See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups-Manage#display-information-about-individual-groups
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups-Manage#display-information-about-multiple-groups

4.95.03

Added option `memberemaildisplaypattern|memberemailskippattern <RegularExpression>` to `gam print/show group-members`
to allow displaying members based on their email address.
* `memberemaildisplaypattern <RegularExpression>` - Members with email addresses that match `<RegularExpression>` will be displayed; others will not be displayed
* `memberemailskippattern <RegularExpression>` - Members with email addresses that match `<RegularExpression>` will not be displayed; others will be displayed
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership#display-group-membership-in-csv-format
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership#display-group-membership-in-hierarchical-format

4.95.02

Following Jay's lead, added `scope|scopes <APIScopeURLList>` option to `gam check serviceaccount`.
This allows you to enable service account access for a set of specific scopes rather than the full
set of scopes that GAM is capable of using.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization#manage-gam-service-account-access

When `no_update_check = false` in `gam.cfg` and a GAM update is available, execution will not be interrupted;
you will get a warning message on stderr: `WARNING: Version update available, Current: 4.95.01, Latest: 4.95.02`.

4.95.01

Fixed bug where lists of course aliases containing spaces were not properly parsed.

4.95.00

Added options `emailclearpattern|emailretainpattern <RegularExpression>` to `gam update groups <GroupEntity> clear`
to allow clearing members based on their email address.
* `emailclearpattern <RegularExpression>` - Members with email addresses that match `<RegularExpression>` will be cleared; others will be retained
* `emailretainpattern <RegularExpression>` - Members with email addresses that match `<RegularExpression>` will be retained; others will be cleared
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership#delete-members-from-a-group-by-role

4.94.24

Fixed `gam update groups <GroupEntity> clear` to show actual role of cleared members; previuosly, all
cleared members were displayed as MEMBER regardless of their actual role.

4.94.23

Define `<Locale>` values.

4.94.22

Fixed bug that caused trap when `gam config timezone` specified an invalid value.

Added `tdlocale <Locale>` and `tdtimezone <TimeZone>` to `<ToDriveAttribute>`.
Added `todrive_locale` and `todrive_timezone` to `gam.cfg`.
These settings are used to set Spreadsheet settings for files uploaded with `todrive`.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive

4.94.21

Added `gplus` to `<CustomerServiceName>` which is used in `gam report domain`.

4.94.20

Fixed bug in `gam project` commands that used the current ProjectID rather than the specified ProjectID
when command form `gam <Action> project <ProjectID>` was used.

4.94.19

Included `photoUrl` in `gam print/show classroomprofile`.

4.94.18

Added commands to display classroom user profiles.
gam <UserTypeEntity> print classroomprofile [todrive <ToDriveAttribute>*]
gam <UserTypeEntity> show classroomprofile

4.94.17

Added option `[admincreatedmatch <Boolean>]` to `gam print groups` and `gam print/show group-members`
to allow filtering of groups based on whether they were created by an administrator or a user.

4.94.16

Added `onerow` option to `gam print cros`. By default, when you specify a list field:
activeTimeRanges, recentUsers, deviceFiles, cpuStatusReports, diskVolumeReports, systemRamFreeReports;
there is one value of each each type per row, this allows for trivial sorting by those columns. The `onerow`
option puts all of the list field values on one row.

Added option `includederivedmembership` to `gam print/show group-members`.
This option causes the API to list indirect members of groups.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership

4.94.15

Make `unknownError - Unknown` a retryable error when making API calls to list files.

4.94.14

Added `execute <Command> <ArgumentList>` to `gam tbatch` commands. This allows you to execute
non-GAM commands in the batch.
See https://github.com/taers232c/GAMADV-XTD3/wiki/Bulk-Processing#batch-files

4.94.13

Updated `gam print/show matters` to display the email address matching the permission accountId.

4.94.12

Added `summary none|only|plus` option to `gam print filecounts` that specifies display of a summarization of file counts
across all users specified in the command.
* `none` - No summary is displayed; this is the default
* `only` - Only the summary is displayed, no individual user file counts are displayed
* `plus` - The summary is displayed in addition to the individual user file counts

4.94.11

Fixed bug that caused trap in `gam print messages showbody` when a message has no body.

4.94.10

When `show_gettings_got_nl = false` in `gam.cfg`, short `Got NN ...` lines were not completely
overwriting a longer previous line; this is fixed.

4.94.09

Changed `gam report` to show running total in `Got N Activities\Reports ...`.

4.94.08

Added `[aliasmatchpattern <RegularExpression>]` to `gam print aliases` to allow filtering
of aliases.

4.94.07

Added `types <GroupTypeList>` to `gam print/show group-members`; only members with type in `<GroupTypeList>`
will be displayed. By default, members of all types are displayed.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership

4.94.06

Handle trap when a CSV file contains a NULL byte in the header row.

4.94.05

Fixed bug in `gam sendemail` that caused a trap.

4.94.04

Following Jay's lead, added additional platform information to `gam version`.

4.94.03

Added additional client access scopes for `todrive_clientaccess`.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive#client-access

4.94.02

When `gam oauth create` is issued and `no_browser = true`, GAM indicates where the `gamoauthurl.txt` file is located
to simplify copying the long URL from the file rather than the screen. This is most useful with older versions of Command Prompt
and PowerShell which can't properly copy/paste multi line strings.

4.94.01

Fixed bug in `gam info mobile` that caused a trap.

Added `todrive_clientaccess` to `gam.cfg`. This is a special use Boolean option that allows
the `todrive` option to be used with client access rather than service account access.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive#client-access

4.94.00

Following Jay's lead, added additional validation code to `gam check serviceaccount`.

4.93.02

Added option `timeoffset` to `gam version`; this causes GAM to display the difference between
the local system time (in UTC) and Google's time (in UTC). If the difference is more than 30 seconds,
you should correct the local system time; otherwise you might Google API errors due to the time difference.

Following Jay's lead, added additional validation code to `gam check serviceaccount`.

4.93.01

Fixed bug where `charset <Charset>` option was being ignored in `redirect csv <FileName>`.
The `charset` value from `gam.cfg` was being used instead of the value set in `redirect`.
It's not typical that you would want to override the `charset` value from `gam.cfg` but it now works.

4.93.00

Added option `matterstate <MatterStateList>` to `gam print/show vaultnatters` to allow
display of Vault matters filtered by state.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault#display-vault-matters

Added option `exportstatus <ExportStatusList>` to `gam print/show vaultexports` to allow
display of Vault exports filtered by status.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Vault#display-vault-exports

Added `removedomainnostatusmembers` to `gam update group sync/clear`. This option
is used to remove members from the group that are in your domain but have no status.
These members were added to the group before the user or group that they represent was created.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership#synchronize-members-in-a-group
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership#delete-members-from-a-group-by-role

4.90.09

The CrOS device field `autoUpdateExpiration` will now be displayed as a date: `YYYY-MM-DD`.

Added options `addcontactgroup <ContactGroupItem>` and `removecontactgroup <ContactGroupItem>` to
`gam <UserTypeEntity> update contacts`. This allows you add and remove contact groups from a contact
without having to specify the entire contact group list. You can add and/or remove multiple contact
groups in a single command.

4.90.08

Allow for empty `recoveryemail` and `recoveryphone`.

4.90.07

Added code to help Windows users address `gam oauth create` issues. When you do `gam ouath create`,
the URL generated to authenticate the scopes is over 2500 characters long; Internet Explorer and Edge
can not take a URL that long on the command line and cause an error. The quick fix is to do
`gam config no_browser true oauth create` and copy/paste the long URL into the browser of your choice.
Unfortunately, older versions of Command Prompt and PowerShell don't properly copy/paste multi line strings so you're still stuck.
Now, GAM writes the long URL into the file `gamoauthurl.txt` in the folder with the GAM executable.
You can open the file with Notepad/Wordpad, do a control-A to select the text, control-C to copy the text,
start a browser and paste the URL (control-V) into the address bar. Authenticate and copy the Verification code
back to your Command Prompt/PowerShell window.

Handle traps like `TypeError: expected bytes-like object, not str` when accessing contacts and you have a proxy defined.

4.90.06

Added additional attributes to `<UserBasicAttribute>`: `recoveryemail <EmailAddress>` and `recoveryphone <string>`.
* `recoveryphone <string>` must contain a country code.
Added additional fields to `<UserFieldName>`: `recoveryemail` and `recoveryphone`.

4.90.05

Added additional fields to `<CrOSFieldName>`: `autoupdateexpiration, dockmacaddress, ethernetmacaddress0`, manufacturedate`.
`autoupdateexpiration` will be most useful with `gam print cros` as it should eliminate the need for the `guessaue` option.

4.90.04

Handle additional errors in `gam calendars <CalendarEntity> modify` and `gam <UserTypeEntity> modify calendars`.

4.90.03

Added `mobile_max_results` to `gam.cfg`; when retrieving lists of mobile devices from the API,
how many should be retrieved in each chunk. The default and maximum is 100.

4.90.02

Update `gam <UserTypeEntity> print/show groups` to handle case where a user in a group has no role.

4.90.01

Added commands to show group membership for a user. By default, all groups to which a member belongs are displayed;
you can restrict the display to those groups for which the user has a specific role. You can also restrict
the display to groups within a specific domain.
gam <UserTypeEntity> print groups [roles <GroupRoleList>] [domain <DomainName>] [todrive <ToDriveAttributes>*]
gam <UserTypeEntity> show groups [roles <GroupRoleList>] [domain <DomainName>]
For example: gam user user@domain.com show groups roles owner,manager

4.90.00

Added the `selectfilter <Section>` meta command to allow selection pf predefined CSV output filters.
The only `<VariableName>`s recognized in this `<Section>` are: `csv_output_header_filter` and `csv_output_row_filter`.
You can use this meta command by itself:
gam selectfilter LastLoginTimeFilter print users fields primaryemail,lastlogintime
You can combine the `select` and `selectfilter` meta commands:
gam select Domain1 selectfilter LastLoginTimeFilter print users fields primaryemail,lastlogintime

4.89.09

Handle inappropriate error when Gam has to update oauth2.txt after an upgrade.

4.89.08

Make GAM family (GAMADV-X, GAMADV-XTD, GAMADV-XTD3) explicit in `gam version`.

Handle an additional API error in `gam create resource`.

4.89.07

Added new forms of `gam create\use project` to allow unambiguous entry of options.
gam create project [admin <EmailAddress>] [project <ProjectID>] [parent <String>]
gam use project [admin <EmailAddress>] [project <ProjectID>]

Following Jay's suggestion, added options to `gam update\delete mobile` to allow qualifying
devices by user email address. This would typically be used when a query is performed to select devices.
Additionally, if more that one device is selected, the `doit` option must be specified.

gam update mobile <MobileEntity> action <MobileAction>
        [doit] [matchusers <UserTypeEntity>]
gam delete mobile <MobileEntity>
        [doit] [matchusers <UserTypeEntity>]

4.89.06

Add code to handle a rare API error when creating a group.
Fix segmentation fault error in Linux executables.

4.89.05

Fixed bug in `gam create project` that generated the error:
ERROR: Project: id:, Create Failed: Request contains an invalid argument.

4.89.04

Executable versions of GAMADV-XTD3 now use Python 3.7.4 and are built with PyInstaller 3.5.

Clean up windows-build.bat; rename Windows installation files:
* gamadv-xtd3-4.wx.yz-windows-x86.msi - 32 bit Windows Installer
* gamadv-xtd3-4.wx.yz-windows-x86.zip - 32 bit Windows ZIP file
* gamadv-xtd3-4.wx.yz-windows-x86-64.msi - 64 bit Windows Installer
* gamadv-xtd3-4.wx.yz-windows-x86-64.msi - 64 bit Windows ZIP file

4.89.03

Added options to `<UserTypeEntity>` to allow a greater selection of users based on suspension status:
* `all users` - All non-suspended Users, this is the existing option
* `all users_ns` - All non-suspended Users, a synonym for `all users`
* `all users_susp` - All suspended Users
* `all users_ns_susp` - All non-suspended and suspended Users

4.89.02

Added options to `gam update calattendees` to allow easier specification of multiple attendees.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events#update-calendar-event-attendees

Fixed bug that caused `gam purge evant` and `gam empty calendartrash` to fail
with error `ERROR: Parameter "sendUpdates" value "False" is not an allowed value in "[u'all', u'externalOnly', u'none']"`.

4.89.01

Added the ability to select fields in `gam print/show drivefileacls` and `gam print/show teamdriveacls`.

4.89.00

Fixed bug `gam print sheetrange` that caused a trap.

4.88.13

Update code to match changes in Vault API concerning change from Team Drive to Shared Drive.

4.88.12

Added options `region any|europe|us` and `showconfidentialmodecontent <Boolean>` to `gam create vaultexport|export matter`.
The `region any|europe|us` option requires G Suite Enterprise or G Suite Business licenses.

4.88.11

Recoded `gam create/update course`.

4.88.10

Added `countsonly` option to `gam calendar <CalendarEntity> print/show events` and
`gam <UserTypeEntity> print/show events <UserCalendarEntity>`.
This will cause Gam to print the number of events selected but no event details.

4.88.09

Fixed bug in atom library that caused `gam create\update contact` to generate an error when Unicode characters
were present in the data.

4.88.08

Updated `gam sendemail` to allow from addresses with display names.
gam sendemail user@domain.com from "Google Admin<admin@domain.com>" subject test message test

4.88.07

Following Jay's lead, simplify DNS handling in `gam update verification`.

4.88.06

Handle `sharingRateLimitExceeded` error when manipulating Drive File ACLs.

4.88.05

Fixed bug in `gam create/update user` that caused a trap when the `notify` option was used.

4.88.04

Fixed bug in atom library that caused `gam update contactphoto` to hang in infinite loop.

4.88.03

Fixed bug that caused trap in `gam print filelist countsonly'.

Added option to the `copyfrom` option used with `gam create/update course` that modifies how
coursework is copied.
* `copytopics` - Copy course topics
If topics are not copied, references to them will be deleted from class work that is copied.

To use this option you must update your Client and Service Account authentication:
* `gam oauth create` - Enable the scope `Classroom API - Course Topics`
* `gam user user@domain.com check serviceaccount`

Added command to print course topics.
gam print course-topics [todrive <ToDriveAttributes>*]
        (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
        [topicids <CourseTopicIDEntity>]
        [formatjson] [quotechar <Character>]
        [timefilter updatetime] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]

To use this command you must update your Client authentication:
* `gam oauth create` - Enable the scope `Classroom API - Course Topics`.

4.88.02

Added `replace <Tag> <UserReplacement>` to 'gam create\update user` to allow additional data to be
substituted into the subject and message if `notify <EmailAddress>` is specified.

Previously, the `gam import message` command instructed the API to check the message for spam;
the `nevercheckspam` option disabled this check. Checking the message for spam seems unnecessary,
so now the default is to disable the check; use the `checkspam` option to enable the check.

Added options to the `copyfrom` option used with `gam create/update course` that modify how
coursework is copied.
* `markpublishedasdraft` - Mark all published coursework as draft
* `removeduedate` - Remove due dates from coursework.
Improved handling of coursework fields that can't be copied; in particular, forms can't be copied.

Fixed bug in `gam show filecounts` that caused a trap.

4.88.01

When `todrive` is used, the command used to generate the CSV file is written to the file description.
Any arguments in the command that included spaces are now enclosed in quotes so that the description
can be used to reexecute the command.

4.88.00

When deleting duplicate email addresses within a contact, if any of the deleted duplicate
email addresses was marked `primary`, then the single saved email address will be marked `primary`.

4.86.12

Added commands to delete duplicate email addresses within a contact.
If the same email address appears multiple times within a contact, all but the first will be deleted.
By default, the email type (work|home|other|<String>) is ignored, all duplicates, regardless of type,
will be deleted. If `matchtype` is true, only duplicate email addresses with the same type will be deleted.
gam dedup contacts <ContactEntity>|<ContactSelection> [matchType [<Boolean>]]
gam <UserTypeEntity> dedup contacts <ContactEntity>|<UserContactSelection> [matchType [<Boolean>]]

Added command to add a draft message to a user's mailbox.
gam <UserTypeEntity> draft message (<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)*
        (header <String> <String>)*
        (textmessage|message <String>)|(textfile|file <FileName> [charset <CharSet>])
        (htmlmessage <String>)|(htmlfile <FileName> [charset <CharSet>])
        (replace <Tag> <UserReplacement>)* (attach <FileName> [charset <CharSet>])*

4.86.11

Added additional network error handling.

Added user oriented variant of `gam sendemail` command. In this variant, the message is
sent from each user in <UserTypeEntity>.
gam <UserTypeEntity> sendemail [recipient <EmailAddressEntity>] [replyto <EmailAddress>]
        [cc <EmailAddressEntity>] [bcc <EmailAddressEntity>] [singlemessage [<Boolean>]]
        [subject <String>] [message|body <String>|(file <FileName> [charset <CharSet>])]
        (replace <Tag> <String>)* [html [<Boolean>]] (attach <FileName> [charset <CharSet>])*
        [newuser <EmailAddress> firstname|givenname <String> lastname|familyname <string> password <Password>]

4.86.10

Following Jay's lead, moved the ChromeOS device Auto Update Expiration date table out of the
code and into a file: cros-aue-dates.json.

4.86.09

Fixed bug in `gam report meet` that caused a trap.

Display `mobile.securityPatchLevel` as a date/time.

4.86.08

Added code to handle `limitExceeded` error when creating aliases.

Added `notregex:<RegularExpression>` to `<FieldValueFilter>` so that `csv_output_row_filter`
can select rows where a field doesn't match `<RegularExpression>`. For example, print all users
that do not have an organization cost center value "Tech Support".
gam config csv_output_row_filter 'organizations.*costCenter:notregex:"Tech Support"' print users fields name,ou,organization

4.86.07

Handle error generated by `gam print courses/course-participants` caused by Google returning deleted courses when listing courses.

Handle trap in `gam transfer drive`.

4.86.06

Improved `gam update group sync` when the following form of the command is used:
gam update group csvkmd GroupMembers.csv keyfield group subkeyfield role datafield email sync csvdata email

Corrected Linux/Mac OS install script to properly set 'no_browser true` based on user input.

4.86.05

Added `showownedby <UserItem>` option to `gam print groups` and `gam print/show group-members` to limit
display to those groups owned by `<UserItem>`. For example:
gam print groups showownedby support@domain.com

Courtesy of Jay, updated the Auto Update Expiration date table for ChromeOS devices.

4.86.04

Fixed bug that caused a trap when `csv_output_row_filter` was used.

4.86.03

Code cleanup for `oauth2client` library calls; following Jay's suggestion, enabled OAuth 2.0 PKCE (https://www.oauth.com/oauth2-servers/pkce)
to protect tokens during authentication.

4.86.02

Added code to handle the following error: `setting tls_maximum_version requires Python 3.7 and OpenSSL 1.1 or newer`
If you get this error, you will be instructed to execute the following command:
gam config tls_max_version "" tls_min_version "" save

4.86.01

Fixed bug in `gam report <ActivityApplicationName>` that caused a trap.

4.86.00

Following Jay's lead, reformatted output of `gam report <ActivityApplicationName>` to make it more usable.

4.85.02

Fixed bug in `gam report customer` where a trap was thrown if `date` was not specified.

Enhanced `gam update group` to support more powerful membership update capabilities.
Suppose you have a CSV file (GroupMembers.csv)  with headers: group,role,email
Each row contains a group email address, member role (owner, member, manager) and a member email address.
The following command will synchronize the group membership for all groups and roles.
gam update group csvkmd GroupMembers.csv keyfield group subkeyfield role datafield email sync csvdata email

4.85.01

Fixed bug where use of `csvkmd` inside of a `gam csv` command threw a spurious error: "ERROR: CSV data already saved".

4.85.00

Due to an earlier Google limitation, GAM had to authorize Client access in two steps. That limitation has been eliminated and now GAM can authorize
Client access in one step. This change requires a one-time update of the client access file oauth2.txt. If you are running any GAM version before
`4.85.00`, perform the following command:

gam oauth update

If you have multiple sections in `gam.cfg` that reference different oauth2.txt files, perform an update on each section:

gam select aaa oauth update
gam select bbb oauth update
...

If you do not perform `gam oauth update`, it will be executed automatically on the first command entered.

Added `countsonly` option to `gam print filelist`. This produces the same output columns as
`gam print filecounts` but can be combined with the greater file selection options of `gam print filelist`.

Added `norecursion` option to `gam print filelist`; this is used with the `select <DriveFileEntityListTree>`
to prevent resursion into folders; only information about the selected folder is displayed.

Code cleanup of all `gam print commands`.

Courtesy of Jay, added the `guessaue` option to `gam info/print cros`. This option causes Gam to look up
the Auto Update Expiration date for ChromeOS devices. Two additional fields are output: `guessedAUEDate`
and `guessedAUEModel`. You should compare `model` and `guessedAUEModel` to verify that the proper date has been
determined.
See: https://support.google.com/chrome/a/answer/6220366

4.83.14

Due to a recent change to the Google Cloud console, it's no longer necessary to enable Domain-wide delegation
for service accounts when creating a project; those steps have been removed from `gam create project`.

4.83.13

Fixed Python 3 issue that caused a trap when `ziptostdout` was used with `gam download vaultexport|export`
or `targetname -` was used with `gam get drivefile`.

4.83.12

Fixed bug that caused a trap in `gam show messages` when `showattachements` was used.

4.83.11

Added `targetname <FileName>` to `gam download vaultexport|export` so that downloaded zip file has a predictable name.

4.83.10

Removed check in `gam update license` that required old and new SKUs to have the same product number.

4.83.09

The `gam sendemail`, `gam import message` and `gam insert message` commands all allow specifying attachments.
You can now optionally specify the character set for text attachments: `attach <FileName> [charset <CharSet>]`.
For example, on a PC you might say: `attach C:\Data\Attachment.txt charset latin1`.

4.83.08

Handle Google API change where `teamMembersOnly` was renamed to `driveMembersOnly`.
Gam will accept either keyword and map to `driveMembersOnly`.

4.83.07

Fixed code that generated unusable random passwords when `random password` option was used
with `gam create/update user`.

4.83.06

Handle errors when `todrive_user` doesn't have access to Google Drive or Gmail.

4.83.05

Added `norecursion` option to `gam print filelist`; this is used with the `select <DriveFileEntityListTree>`
to prevent resursion into folders; only information about the selected folder is displayed.

Added `matchfield attendeesstatus [<AttendeeAttendance>] [<AttendeeStatus>] <EmailAddressEntity>` option to
`<EventMatchProperty>`. All of the attendees in `<EmailAddressEntity>` must be present and must have the specified values.
    * `<AttendeeAttendance>` - Default is `required`
    * `<AttendanceStatus>` - Default is `needsaction`

4.83.04

Improve handling of Authentication Token Errors.

4.83.03

Fixed code that caused a trap in `gam print/show teamdrives` when `fields` was specified.
Google changed the Drive API without notice.

4.83.02

Fixed bug in `gam print courses` that caused Aliases column to be included twice.

4.83.01

Added address fields to `<BuildingAttribute>`.
<BuildingAttribute> ::=
        (address|addresslines <String>)|
        (city|locality <String>)|
        (country|regioncode <String>)|
        (description <String>)|
        (floors <FloorNameList>)|
        (id <String>)|
        (language|languageCode <Language>)|
        (latitude <Float>)|
        (longitude <Float>)|
        (name <String>)
        (state|administrativearea <String>)|
        (sublocality <String>)|
        (zipcode|postalcode <String>)

4.83.00

Added `query <String>` option to `gam print/show resources`.

Fixed bug in `redirect stderr` that would cause a trap in Windows.

Fixed bug in `redirect stdout` when used with `redirect csv` that caused messages
about `todrive` results to be deleted.

Fixed bug where `matchfield attendees` or `matchfield attendeespattern` was used to select
events and a trap was thrown when an attendee had no email address.

4.82.12

Modified the behavior of the `from` and `to` options in `gam create filter`. Previously,
if you entered `gam user user@domain.com create filter from foo.com ...`, Gam would
treat `foo.com` as an email address and, as there is no `@`, it would add `domain.com`
from `gam.cfg` yielding `foo.com@domain.com`. This prevents you from creating correct filters.
Now, Gam just passes whatever comes after `from` and `to` directly to the API unchanged.

4.82.11

`<UniqueID>` has been added to `<UserCalendarAddEntity>` and `<UserCalendarEntity>` to allow
specification of user calendars by their user, group or resource ID.

Previously (changeover date uncertain), when the Drive API was used to access a Team Drive,
it returned "Team Drive" as the name of all Team Drives; Gam would make an additional API call to get
the actual name. Now, the Drive API returns the name "Drive" for all Team Drives; Gam now
recognizes the new name and makes the additional API call to get the actual name.

4.82.10

Fixed bug in `gam update calattendees` where an attendee's optional status was not properly set.

4.82.09

Code cleanup.

Fixed bugs in encoding and processing csv_output_row_filter.

4.82.08

Handle `insufficientFilePermissions - The user does not have sufficient permissions for this file.` error
in `gam delete teamdrive`.

Handle `conflict - Conflicting requests.` error when adding/removing members to/from a group.

Added option `checkrc` to `gam version`; this will print the current and latest versions of Gam and:
* set the return code to 0 if the current version is the latest version
* set the retrun code to 1 if the current version is not the latest

Added additional option to `<CrOSTypeEntity>` that allows reading a CSV file to obtain
items that will generate deviceIds or device serial numbers.
csvdatafile cros|cros_sn|cros_ous|cros_ous_and_children
        ((<FileName>(:<FieldName>)+)|(gsheet(:<FieldName>)+ <UserGoogleSheet>)
                [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>])
        [fields <FieldNameList>]
        (matchfield|skipfield <FieldName> <RegularExpression>)*
        [delimiter <Character>]

Added additional option to `<UserTypeEntity>` that allows reading a CSV file to obtain
items that will generate user email addresses.
csvdatafile users|groups|groups_ns|groups_susp|ous|ous_ns|ous_susp|
        ous_and_children|ous_and_children_ns|ous_and_children_susp|
        courseparticipants|students|teachers
        ((<FileName>(:<FieldName>)+)|(gsheet(:<FieldName>)+ <UserGoogleSheet>)
                [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>])
        [fields <FieldNameList>]
        (matchfield|skipfield <FieldName> <RegularExpression>)*
        [delimiter <Character>]

4.82.07

Fixed bug in `gam create/use/update/delete/show/print projects` when `<EmailAddress>` was not specified.

4.82.06

Fixed bug where `gam create project` command caused a trap.

4.82.05

Fixed bug where `gam get contactphoto` command caused a trap.

4.82.04

Fixed bug where `gam printjob` command caused a trap.

4.82.03

Fixed bug where `gam update photo` generated the following error:
ERROR: Object of type 'bytes' is not JSON serializable

4.82.02

Mobile devices may have embedded newlines, encode them to avoid problems on output.

Fixed bug in `gam info teamdrive` where trap was thrown if the `hidden` field was not present.

4.82.01

Enhanced `gam <UserTypeEntity> update calattendees` to provide more options.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events#update-calendar-event-attendees

Added commands to hide and unhide Team Drives.
gam <UserTypeEntity> hide teamdrive <TeamDriveEntity>
gam <UserTypeEntity> unhide teamdrive <TeamDriveEntity>

Fixed code in `gam create user` to avoid this error:
`DeprecationWarning: the method passlib.handlers.sha2_crypt.sha512_ crypt.encrypt() is deprecated as of Passlib 1.7, and will be removed in Passlib 2.0, use .hash() instead.`

4.82.00

Added `domains|domains_ns|domains_susp <DomainNameListList>` to `<UserTypeEntity>`. For users with multiple
domains under one Customer ID, this allows selection of users from specific domains.
* `domains <DomainNameListList>` - All users
* `domains_ns <DomainNameListList>` - Non-suspended users
* `domains_susp <DomainNameListList>` - Suspended users

Added `attendeestatus [optional] [accepted|declined|needsaction|tentative] <EmailAddress>`
to `gam calendar create/update event` to allow adding an attendee with the specified status.

Added `jsonattendees [charset <Charset>] <JSONData>` and `jsonattendees file <FileName> [charset <Charset>]` arguments
to `gam calendar create/update event` to allow JSON data to be used to set event attendees.

Fixed bug in `gam report <ActivityApplictionName>` where using `start <Time>` but not `end <Time>`
caused an error: `ERROR: end None must be greater than/equal to start YYYY-MM-DDTHH:MM:SS`

Fixed bug in `gam report admin|mobile` where event names were not properly passed to the API.

Made significant code changes related to Unicode strings, there should be no visible effects.

4.70.06

Fixed bug in `gam print groups` where use of `namematchpattern` or `descriptionmatchpattern` caused a trap.

4.70.05

For consistency, replaced `otherusers` option with `nousers` option in `gam print/show calendars`.
* `noprimary` - Do not display the users's primary calendar
* `nogroups` - Do not display group calendars, email address ends in "@group.calendar.google.com"
* `noresources` - Do not display resource calendars, email address ends in "@resource.calendar.google.com"
* `nosystem` - Do not display system calendars, email address ends in "@group.v.calendar.google.com"
* `nousers` - Do not display users calendars, email address ends in `domain` value from `gam.cfg`.

4.70.04

Added `noprimary`, `nogroups`, `noresources`, `nosystem` and `otherusers` options to `gam print/show calendars`.
* `noprimary` - Do not display the users's primary calendar
* `nogroups` - Do not display group calendars, email address ends in "@group.calendar.google.com"
* `noresources` - Do not display resource calendars, email address ends in "@resource.calendar.google.com"
* `nosystem` - Do not display system calendars, email address ends in "@group.v.calendar.google.com"
* `otherusers` - Limits the selection to other user's calendars, equivalent to: `noprimary nogroups noresources nosystem`

For example, to list the calendars shared to a user by other users:
gam user user@domain.com show calendars otherusers

Added `querytime.* <Time>` option to `gam print filelist/filecounts` to allow times, usually relative,
to be substituted into the `query <QueryDriveFile>` option.
The `querytime.* <Time>` value replaces the string `#querytime.*#` in any queries.
The characters following `querytime` can be any combination of lowercase letters and numbers. This is most useful in scripts
where you can specify a relative date without having to change the script.

For example, to list all files/folders that have been modified in the last year:
gam user user@domain.com print filelist query "modifiedTime >= '#querytimelastyear#'" querytimelastyear -1y

Added `maxfiles <Integer>` option to `gam print filelist` to limit the number of files listed.
This would typically be used with `orderby` to get the oldest/newest files.

For example, to list the file with the most recent modification date:
gam user user@domain.com print filelist orderby modifiedtime descending maxfile 1

4.70.03

Added command to show a group and its parent groups in CSV format.
gam print grouptree <GroupEntity> [todrive <ToDriveAttribute>*]

4.70.02

Added command to show an indented list of a group and its parent groups.
gam show grouptree <GroupEntity>`

4.70.01

The following commands have been deleted as their respective APIs have been deprecated:
gam <UserTypeEntity> show gplusprofile
gam <UserTypeEntity> print gplusprofile [todrive <ToDriveAttribute>*]
gam update notification|notifications [(id all)|(id <NotificationID>)*] unread|read|unreadonly
gam delete notification|notifications [(id all)|(id <NotificationID>)*] [unreadonly|unread|read]
gam info notification|notifications [unread|read|unreadonly]

Improved column title sorting in `gam print` commands where there are more than 10 fields of the form: `field.N.subfield`.
N will be sorted as a number, not as text, so fields will appear in the proper order. This only applies to fields
at the top level.

4.70.00

Starting from initial code by Jay Lee, added support for the Alert Center API.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Alert-Center

To use these commands you must update your gam project and service account authorization.
gam update project
gam user user@domain.com check serviceaccount

4.65.91

Fixed bug where field names including a `_` character were flagged as incorrect in some cases.

4.65.90

Clean up error message when trying to download a file from a suspended user.

4.65.89

Added editing of JSON data in `gam create/update group` and `gam create/update user` to eliminate read-only attributes.

4.65.88

Added `json [charset <Charset>] <JSONData>` and `json file <FileName> [charset <Charset>]` arguments
to `gam create/update group` and `gam create/update user` to allow JSON data to be used to set group and user attributes.

Code and documentation cleanup.

4.65.87

Updated `gam forward` to not require a domain in `<EmailAddress>`; the value of `domain` in `gam.cfg` will be used if required.
gam <UserTypeEntity> forward <TrueValues> keep|leaveininbox|archive|delete|trash|markread <EmailAddress>

4.65.86

In `gam create/update group`, all permission role abbreviations were eliminated as they were not consistent.
* `members` - Use `all_members`
* `managers` - Use `owners_and_managers` or `managers_only` as required
* `owners` - Use `owners_and_managers` or `owners_only` as required

4.65.85

Code cleanup in `gam create/update/info group` due to corrections in Google APIs.

Fixed bug in `gam update group create/delete/sync/update/clear` where members of the form `uid:<string>` were not properly processed.

Changed the column order in `gam print group-members` to match basic GAM:
* old: id, role, group, email, type, status
* new: group, type, role, id, status, email

4.65.84

Fixed bug in `gam sendmail` where `from` argument was ignored when `newuser` argument was used.

4.65.83

Fixed bug in `gam report` where `maxactivities` argument was flagged as Invalid Argument.

4.65.82

Code and documentation cleanup.

4.65.81

Fixed bug in `gam check service account` where extra scope was being authorized.

4.65.80

Updated all commands that deal with group settings:
* https://support.google.com/a/answer/9191148
* https://drive.google.com/file/d/1-ux3z6-hcjsPbhAj_EIwS7cd_emkE-NC/view

During the transition period between March 25 2019 and May 6 2019, the new group settings are available read-only;
this will allow you to evaluate how the new merged settings will work in your environment.

Added `nodeprecated` option to `gam info/print groups` to suppress display of the variables that will become
deprecated in May when the new settings become effective.

Added `basic` option to `gam info/print groups` to select these fields for display:
`email,id,name,description,directMembersCount,aliases,nonEditableAliases,adminCreated`.

The order of the columns in the CSV file produced by `gam print groups` has been changed to aid in evaluating the new merged settings.
If you have scripts that expect the fields to be in a particular order, test to see if you have to make changes.

The variable, `print_native_names`, has been deleted from `gam.cfg`; it controlled the field names used in `gam print groups/orgs`.
Now, `gam print groups/org` will always use the native Directory API field names. If you have scripts that process the output
of these two commands, verify that they are using the native field names.

Groups:
* No longer used - Email,ID,Name,Description,DirectMembersCount,Aliases,NonEditableAliases,Admin_Created
* Native - email,id,name,description,directMembersCount,aliases,nonEditableAliases,adminCreated
Orgs:
* No longer used - Path,ID,Parent,ParentID,Name,Description,InheritanceBlocked
* Native - orgUnitPath,orgUnitId,parentOrgUnitPath,parentOrgUnitId,name,description,blockInheritance

Added `user_service_account_access_only` to `gam.cfg`. It will typically be used by consultants that do not have client access
to client domains, but only service account access to manage user content: files, messages, calendars. The default value
is false which is appropriate for almost all Gam users.

4.65.79

Added `createifnotfound` option to `gam update groups update [member|manager|owner]`. If, when attempting to update
the role of a group member, the group member is not found, this option causes Gam to add the member with the specified role.
gam update groups <GroupEntity> update [member|manager|owner] [usersonly|groupsonly] [notsuspended|suspended]
        [delivery allmail|daily|digest|none|disabled] [preview] [createifnotfound] <UserTypeEntity>

4.65.78

Reverted change introduced in 4.65.77 that indicated that `gam update drivefile` can not use the `parentid/parentname` options to change
the parents for a file/folder. This is incorrect, those options are valid; however there was a bug, now fixed, that prevented the update from succeeding.
Remember, when using this option, all existing parents are replaced by the new parent.
I apologize for the confusion.

4.65.77

Updated code and documentation to reflect that `gam update drivefile` must use the `addparents/removeparents` options
to change a file's parents; the `parentid/parentname` options are not valid.

4.65.76

Added actual API field names to `<ResourceFieldName>`:
        featureinstances|
        resourcecategory|
        resourcedescription|
        resourceemail|
        resourceid|
        resourcename|
        resourcetype|

4.65.75

Fix coding in `gam show filetree` that caused a trap.

4.65.74

Added commands to show domains and domain aliases as an indented list of keys and values.
gam show domains [formatjson]
gam show domainaliases|aliasdomains [formatjson]

Code cleanup to standardize handling of `formatjson` and `quotechar <Character>` options.

Added `skipids <DriveFileEntity>` option to `gam transfer drive` to handle special cases where you want to prevent selected files from being transferred.

4.65.73

Added command `gam print filetree` to allow that data to be output as a CSV file.

4.65.73

Added command gam print filetree to allow that data to be output as a CSV file.

4.65.72

Following a suggestion submitted by Pawel Szubert to Jay, added popimap option to gam deprovision user
that disables POP and IMAP access for a deprovisioned user.

4.65.71

Added `aggregatebydate [Boolean]` option to `gam report user` to allow data aggregation for multiple users.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Reports#user-reports

4.65.70

Added ziptostdout option to gam download vaultexport; this allows the following command structure:
gam download vaultexport <MatterItem> <ExportItem> ziptostdout | some program that consumes the Zip file
This will only be successful if there is one main Zip file in the export.

4.65.69

Added `exportsheetaspdf <String>` to `gam get drivefile` to allow downloading Google Sheets into PDF files.

* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files#download-files

4.65.68

Added `minimumfilesize <Integer>` to `gam print/show filecounts` and `gam show filetree` to allow selection of files with binary content of size >= `<Integer>`.

4.65.67

Added `minimumfilesize <Integer>` to `gam print filelist` to allow selection of files with binary content of size >= `<Integer>`.

4.65.66

Improvements to gam report commands that allow greater ability to select reports and specify dates.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Reports

4.65.65

Added date column for gam report customer.

Fixed bug in gam copy drivefile that caused the error: `ERROR: 403: fieldNotWritable -The resource body includes fields which are not directly writable.`

4.65.64

Handle additional errors in gam show fileinfo and gam print filelist.

4.65.63

Added `sendnotifications <Boolean>` option to `gam transfer calendars|seccals` for backwards compatibility with Basic GAM.

4.65.62

Enhanced <Tag> <Replace> processing to allow selection of user field keyword.
See: https://github.com/taers232c/GAMADV-X/wiki/Tag-Replace

4.65.61

Added todrive_nobrowser and todrive_noemail to gam.cfg to provide more control over whether
a browser is opened and/or an email is sent when a print command uses the todrive option.
Updated <ToDriveAttribute> to allow overriding the gam.cfg values.
<ToDriveAttribute> ::=
        (tduser <EmailAddress>)|
        (tdtitle <String>)|
        (tddescription <String>)|
        (tdsheet <String>)|
        (tdparent id:<DriveFolderID>|<DriveFolderName>)|(tdfileid <DriveFileID>)
        (tdtimestamp [<Boolean>] [tddaysoffset <Number>] [tdhoursoffset <Number])|
        (tdlocalcopy [<Boolean>])|
        (tdnobrowser [<Boolean>])|
        (tdnoemail [<Boolean>])

In prior versions of Gam, if gam.cfg/no_browser was false or tdnobrowser was not specified, a browser would be opened
and no email would be sent. If either of these values was true, no browser would be opened and an email was sent. You
got one or the other actions; now you can now control these actions independently.

IMPORTANT! When you upgrade to this version, issue the following command to set the desired actions:
gam select default config todrive_nobrowser <Boolean> todrive_noemail <Boolean> save verify

Added `targetuserfolderid <DriveFolderID>` to `gam collect orphans` to allow specifying the folder for orphans by ID.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Orphans

Fixed bug in `gam print filelist` where `showownedby others` and no `fullquery/query` caused a trap.

Added commands to print calendar settings by calendar; this will be most useful for resource calendars.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Calendars

Expanded options in `gam move drivefile` when moving the sub files/folders within the top folder, but not the top folder itself.
Previously, the following option specified this mode of operation.
* `mergewithparent [<Boolean>]` - If `<Boolean>` is True or not specified, the top folder is deleted after its sub files/folders are moved
Now, you can have the same mode of operation but retain the top folder.
* `mergewithparentretain [<Boolean>]` - If `<Boolean>` is True or not specified, the top folder is retained after its sub files/folders are moved

4.65.60

Removed return code `NO_DATA_TO_PROCESS_RC = 40` introduced in 4.65.56 as it negatively affects job scripts.

4.65.59

Added additional `matchfield` options to `<EventMatchProperty>`.
        (matchfield status <RegularExpression>)|
        (matchfield transparency <RegularExpression>)|
        (matchfield visibility <RegularExpression>)
* https://github.com/taers232c/GAMADV-XTD3/wiki/Calendars-Events#event-selection
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events#event-selection

Update code to recognize additional forms of `<DriveFileURL>`; the last two forms were not recognized.
<DriveFileURL> ::=
        https://docs.google.com/a/<DomainName>/document/d/<DriveFileID>/<String>
        https://drive.google.com/open?id=<DriveFileID>
        https://www.googleapis.com/drive/v2/files/<DriveFileID>
        https://www.googleapis.com/drive/v2/folders/<DriveFileID>

4.65.58

Added `calendar` option to `gam info/show/print resources'; this displays the calendar settings of the calendar associated with the resource.

Added the name of the printer to the output of `gam printer showacls/printacls`. For `printacls`, the column name is `printerName`.

4.65.57

Fixed bug in `gam print events` where the argument `fields attendees.responsestatus` caused an invalid argument error.

Changed processing in `gam info/delete/update drivefileacl` to not use email address from oauth2.txt in conversion of
an email address to a permission ID.

4.65.56

Added a new return code `NO_DATA_TO_PROCESS_RC = 40` that is set when a `gam csv <FileName> gam ...` command
is executed and `<FileName>` contains a header row but no data rows.

Added a new option `updateoufromgroup` to `gam update user` that allows updaing a user's OU based on their group membership.
This would typically be used when an external service creates a Google user and assigns it to a group but does not place it in an OU.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users#update-a-users-OU-based-on-group-membership

4.65.55

Skipped.

4.65.54

Set the GAM return code to (`NO_ENTITIES_FOUND = 60`) when `gam print filelist` finds no files to print.

4.65.53

Fixed bug in `gam print/show events` that caused an exception when the `matchfield` option was specified.

Added `matchfield attendeespattern <RegularExpression>` to `gam print/show events` to allow selection of events
by pattern matching against the attendee list.
For example, to print all events with any attendee with "staff" in their email address:
gam user user@domain.com print events primary matchfield attendeespattern "staff"

4.65.52

Fixed bug in `gam print users countsonly` that reported inaccurate counts.

Fixed bug in `gam print group-members` where group members with no status, typically non-domain addresses, caused an exception.

4.65.51

Fixed bug in get drivefile that caused an exception.

4.65.50

Added abreviations for options `drivefilename` and `anydrivefilename`.
* `name` = `drivefilename`
* `anyname` = `anydrivefilename`

These are equivalent:
gam user user@domain.com show fileinfo drivefilename "My File Name"
gam user user@domain.com show fileinfo name "My File Name"

4.65.49

Fixed a bug in `gam move drivefile` where source files were being copied unnecessarily
rather than simply being moved.

Improve error handling in `gam copy/move drivefile`.

4.65.48

Added `mincroscounts`, `maxcroscounts`, `minusercounts` and `maxusercounts` to `gam print orgs`.
OUs will only be displayed if the number of ChromeOS devices and/or users falls within the min/max values.
Additional columns are generated to display the number and status of ChromeOS devices and users in each OU.

Examples:
* Show all OUs with at least one user.
gam print orgs minusercount 1

* Show all OUs with no users.
gam print orgs maxusercount 0

* https://github.com/taers232c/GAMADV-XTD3/wiki/Organizational-Units#print-organizational-units

4.65.47

You can now use a user's Google Doc to supply data to Gam commands by specifying two items:
<UserGoogleDoc> ::=
        <EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity>
* gdoc <UserGoogleDoc> - Google Doc

You can now use a user's Google Sheet to supply data to Gam commands by specifying three items:
<UserGoogleSheet> ::=
        <EmailAddress> <DriveFileIDEntity>|<DriveFileNameEntity> <SheetName>
* gsheet(:<FieldName>)+ <UserGoogleSheet> - Google Sheet and field names
* gsheet <UserGoogleSheet> - Google Sheet

* https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-ChromeOS-Devices
* https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-Users
* https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-Items
* https://github.com/taers232c/GAMADV-XTD3/wiki/Bulk-Processing

Examples
Execute a Gam command on user@domain.com's Google Sheet UserSheet sheet NewUsers.
gam redirect stdout - multiprocess csv gsheet user@domain.com drivefilename UserSheet NewUsers gam info user ~primaryEmail name nogroups nolicenses

Add users to a group from a Google Sheet.
gam update group group@domain.com add members csvfile gsheet:primaryEmail user@domain.com drivefilename UserSheet NewUsers

Add users to a group from a Google Doc.
gam update group group@domain.com add members file gdoc user@domain.com drivefilename UserDoc

Execute a batch of commands from a Google Doc.
gam batch gdoc admin@domain.com drivefilename BatchSyncGroupsFromOUs

4.65.46

At Jay's suggestion changed `gam get drivefile` to allow the option `targetname -` which will output the downloaded file to stdout;
this option will be most useful in conjunction with the `csvsheet <SheetName>` option that downloads a specific sheet from a Google Sheets file.

For example, the following command downloads sheet NewUsers from Google Sheet UserSheet and then executes a gam command on that CSV file.
gam user user@domain.com get drivefile drivefilename UserSheet csvsheet NewUsers targetname - | gam redirect stdout - multiprocess csv - gam info user ~primaryEmail name nogroups nolicenses

It is equivalent to the following two commands:
gam user user@domain.com get drivefile drivefilename UserSheet csvsheet NewUsers targetname Users
gam redirect stdout - multiprocess csv Users.csv gam info user ~primaryEmail name nogroups nolicenses

* In the first command, the extension `.csv' is automatically added to the `targetname Users` file
* The `redirect stdout - multiprocess` option produces clean output from the multiple processes

4.65.45

Enhanced gam delete/update projects commands to allow more project selection options.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization

4.65.44

Added the ability to display all message headers in gam print/show messages/threads; use the headers all option.
gam <UserTypeEntity> show messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [countsonly] [headers all|<SMTPHeaderList>] [showlabels] [showbody] [showsize] [showsnippet] [showattachments [attachmentnamepattern <RegularExpression>]]
gam <UserTypeEntity> print messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [countsonly] [headers all|<SMTPHeaderList>] [showlabels] [showbody] [showsize] [showsnippet] [convertcrnl] [delimiter <Character>] [todrive <ToDriveAttribute>*]

4.65.43

Added csvsheet <SheetName> argument to gam get drivefile to allow downloading a specific sheet from a Google Sheets file in CSV format.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files#download-files

Added gam print projects command.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization

4.65.42

Correct onscreen instructions for gam create/use project to match Google admin console screens.

4.65.41

Added sync option to gam update org/orgs. A synchronize operation gets the current members in the `<OrgUnitItem>/<OrgUnitEntity>`
and a list of users from <UserTypeEntity>/<CrOSTypeEntity>:
* Members in the OU but not in <UserTypeEntity>/<CrOSTypeEntity> will be moved to OU / or the OU specified in removetoou <OrgUnitItem>
* Members in <UserTypeEntity>/<CrOSTypeEntity> but not in the OU are moved to the OU
* Members in the OU and in <UserTypeEntity>/<CrOSTypeEntity> are unaffected
Remember: think before you sync.

gam update org|ou <OrgUnitItem> sync <CrOSTypeEntity> [removetoou <OrgUnitItem>] [quickcrosmove [<Boolean>]]
gam update org|ou <OrgUnitItem> sync <UserTypeEntity> [removetoou <OrgUnitItem>]
gam update orgs|ous <OrgUnitEntity> sync <CrOSTypeEntity> [removetoou <OrgUnitItem>] [quickcrosmove [<Boolean>]]
gam update orgs|ous <OrgUnitEntity> sync <UserTypeEntity> [removetoou <OrgUnitItem>]

Starting from code supplied by Gavin Lam, added a command to allow Gam to use previously defined projects.
Added additional commands to delete and display projects.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Authorization

4.65.40

Modified gam printer create/delete to handle creating/deleting public scope ACL.
gam printer|printers <PrinterIDEntity> create print public
gam printer|printers <PrinterIDEntity> delete public

4.65.39

Improve error handling for gam info contact/gal.

4.65.38

Added peoplelookup and peoplelookupuser <EmailAddress> options to gam print group-members. When one of these options
is specified, GAM will use the People API to retrieve names for user members not in the domain. Names are not retrieved
in all cases and success is dependent on what user is used to perform the retrievals.
* peoplelookup - Use the administrator named in oauth2.txt to perform the retrievals
* peoplelookupuser <EmailAddress> - Use <EmailAddress> to perform the retrievals

To enable this feature you must perform the following commands:
gam update project
gam oauth create - Enable the People API

4.65.37

Simplified specifying Team Drive restrictions.
<TeamDriveRestrictionsFieldName> ::=
        adminmanagedrestrictions|
        copyrequireswriterpermission|
        domainusersonly|
        teammembersonly
* Previously, you had to enter: restrictions.<TeamDriveRestrictionsFieldName>
* That is still supported but now you can just enter: <TeamDriveRestrictionsFieldName>
* The following are equivalent:

gam user user@domain.com update teamdrive <TeamDriveID> restrictions.domainusersonly false
gam user user@domain.com update teamdrive <TeamDriveID> domainusersonly false

4.65.36

Fixed bug in gam print group-members where member name was not being printed when requested.

Added domain administrator access for updating basic Team Drive settings.
gam update teamdrive <TeamDriveEntity> [name <Name>]
        [(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
        [<TeamDriveRestrictionsFieldName> <Boolean>]
gam <UserTypeEntity> update teamdrive <TeamDriveEntity> [adminaccess|asadmin] [name <Name>]
        [(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
        [<TeamDriveRestrictionsFieldName> <Boolean>]

4.65.35

Updated gam report users to support new orgUnitID argument in Reports API.

gam report users|user [todrive <ToDriveAttribute>*] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
        [(user all|<UserItem>)|(orgunit|org|ou <OrgUnitPath>)|(select <UserTypeEntity>)] (filtertime.* <Time>)* [filter|filters <String>] [fields|parameters <String>]
        [maxactivities <Number>] [maxresults <Number>]

Select the users for whom information is desired.
* `user all` - All users, the default
* `user <UserItem>` - An individual user
* `orgunit|org|ou <OrgUnitPath>` - All users in the specified OU
* `select <UserTypeEntity>` - A selected collection of users, e.g., `select group staff@domain.com`

4.65.34

Added `updatenotes <String>` option to `gam update cros` to allow updating of the `notes` field while retaining the existing value.
If you specify the `updatenotes <String>` option and it contains the string `#notes#`, the existing notes value will replace `#notes#`.
This requires an additional API to get the existing value.
For example, if you have a CSV file, UpdateCrOS.csv with two columns: deviceId,notes
this command will add a new line of notes to the front of the existing notes:

gam csv UpdateCrOS.csv gam update cros ~deviceId updatenotes "~~notes~~\n#notes#"

4.65.33

Handle "Gateway Timeout" errors.

4.65.32

Added mergewithparent [<Boolean>] option to gam copy/move drivefile to allow copying/moving
the contents of a folder but not the folder itself.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Copy-Move

4.65.31

Fixed bug in gam show group-members where a group member without a status caused a trap.

4.65.30

Added fullpath option to gam print filelist. Currently, if you use the select and filepath options,
GAMADV-XTD only displays file path information back to the selected file or folder. With the fullpath option,
GAMADV-XTD will display information as far back to the root (My Drive or Team Drive) as possible.
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files

4.65.29

Google has introduced Drive Activity API v2; it adds time and action filtering and has reorganized the format of the data.
Drive Activity API v1 will be deprecated in December 2019. GAMADV-XTD supports both versions of the API.
* https://developers.google.com/drive/activity/v2/migrating
* https://developers.google.com/drive/activity/v2/reference/rest/v2/activity/query
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Activity-Settings

Code cleanup.

4.65.28

Changed code in gam undelete user to drop requirement that OUs with spaces require two levels of quoting.
For example, you only need double quotes surrounding an OU with spaces in the name.
gam undelete user user@domain.com org "/Path/To OU with Spaces"

4.65.27

Fixed bug in gam clear contacts where contacts that matched emailclearpattern <RegularExpression> lost their
contact group information.

4.65.26

Fixed bug in gam transfer calendars that caused a trap when the append option was used.

4.65.25

Made forwards a synonym for forward in the following commands:
gam <UserTypeEntity> show forward|forwards
gam <UserTypeEntity> print forward|forwards [enabledonly] [todrive <ToDriveAttribute>*]

4.65.24

Added the ability to negate the result of a permission match, this allows for more complex match criteria.
For example, `pm type group emailaddress group@domain.com em pm not type user user@domain.com em pmm and`
will select those files shared with group group@domain.com and not shared with user user@domain.com.

Previously, when a permission match was used with print filelist, all permission fields were displayed; this caused
a large number of fields to be displayed. Now, only the fields used in the match are displayed. If you want all permission
fields displayed, add `permissions` to the fields list or you can specify permissions subfields to be displayed in addition to
the match fields.

4.65.23

Handle API errors in gam print filelist/filecounts when query "'xxxyyyxx' in parents" is used and 'xxxyyyzzz' is not a valid file ID.

4.65.22

Extended permission matching to gam show filetree.

Code cleanup.

4.65.21

Code cleanup.

Added additional error handling to gam update drivefile when modifying
options restricted/viewerscancopycontent/copyrequireswriterpermission.

4.65.20

Handle additional ownership change error in gam transfer drive.

4.65.19

Added abbreviations for the permission match keywords.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files#permission-matches

4.65.18

Added tddescription <String> and tdsheet <String> to <ToDriveAttribute> to allow setting an uploaded
CSV file description and sheet name.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Todrive

Added options to print filelist/filecounts that allow selection of files based on their permissions.
For example, to see all of a user's files that are shared with anyone:
gam user user@domain.com print filelist id title permissionmatch type anyone endmatch
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files#permission-matches

4.65.17

Backed out the gam <UserTypeEntity> language <Language> language change in 4.65.11.
There seem to be three language settings for Google: Gmail, all other Google products and a User's language abilities.
* Gmail: gam <UserTypeEntity> language <Language>
* Other Google products: I don't see API support for this.
* User's language abilities: gam update user <UserTypeEntity> language <LanguageList>

4.65.16

Further extended the gam print/show filecounts commands to include the Team Drive name in the output in addition to the
Team Drive ID when the select <TeamDriveEntity> option is used.

4.65.15

Handle additional ownership change error in gam transfer drive.

4.65.14

Code cleanup.

Extended the gam print/show filecounts commands to include the Team Drive ID in the output
when the select <TeamDriveEntity> option is used. This lets you get file counts for all of
a user's Team Drives. With that output you can identify empty Team Drives.
gam redirect csv ./TeamDrives.csv user user@domain.com print teamdrives role organizer fields id,name
gam redirect csv ./TeamDriveFileCounts.csv multiprocess csv ./TeamDrives.csv gam user ~User print filecounts select teamdriveid ~id

4.65.13

Code cleanup.

Added additional error checking to gam create teamdrive to handle errors when building multiple Team Drives for a user.

4.65.12

Added options to gam transfer calendar that allow updating of calendar settings as part of the transfer.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Access

o4.65.11

Added show_api_calls_retry_data to gam.cfg. When true, Gam will display API calls retry data at the end of ececution.
This data can be used to determine if rate limiting measures should be used.

Fixed problem on Windows where a Gam command using service account access running for over an hour would throw a trap.

Previously, the command `gam <UserTypeEntity> language <Language>` used the Email Settings API; it no longer seems to function.
It has been recoded to use the Directory API and is equivalent to `gam update user <UserTypeEntity> language <Language>`.

4.65.10

Added basic rate limiting of Google API calls. Google has several quota limits, one of them is the number
of API calls per 100 seconds. Two variables have been added to gam.cfg to implement rate limiting.
* api_calls_rate_check - Should rate of Google API calls per 100 seconds be checked; default: False
* api_calls_rate_limit - Limit on number of Google API calls per 100 seconds; default: 1000; range: 100 - Unlimited

The limits applicable to your account are found on the Developers Console, IAM & admin Quotas page.

4.68.09

Add additional error handling to several calendar commands.

4.65.08

Added options to <UserCalendarAddEntity> and <UserCalendarEntity> to allow selection of calendars from courses.
All gam <UserTypeEntity> commands that reference calendars, calendar lists, calendar ACLs and calendar events can
use these options.
See:
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-List
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Access
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events

4.65.07

Added fields <EventFieldNameList> option to gam info/show/print events to allow selection of specific event fields to display.
See:
* https://github.com/taers232c/GAMADV-XTD3/wiki/Calendars-Events
* https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events

Enhanced <Tag> <Replace> processing to allow greater selection of user fields.
See:
* https://github.com/taers232c/GAMADV-XTD3/wiki/Tag-Replace

4.65.06

Added command to display Google license counts in "keyword: value" form.
gam show licenses [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)|allskus|gsuite]

Added countsonly option to gam print licenses to allow display of Google license counts in CSV form.
gam print licenses [todrive <ToDriveAttributes>*] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)|allskus|gsuite] [countsonly]

Both commands have additional options for selecting which products/SKUs to display.
* allskus - Select all Google product SKUs
* gsuite - Select G Suite products: Google-Apps and 101031

4.65.05

Handle trap caused by invalid date returned by Google Drive API.

4.65.04

Fixed an error on Windows that occurred when redirect csv filename.csv multiprocess was specified but filename.csv was locked by another process.

Added the ability to select invdividual file label fields in gam show fileinfo/gam print filelist.
The fields can be specifed with the full name or the just the portion to the right of "labels.".
This is for backwards compatibility with GAMADV-X; the actual field names are shown.
<DriveLabelsSubfieldName> ::=
        labels.modified|        # modifiedByMe
        labels.restricted|      # copyRequiresWriterPermission
        labels.starred|         # starred
        labels.trashed|         # trashed
        labels.viewed           # viewedByMe

4.65.03

Currently, when you add a delegate for a user, the delegate is enabled to access the user's mail. Google is changing the Gmail API
so that the delegate is also enabled to access the user's contacts. Existing contacts must be updated to acquire this additional access.
gam <UserTypeEntity> update delegate|delegates [<UserEntity>]
If <UserEntity> is omitted, all of a user's accepted delegates are updated.

The Gmail API appears to require an additional Service Account scope to access delegates.
Do this command; substitute a valid email address for user@domain.com.
    gam user user@domain.com check serviceaccount
You might see the following scopes fail:
  Scope: https://www.googleapis.com/auth/gmail.modify                , Checked: FAIL (10/18)

Follow the directions to authorize the Service Account scopes.

4.65.02

Added options to gam print courses/course-announcements/course-work/course-submissions to allow selection of items
created/updated/scheduled within a particular time frame.
        [timefilter creationtime|updatetime|scheduledtime] [start|starttime <Date>|<DateTime>] [end|endtime <Date>|<DateTime>]
* timefilter creationtime|updatetime|scheduledtime specifies the field to monitor: creationtime and updatetime are defined for all four course items;
  scheduledtime is defined for course-announcements and course-work.
* start|starttime <Date>|<DateTime> specifies the start of the time frame; if not specified, the time frame will be open ended at the start.
* end|endtime <Date>|<DateTime> specifies the end of the time frame; if not specified, the time frame will be open ended at the end.
For the filter to apply, timefilter and at least one of start|starttime and end|endtime must be specified.

4.65.01

The Admin Settings API was turned off on 2018/10/31; here are the changes.
gam info domain and gam info instance will no longer display these values:
    Maximum Users, Current Users, Domain Edition, Customer PIN
    SSO Enabled, SSO Signon Page, SSO Logout Page, SSO Password Page, SSO Whitelist IPs, SSO Use Domain Specific Issuer
    SSO Key Algorithm, SSO Key Format, SSO Key Modulus, SSO Key Exponent, SSO Key yValue, Full SSO Key

The following commands are no longer valid:
gam info instance logo <FileName>
gam info domain logo <FileName>
gam update instance sso_settings [enabled <Boolean>] [sign_on_uri <URI>] [sign_out_uri <URI>] [password_uri <URI>] [whitelist <CIDRnetmask>] [use_domain_specific_issuer <Boolean>]
gam update instance sso_key <FileName>
gam update instance logo <FileName>

Added options to gam create sendas to allow sendas addresses outside of your domain.
See: https://developers.google.com/gmail/api/v1/reference/users/settings/sendAs#resource
gam <UserTypeEntity> [create|add] sendas <EmailAddress> <String> [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <Tag> <UserReplacement>)*]
        [html [<Boolean>]] [replyto <EmailAddress>] [default] [treatasalias <Boolean>]
        [smtpmsa.host <SMTPHostName> smtpmsa.port 25|465|587 smtpmsa.username <UserName> smtpmsa.password <Password> [smtpmsa.securitymode none|ssl|starttls]]

4.65.00

Added delete_cleared_contacts_with_no_emails option to gam clear contacts.
A contact may contain no email addresses after matching email addresses are cleared. If you do not want to keep contacts with no
email addresses after clearing, use the delete_cleared_contacts_with_no_emails option and they will be deleted.
Contacts with no email addresses before clearing will not be affected.

User contacts may be assigned to Contact Groups or may be unassigned and appear under Other Contacts. The Contacts API
allows selection of contacts by Contact Group; in Gam you specify selectcontactgroup <ContactGroupItem>. However, the API
does not allow selection of contacts from the Other Contacts section. If you specify selectothercontacts, then GAM will select only the contacts from "Other Contacts".
<UserContactSelection> ::=
        [query <QueryContact>] [(selectcontactgroup <ContactGroupItem>)|selectothercontacts] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]

4.61.25

Fixed bug in gam print/show sites that caused a trap.

4.61.24

Fixed bug in gam print/show messages that caused a trap.

4.61.23

Updated gam print groupmembers to get delivery options for members; you must explicitly specify delivery in the fields option.
(Both delivery and delivery_settings are recognized as the field name.)
This is currently expensive, it takes a separate API call per member per group to get this data; use sparingly.
If the members list API starts to return the delivery option data, then GAM will use that and not make the per member API calls.
For example:
gam print groupmembers group testgroup fields role,group,email,type,status,delivery

Added command gam clear contacts to help clear old email addresses out of domain shared contacts and user contacts.
Typically, you would select contacts by emailmatchpattern <RegularExpression> (and optionally emailmatchtype work|home|other|<String>),
then the matching email addresses will be deleted from the contact's email list. Email addresses that don't match will be unaffected.
You can specify emailclearpattern <RegularExpression> (and optionally emailcleartype work|home|other|<String>) if you want to
clear email addresses other than the ones used to match the contacts or if you specify <ContactEntity>.

<ContactSelection> ::=
        [query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
gam clear contacts <ContactEntity>|<ContactSelection> [emailclearpattern <RegularExpression>] [emailcleartype work|home|other|<String>]
<UserContactSelection> ::=
        [query <QueryContact>] [selectcontactgroup <ContactGroupItem>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
gam <UserTypeEntity> clear contacts <ContactEntity>|<UserContactSelection> [emailclearpattern <RegularExpression>] [emailcleartype work|home|other|<String>]

For example, you want to eliminate any contact email addresses that use your company's old domain name.
First, do show contacts emailmatchpattern "<RegularExpression>" to verify that you're getting the right contacts.
Then do clear contacts emailmatchpattern "<RegularExpression>" to clear the email addresses.

gam user user@domain.com show contacts emailmatchpattern ".*@olddomain.com" fields email
gam user user@domain.com clear contacts emailmatchpattern ".*@olddomain.com"

4.61.22

Added delivery option to gam update group create/sync/update; this allows you to set the delivery option for group members.
gam update group|groups <GroupEntity> create|add [owner|manager|member] [usersonly|groupsonly] [notsuspended|suspended]
        [delivery allmail|abridged|daily|digest|none|nomail|disabled] [preview] <UserTypeEntity>
gam update group|groups <GroupEntity> sync [owner|manager|member] [usersonly|groupsonly] [addonly|removeonly] [notsuspended|suspended]
        [delivery allmail|abridged|daily|digest|none|nomail|disabled] [preview] <UserTypeEntity>
gam update group|groups <GroupEntity> update [owner|manager|member] [usersonly|groupsonly] [notsuspended|suspended]
        [delivery allmail|abridged|daily|digest|none|nomail|disabled] [preview] <UserTypeEntity>

At the moment, the Google API does not provide delivery information when you list the members of a group, you must
make a API call per member to get delivery information. The following commands will display delivery information.
gam <UserTypeEntity> info member|group-members <GroupEntity>
gam info member|group-members <UserTypeEntity> <GroupEntity>

4.61.21

Added adminaccess option to gam create classroominvitation. By default, classroom invitations are issued by
the owner of the course, the adminaccess option causes the invitations to be issued by the admin named in oauth2.txt.

4.61.20

Added support for new ChromeOS fields: cpuStatusReports, diskVolumeReports and systemRamFreeReports. These fields
are supported in gam info cros and gam print cros.

4.61.19

Fixed bug in gam create/update user where use of the crypt|sha|sha1|sha-1|md5|nohash options caused a trap.

Added error check in gam create/update group to confirm that customreplyto <EmailAddress> is specified when
replyto reply_to_custom is specified.

4.61.18

Fixed parsing bug in gam print cros command.

4.61.17

Changed the gam create/update course copyfrom option to use Service Accounts for authorization
rather than the special teacher oauth2.txt files.

You must authorize additional Service Account scopes to use gam create/update course copyfrom with the
Service Account authorizations.
Do this command; sustitute a valid email address for user@domain.com.
    gam user user@domain.com check serviceaccount
You might see the following scopes fail:
    Scope: https://www.googleapis.com/auth/classroom.announcements     , Checked: FAIL (6/17)
    Scope: https://www.googleapis.com/auth/classroom.coursework.students, Checked: FAIL (7/17)
    Scope: https://www.googleapis.com/auth/classroom.rosters           , Checked: FAIL (8/17)

Follow the directions to authorize the Service Account scopes.

The following commands have been deleted as they are no longer required.

gam <UserTypeEntity> create classroomoauth2
gam <UserTypeEntity> delete classroomoauth2
gam <UserTypeEntity> info classroomoauth2

All files named classroom-<OwnerID>-oauth2.txt in the directory specified by config_dir in gam.cfg can be deleted.

4.61.16

Updated gam create classroominvitation to send invitations as the owner of the course rather than as
the Google admin in oauth2.txt.

4.61.15

Fixed bug in gam move drivefile that threw an exception.

4.61.14

Simplify gam <UserTypeEntity> add/delete groups; handle additional errors.

4.61.13

Improved handling of Quota Exceeded errors when updating group membership.
Gam processes the members in batches and pauses between batches in order to avoid exceeding Google's quota limits. The size of the batch
is set in gam.cfg/batch_size and the pause in gam.cfg/inter_watch_wait. For each batch, if the quota rate limit is exceeded, Gam increases inter_batch_wait by .25 seconds.
You can set these values on the command line:
    gam config batch_size 20 inter_batch_wait 1 update group testgroup@domain.com add/clear/delete/sync members ...

Added command to clear(remove) students or teachers from a course. For teachers, the owner teacher will not be removed.
gam course <CourseID> clear teachers|students
gam courses <CourseEntity> clear teachers|students

Added support for Google Classroom invitations:
gam <UserTypeEntity> create classroominvitation courses <CourseEntity> [role owner|student|teacher]
        [csvformat] [todrive <ToDriveAttributes>*] [formatjson] [quotechar <Character>]
gam <UserTypeEntity> accept classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
gam <UserTypeEntity> delete classroominvitation (ids <ClassroomInvitationIDEntity>)|([courses <CourseEntity>] [role all|owner|student|teacher])
gam <UserTypeEntity> show classroominvitations [role all|owner|student|teacher]
        [formatjson]
gam <UserTypeEntity> print classroominvitations [todrive <ToDriveAttributes>*] [role all|owner|student|teacher]
        [formatjson] [quotechar <Character>]

gam show classroominvitations (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [role all|owner|student|teacher] [formatjson]
gam print classroominvitations [todrive <ToDriveAttributes>*] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [role all|owner|student|teacher] [formatjson] [quotechar <Character>]

You must authorize an additional Service Account scope to use these commands.
Do this command; sustitute a valid email address for user@domain.com.
    gam user user@domain.com check serviceaccount
You should see the following scope fail:
    Scope: https://www.googleapis.com/auth/classroom.rosters           , Checked: FAIL (6/15)

Follow the directions to authorize the Service Account scopes.

4.61.12

Added preview option to gam update group create/delete/sync/update/clear; if specified, the changes will be previewed but not executed.
gam update group|groups <GroupEntity> create|add [owner|manager|member] [usersonly|groupsonly] [notsuspended|suspended] [preview] <UserTypeEntity>
gam update group|groups <GroupEntity> delete|remove [owner|manager|member] [usersonly|groupsonly] [notsuspended|suspended] [preview] <UserTypeEntity>
gam update group|groups <GroupEntity> sync [owner|manager|member] [usersonly|groupsonly] [addonly|removeonly] [notsuspended|suspended] [preview] <UserTypeEntity>
gam update group|groups <GroupEntity> update [owner|manager|member] [usersonly|groupsonly] [notsuspended|suspended] [preview] <UserTypeEntity>
gam update group|groups <GroupEntity> clear [member] [manager] [owner] [notsuspended|suspended] [preview]

4.61.11

Fixed bug in gam update group clear members that caused a trap.

4.61.10

The Google Drive API v3 has deprecated the drive file field viewersCanCopyContent; it is now called copyRequiresWriterPermission.
The description of the copyRequiresWriterPermission field in the API documentation is:
* "Whether the options to copy, print, or download this file, should be disabled for readers and commenters."
GAM still recognizes the viewersCanCopyContent field name; n.b., the sense of the two field names is reversed:
* viewersCanCopyContent False = copyRequiresWriterPermission True
* viewersCanCopyContent True = copyRequiresWriterPermission False
GAM properly sets the value of copyRequiresWriterPermission regardless of the option used on the command line.

4.61.09

Handle rare HTTP retry error.

Fixed bug in gam copy drivefile that caused the following error:
"ERROR: 403: fieldNotWritable - The resource body includes fields which are not directly writable."

4.61.08

Added cc <EmailAddressEntity>, bcc <EmailAddressEntity> and  singlemessage <Boolean> options to gam sendemail.
gam sendemail <EmailAddressEntity> [from <UserItem>] [replyto <EmailAddress>]
        [cc <EmailAddressEntity>] [bcc <EmailAddressEntity>] [singlemessage [<Boolean>]]
        [subject <String>] [message <String>|(file <FileName> [charset <CharSet>])]
        (replace <Tag> <String>)* [html [<Boolean>]] (attach <FileName>)*
        [newuser <UserItem> firstname|givenname <String> lastname|familyname <string> password <Password>]
By default, a separate email is sent to each recipient; this isolates the recipient email addresses.
If any of these options are specified, a single email will be sent to all of the recipients:
* cc <EmailAddressEntity>
* bcc <EmailAddressEntity>
* singlemessage True

Code cleanup of exception handling.

Added checking to avoid an API bug when trying to upload a zero-length file with gam create/update drivefile.

4.61.07

Added error checking so that gam <UserTypeEntity> delete backupcodes and gam <UserTypeEntity> deprovision
do not throw a trap for a suspended user.

4.61.06

Fixed a bug in gam <UserTypeEntity> delete contacts that caused a trap for a suspended user.

4.61.05

Add ability to add attachments in gam sendemail.
    gam sendemail <EmailAddressEntity> [from <UserItem>] [replyto <EmailAddress>] [subject <String>] [message <String>|(file <FileName> [charset <CharSet>])]
        (replace <Tag> <String>)* [html [<Boolean>]] (attach <FileName>)*
        [newuser <UserItem> firstname|givenname <String> lastname|familyname <string> password <Password>]

Google is adding a new role for team drive files, see: https://gsuiteupdates.googleblog.com/ "New Content manager role coming to Team Drives"
Added fileorganizer role for team drive file permissions.
<DriveFileACLRole> ::= commenter|editor|fileorganizer|organizer|owner|reader|writer
<TeamDriveACLRole> ::= commenter|fileorganizer|organizer|reader|writer

4.61.04

Previously, Gam issued an error if the start <Time> in gam report was earlier that 180 days before today as Google would issue an error if it was.
Now, Google adjusts the start time to the earliest acceptable value so the check by Gam is unnecessary.

4.61.03

Fixed bug in gam <UserTypeEntity> print filelist select orphans that gave an invalid error message.

Added formatjson option to gam info/print mobile; added quotechar <Character> option to gam print mobile.

4.61.02

Google allows mixed-case aliases and requires the exact case when deleting an alias; allow mixed case aliases
and delete a mixed-case alias regardless of case specified on the command line.

4.61.01

Fixed bug in gam <UserTypeEntity> print users where allfields|full|basic options were ignored.

4.61.00

Fixed bug in gam print filelist where the anyowner option was ignored.

Updated gam sendemail to allow empty subjects and messages.

Enhanced all guardian commands to support a syntax similar to other commands.
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Classroom-Guardians
* Added a command to clear all guardian invitations and accepted guardians for a student.
* Added a command to sync guardians where the new set of guardians is specified in the command line
and Gam deletes any pending guardian invitations and accepted guardians that are not in the new set and sends
invitations to the members in the new set that don't have a pending invitation or have not accepted.
* Multiple guardians can be specified in create, cancel, delete and sync.
* Added formatjson option to gam show/print guardians; added quotechar <Character> option to gam print guardians.
    gam <UserTypeEntity> create|add guardian|guardianinvite|inviteguardian <GuardianEntity>
    gam <UserTypeEnfity> cancel guardianinvitation|guardianinvitations <GuardianInvitationIDEntity>
    gam <UserTypeEntity> delete guardian|guardians <GuardianEntity> [accepted|invitations|all]
    gam <UserTypeEntity> clear guardian|guardians [accepted|invitations|all]
    gam <UserTypeEntity> sync guardian|guardians <GuardianEntity>
    gam <UserTypeEntity> show guardian|guardians [accepted|invitations|all] [states <GuardianInvitationStateList>] [invitedguardian <EmailAddress>]
        [showstudentemails] [formatjson]
    gam <UserTypeEntity> print guardian|guardians [todrive <ToDriveAttribute>*] [accepted|invitations|all] [states <GuardianInvitationStateList>] [invitedguardian <EmailAddress>]
        [showstudentemails] [formatjson] [quotechar <Character>]

For example, your school SIS produces a CSV file, StudentGuardians.csv, each evening with two columns: Student,Guardian.
There is no indication as to what changes have been made from the night before. The following command will perform the necessary changes.
gam csvkmd users StudentGuardians.csv keyfield Student datafield Guardian sync guardians csvdata Guardian

Added issuspended <Boolean> option to gam print users to allow display of subsets of users based on their status.
    gam print users [todrive <ToDriveAttribute>*]
        ([domain <DomainName>] [(query <QueryUser>)|(queries <QueryUserList>)] [deleted_only|only_deleted])
        [orderby <UserOrderByFieldName> [ascending|descending]]
        [groups] [license|licenses|licence|licences] [emailpart|emailparts|username] [schemas|custom all|<SchemaNameList>]
        [userview] [basic|full|allfields | <UserFieldName>* | fields <UserFieldNameList>]
        [delimiter <Character>] [sortheaders] [formatjson] [quotechar <Character>]
        [issuspended <Boolean>]

Added notsuspended|suspended option to gam info groups to allow display of subsets of group members based on their status.
    gam info group|groups <GroupEntity> [members] [managers] [owners] [nousers|notsuspended|suspended] [quick]
        [noaliases] [groups] <GroupFieldName>* [fields <GroupFieldNameList>] [formatjson]

Added querytime.* <Time> option to gam print cros/crosactivity/mobile to allow times,
usually relative, to be substituted into the query <QueryCrOS> and queries <QueryCrOSList> options.
The querytime.* <Time> value replaces the string #querytime.*# in any queries.
The characters following quicktime can be any combination of lowercase letters and numbers.
    gam print cros [todrive <ToDriveAttribute>*]
        [(query <QueryCrOS>)|(queries <QueryCrOSList>)|(select <CrOSTypeEntity>)] [limittoou <OrgUnitItem>]
        (querytime.* <Time>)*
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [nolists|recentusers|timeranges|devicefiles] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [sortheaders] [formatjson] [quotechar <Character>]
    gam print crosactivity [todrive <ToDriveAttribute>*]
        [(query <QueryCrOS>)|(queries <QueryCrOSList>)|(select <CrOSTypeEntity>)] [limittoou <OrgUnitItem>]
        (querytime.* <Time>)*
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [recentusers] [timeranges] [both] [devicefiles] [all] [listlimit <Number>] [start <Date>] [end <Date>]
        [delimiter <Character>] [formatjson] [quotechar <Character>]

For example, to print information about CrOS devices synced more than 30 days ago:
gam print cros query "sync:..#querytime1#" querytime1 -30d

For example, to print information about CrOS devices synced in the last 30 days:
gam print cros query "sync:#querytime1#.." querytime1 -30d

For example, to print information about CrOS devices synced between 45 days ago and 30 days ago:
gam print cros query "sync:#querytime1#..#querytime2#" querytime1 -45d querytime2 -30d

Added filtertime.* <Time> option to gam report to allow times, usually relative, to be substituted into the filter <String> option.
The filtertime.* value replaces the string #filtertime.*# in the filter <String>.
The characters following filtertime can be any combination of lowercase letters and numbers.
    gam report users|user [todrive <ToDriveAttribute>*] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
        [(user all|<UserItem>)|(select <UserTypeEntity>)] (filtertime.* <Time>)* [filter|filters <String>] [fields|parameters <String>]
        [maxactivities <Number>] [maxresults <Number>]
    gam report admin|calendar|calendars|drive|docs|doc|gplus|groups|group|logins|login|mobile|rules|tokens|token [todrive <ToDriveAttribute>*] [maxresults <Number>] [maxactivities <Number>]
        [([start <Time>] [end <Time>])|yesterday] [(user all|<UserItem>)|(select <UserTypeEntity>)]
        [event <String>] (filtertime.* <Time>)* [filter|filters <String>] [ip <String>] [countsonly] [summary]

For example, this command reports on the users that haven't logged in in the last 5 years.
gam report users parameters accounts:last_login_time filters "accounts:last_login_time<#filtertime#" filtertime -5y

For example, this command reports on the users that haven't logged in in the last 30 to 60 days.
gam report users parameters accounts:last_login_time filters "accounts:last_login_time<#filtertime1# accounts:last_login_time>#filtertime2#" filtertime1 -30d filtertime2 -60d

For example, this command reports on the users that haven't ever logged in.
gam report users parameters accounts:last_login_time filters "accounts:last_login_time==#filtertime#" filtertime never

4.60.29

Fixed bug in gam print filelist where showownedby defaulted to any rather than me when the select option was used.

4.60.28

Improve error message in gam course delete teacher.

Fix errors in gam create/update course when copyfrom and workstates were combined.

4.60.27

Code/documentation cleanup for gam print cros/crosactivity. Make explicit that when then these forms of the commands are used:
    gam <CrOSTypeEntity> print cros [todrive <ToDriveAttribute>*]
    gam <CrOSTypeEntity> print crosactivity [todrive <ToDriveAttribute>*]
these options are not allowed:
    [(query <QueryCrOS>)|(queries <QueryCrOSList>)|(select <CrOSTypeEntity>)] [limittoou <OrgUnitItem>]

Added show_gettings_got_nl variable to gam.cfg to standardize the output of the "Got nnn ..." messages when getting lists of items.
Previously, some "Got nnn ..." messages were written on separate lines and other "Got nnn ..." messages overwrote the previous message on the same line.
* gam.cfg/show_gettings_got_nl = true - "Got nnn ..." messages are written on separate lines
* gam.cfg/show_gettings_got_bl = false - "Got nnn ..." messages overwrite the previous message on the same line
The default value is false.

4.60.26

Code/documentation cleanup for gam print users. Make explicit that when then this form of the command is used:
    gam <UserTypeEntity> print users
these options are not allowed:
    ([domain <DomainName>] [(query <QueryUser>)|(queries <QueryUserList>)] [deleted_only|only_deleted])|[select <UserTypeEntity>]

4.60.25

Fixed bug where user contacts and sites were not using correct SSL cacerts.pem.

4.60.24

Fixed bug in gam move drivefile that threw exception.

4.60.23

Support gam.cfg/no_verify_ssl = true for user contacts and sites to avoid this error:
Temporary error: 3 - Connection error: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)

Handle socket.error messages in non-ASCII character sets.

4.60.22

In gam move drivefile, handle error when the owner of the file being moved is not a member of the destination Team Drive.

4.60.21

In gam move drivefile, when moving directly from root (My Drive) to another location, do not attempt to delete root after the move.

In gam move drivefile, do not attempt to move files in the trash to a Team Drive.

4.60.20

Enhanced Tag Replace processing to handle instances of the form `{RT}...{Tag1}...{Tag2}...{/RT}` (multiple tags).
The instance will be eliminated if there are no replacement values for all `TagN` or if the replacement values are all empty strings.
Previously, only the form `{RT}...{Tag1}...{/RT}` (one tag) was supported.

Added new form `{RTL}...{RT}...{Tag1}...{/RT}{RT}...{Tag2}...{/RT}{/RTL}` to allow elimination of entire lines when no replacement values are supplied.
With this template: `{RTL}Phone:{RT} Office: {officephone}{/RT}{RT} Mobile: {mobilephone}{/RT}{/RTL}`
* replace officephone '' replace mobilephone '' - Entire line is eliminated
* replace officephone '123' replace mobilephone '' - Produces "Phone: Office: 123"
* replace officephone '' replace mobilephone '456' - Produces "Phone: Mobile: 456"
* replace officephone '123' replace mobilephone '456' - Produces "Phone: Office: 123 Mobile: 456"

4.60.19

Attempt to handle "ERROR: 503: transientError - Transient failure.".

The purge events and empty calendartrash commands introduced in 4.60.10 can't handle recurring events; they will be ignored by these commands.

4.60.18

Added additional formatting options for signatures and vacation reply messages.
* compact - Escape carriage returns as \r and newlines as \n in original HTML; this format produces output that can be used as input to Gam
* format - Strip HTML keywords leaving basic printable information
* html - Show original HTML; this is the default option; the output is human readable but cannot be used an input to Gam
The previous default was compact, I changed it to html to match standard Gam.

# gam <UserTypeEntity> info sendas <EmailAddressEntity> [compact|format|html]
# gam <UserTypeEntity> show sendas [compact|format|html]
# gam <UserTypeEntity> show signature|sig [compact|format|html] [primary]
# gam <UserTypeEntity> show vacation [compact|format|html] [enabledonly]

Previously, gam print/show vacation would not show details for a user's vacation settings if the responder was off; the details
are now displayed in all cases. Use the enabledonly option to display vacation settings for only those users with the responder on.

4.60.17

Added sendnotifications <Boolean> option to all commands that create or update calendar ACL; the default value is true.
Wnen true, notifications are sent to the members referenced in the <CalendarACLScopeEntity>.
gam calendar|calendars <CalendarEntity> create|add acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam calendar|calendars <CalendarEntity> update acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam calendar|calendars <CalendarEntity> create|add <CalendarACLRole> ([user] <EmailAddress>)|(group <EmailAddress>)|(domain [<DomainName>])|default [sendnotifications <Boolean>]
gam calendar|calendars <CalendarEntity> update <CalendarACLRole> ([user] <EmailAddress>)|(group <EmailAddress>)|(domain [<DomainName>])|default [sendnotifications <Boolean>]
gam resource <ResourceID> create|add acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam resource <ResourceID> update acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam resources <ResourceEntity> create|add acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam resources <ResourceEntity> update acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam <UserTypeEntity> create|add calendaracls <CalendarManageEntity> <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
gam <UserTypeEntity> update calendaracls <CalendarManageEntity> <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]

Extended gam show labels to display message/thread counts when the showcounts option is used with display basename|fullname.
Previously, showcounts was only effective when used with display allfields.

4.60.16

Updated gam whatis <EmailItem> [noinfo] to show the primary email address whenever <EmailItem> is an alias.

$ gam whatis testuser noinfo
User: testuser@domain.com
$ gam whatis testuseralias noinfo
User Alias: testuseralias@domain.com, User: testuser@domain.com
$ gam whatis testgroup noinfo
Group: testgroup@domain.com
$ gam whatis testgroupalias noinfo
Group Alias: testgroupalias@domain.com, Group: testgroup@domain.com

4.60.15

Added units of years to <Date>, <DateTime> and <Time>; a year is 365 days. Added never to <Date>, <DateTime> and <Time>.
* <Date> - never is 1970-01-01
* <DateTime> - never is 1970-01-00 00:00
* <Time> - never is 1970-01-01T00:00:00Z

<Date> ::=
        <Year>-<Month>-<Day> |
        (+|-)<Number>(d|w|y) |
        never|
        today
<DateTime> ::=
        <Year>-<Month>-<Day>(<Space>|T)<Hour>:<Minute> |
        (+|-)<Number>(m|h|d|w|y) |
        never|
        now|today
<Time> ::=
        <Year>-<Month>-<Day>(<Space>|T)<Hour>:<Minute>:<Second>[.<MilliSeconds>](Z|(+|-(<Hour>:<Minute>))) |
        (+|-)<Number>(m|h|d|w|y) |
        never|
        now|today

Added filtertime <Time> option to gam report to allow times, usually relative, to be substituted into the filter <String> option.
If both filtertime and filter are specified, the filtertime value replaces the string #filtertime# in the filter <String>.

gam report users|user [todrive <ToDriveAttribute>*] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
        [(user all|<UserItem>)|(select <UserTypeEntity>)] [filtertime <Time>] [filter|filters <String>] [fields|parameters <String>]
        [maxactivities <Number>] [maxresults <Number>]
gam report admin|calendar|calendars|drive|docs|doc|gplus|groups|group|logins|login|mobile|rules|tokens|token [todrive <ToDriveAttribute>*] [maxresults <Number>] [maxactivities <Number>]
        [([start <Time>] [end <Time>])|yesterday] [(user all|<UserItem>)|(select <UserTypeEntity>)]
        [event <String>] [filtertime <Time>] [filter|filters <String>] [ip <String>] [countsonly] [summary]

For example, this command reports on the users that haven't logged in in the last 5 years.
gam report users parameters accounts:last_login_time filters "accounts:last_login_time<#filtertime#" filtertime -5y

For example, this command reports on the users that haven't ever logged in.
gam report users parameters accounts:last_login_time filters "accounts:last_login_time==#filtertime#" filtertime never

4.60.14

Added option matchsetting to gam print groups to allow filtering of groups based on attribute values.
* matchsetting <GroupAttribute> - The group must have the specified attribute
* matchsetting not <GroupAttribute> - The group must not have the specified attribute

* You can specify multiple matchsetting options, all of them must match for the group to be displayed.
* You can specify multiple matchsetting options for the same <GroupAttribute>, it is a match if the group has any of the <GroupAttribute> values.
* You can specify multiple matchsetting not options for the same <GroupAttribute>, it is a match if the group has none of the <GroupAttribute> values.

gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] ([member <UserItem>]|[query <QueryGroup>]))|[select <GroupEntity>]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>] [descriptionmatchpattern <RegularExpression>] (matchsetting <GroupAttribute>)*
        [maxresults <Number>] [allfields|([settings] <GroupFieldName>* [fields <GroupFieldNameList>])]
        [members|memberscount] [managers|managerscount] [owners|ownerscount] [countsonly]
        [convertcrnl] [delimiter <Character>] [sortheaders] [formatjson] [quotechar <Character>]

4.60.13

Delegates are now handled by the Gmail API rather than a soon to be deprecated Email Settings API.
This simplifies the code but Google took something away in the change; delegate names are no longer
returned with the delegate email address. The shownames option has been added to cause Gam to retrieve the
delegate name; this involves an extra API call per delegate email address.

Added the csv option to show delegates for backwards compatibility with standard Gam; this displays the
same data as print delegates without the header row.

gam <UserTypeEntity> show delegates|delegate [shownames]
gam <UserTypeEntity> print delegates|delegate [todrive [<ToDriveAttribute>]] [shownames]

Revoved the <UserAttribute> admin <Boolean> that allowed Gam to promote/demote users as super administrators.
* create user admin False - This will be silently ignored
* create user admin True - This will generate an error
* update user admin False - This will generate an error
* update user admin True - This will generate an error

4.60.12

For backwards compatibility with standard GAM, when updating a Gmail label with merge, the old label will be deleted
unless the keepoldlabel option is specified.
gam <UserTypeEntity> update label|labels [search <RegularExpression>] [replace <LabelReplacement>] [merge [keepoldlabel]]

4.60.11

Fixed error in gam update labels where labels with spaces in their name or nested labels were not properly formatted for the API.
This resulted in Gam believing that no messages had the existing label, thus, when the existing label was deleted, the messages
wound up in All Mail.

Previously, when a label was merged with another label, the old label was deleted; this may not always be desired or even correct.
If you want the old label to be deleted, use the deleteoldlabel option.
gam <UserTypeEntity> update label|labels [search <RegularExpression>] [replace <LabelReplacement>] [merge [deleteoldlabel]]

4.60.10

When events are deleted from a calendar, they are moved to the calendar's trash and are only permanently deleted (purged) after 30 days.
A user signed in to Google Calendar can empty the calendar trash but there is no direct API support for this operation. Following a suggestion
here (https://stackoverflow.com/questions/41043053/how-to-empty-calendar-trash-via-google-services) commands have been added to permanently delete
calendar events. This is achieved by creating a temporary calendar, deleting the events, moving the deleted events to the temporary calendar
and then deleting the temporary calendar.

gam calendar|calendars <CalendarEntity> purge events <EventEntity> [doit] [notifyattendees]
gam <UserTypeEntity> purge events <CalendarManageEntity> <EventEntity> [doit] [notifyattendees]

Commands have been added to empty the calendar trash. This is achieved by creating a temporary calendar,
moving the deleted events to the temporary calendar and then deleting the temporary calendar.

gam calendar|calendars <CalendarEntity> empty calendartrash
gam <UserTypeEntity> empty calendartrash <CalendarEntity>

4.60.09

Fixed a bug in gam print/show filelist that would cause a trap when gam.cfg/show_gettings = False.

4.60.08

Corrected a bug in gam download vaultexport where the contents of a downloaded Zip file were extracted into the current
working directory rather than the default directory gam.cfg/drive_dir or the value specified by targetfolder <FilePath>.

4.60.07

Improve handling of files with multiple parents in gam transfer drive.

4.60.06

Worked around constraint that Google API batch requests can't take UTF characters in request_ids; this caused traps when adding Users/ChromeOS devices to OUs.

4.60.05

Fixed a backward compatibility bug where id|eventid <EventId> was not recognized as an <EventEntity>.
<EventEntity> ::=
        (id|eventid <EventId>)|(event|events <EventIdList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVSubkeySelector> | <CSVDataSelector>)|
        (<EventSelectProperties>+ <EventMatchProperties>*)

Fixed a bug where gam get drivefile could not download from a Team Drive.

4.60.04

Handle "invalid_grant: Invalid JWT: No valid verifier found for issuer." as a non-fatal error for service account access.

4.60.03

Fixed an issue in gam transfer drive where a role was not properly transferred from one non-owner to another non-owner.
Confirguration:
* Harry owns a file Test
* Tom has read access to Test
* Dick has no access to Test

Command:
gam user tom transfer drive dick

Result:
* Dick did not get read access to Test

4.60.02

Fixed bug where notsuspended option was not properly processed in gam add/sync member, this led to an incorrect error message.

4.60.01

Changed gam create vaultexport to not show the newly created item details by default; this is what gam create vaulthold/vaultmatter do.
You can display the details of gam create vaultexport/vaultexport/vaultmatter and update vaulthold with the showdetails option.

gam create vaultexport|export matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat
        (accounts <EmailAddressList>) | (orgunit|org|ou <OrgUnitPath>) | (teamdrives <TeamDriveIDList>) | (rooms <RoomList>) | everyone
        [scope <all_data|held_data|unprocessed_data>]
        [terms <String>] [start|starttime <Date>|<DateTime>] [end|endtime <Date>|<DateTime>] [timezone <TimeZone>]
        [excludedrafts <Boolean>] [format mbox|pst]
        [includerooms <Boolean>]
        [includeteamdrives <Boolean>] [driveversiondate <Date>|<DateTime>]
        [includeaccessinfo <Boolean>]
        [showdetails]

Added the terms <String>, includerooms <Boolean> and includeteamdrives <Boolean> options to gam create/update vaulthold to simplify building queries.

gam create vaulthold|hold matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat
        [(accounts|groups|users <EmailItemList>) | (orgunit|org|ou <OrgUnit>)]
        [query <QueryVaultCorpus>]
        [terms <String>] [start|starttime <Date>|<DateTime>] [end|endtime <Date>|<DateTime>]
        [includerooms <Boolean>]
        [includeteamdrives <Boolean>]
        [showdetails]
gam update vaulthold|hold <HoldItem> matter <MatterItem>
        [([addaccounts|addgroups|addusers <EmailItemList>] [removeaccounts|removegroups|removeusers <EmailItemList>]) | (orgunit|org|ou <OrgUnit>)]
        [query <QueryVaultCorpus>]
        [terms <String>] [start|starttime <Date>|<DateTime>] [end|endtime <Date>|<DateTime>]
        [includerooms <Boolean>]
        [includeteamdrives <Boolean>]
        [showdetails]

Added the sendemails <Boolean> and ccme <Boolean> options to gam create vaultmatter.

gam create|add vaultmatter|matter [name <String>] [description <string>]
        [collaborator|collaborators <EmailItemList>] [sendemails <Boolean>] [ccme <Boolean>]
        [showdetails]

4.60.00

Based on the initial work of Jay Lee, the following Vault export commands have been added.

To use these commands you must perform the following commands:
gam update project
gam oauth create

gam create vaultexport|export matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat
        (accounts <EmailAddressList>) | (orgunit|org|ou <OrgUnitPath>) | (teamdrives <TeamDriveIDList>) | (rooms <RoomList>) | everyone
        [scope <all_data|held_data|unprocessed_data>]
        [terms <String>] [start|starttime <Date>|<DateTime>] [end|endtime <Date>|<DateTime>] [timezone <TimeZone>]
        [excludedrafts <Boolean>] [format mbox|pst]
        [includerooms <Boolean>]
        [includeteamdrives <Boolean>] [driveversiondate <Date>|<DateTime>]
        [includeaccessinfo <Boolean>]
        [nodetails]
gam delete vaultexport|export <ExportItem> matter <MatterItem>
gam delete vaultexport|export <MatterItem> <ExportItem>
gam download vaultexport|export <ExportItem> matter <MatterItem> [noverify] [noextract] [targetfolder <FilePath>]
gam download vaultexport|export <MatterItem> <ExportItem> [noverify] [noextract] [targetfolder <FilePath>]
gam info vaultexport|export <ExportItem> matter <MatterItem>
gam info vaultexport|export <MatterItem> <ExportItem>
gam show vaultexports|exports [matter|matters <MatterItemList>] [shownames]
gam print vaultexports|exports [todrive [<ToDriveAttribute>]] [matter|matters <MatterItemList>] [shownames]

4.57.27

Added option filenamematchpattern <RegularExpression> to gam print/show filecounts, gam print filelist and gam show filetree
to give more powerful selection of file names than query <QueryDriveFile>. In particular, this is useful when
the select <DriveFileEntityListTree> option is used and query <QueryDriveFile> is not applicable.
For example, to list all files whose name ends in ".exe" that are in the folder named "Folder Name" and its sub-folders:
     gam user user@domain.com print filelist select drivefilename "Folder Name" filenamematchpattern ".*\.exe"
If you only want files whose name ends in ".exe" that are directly in the folder named "Folder Name":
     gam user user@domain.com print filelist select drivefilename "Folder Name" depth 0 filenamematchpattern ".*\.exe"

4.57.26

Handle situation where Google API is returning users without an Organizational Unit.

4.57.25

Update scopes to reflect Google's deprecation of https://www.googleapis.com/auth/plus.login.

4.57.24

Added option skipfield <FieldName> <RegularExpression> to options that specify CSV files: csv, csvfile, csvkmd, croscsvfile and loop.
When processing the CSV file, if <FieldName> is present and matches <RegularExpression>, the row will be skipped. You can specify
multiple skipfields, if any of them match the row will be skipped. You can specify both `matchfield <FieldName> <RegularExpression>`
and `skipfield <FieldName> <RegularExpression>` options on the same command line; the row will be skipped if any of the `matchfields`
don't match or if any of the `skipfields` do match.

The gam transfer drive command cannot process files/folders owned by a user outside of your domain, an error message is displayed for
each file/folder for which this is the case.

4.57.23

Fixed bugs in gam transfer drive that caused traps.

4.57.22

Changed `countonly` option of `gam print users` to print a CSV file with headers `domain,count` that gives the number of users
in each domain from the account, `<UserTypeEntity>` or any queries.
gam [<UserTypeEntity>] print users [todrive [<ToDriveAttribute>]]
        ([domain <DomainName>] [(query <QueryUser>)|(queries <QueryUserList>)] [deleted_only|only_deleted])|[select <UserTypeEntity>]
        [formatjson] [quotechar <Character>] [countonly]

4.57.21

Added backgroundcolor <LabelColorHex> and textcolor <LabelColorHex> options to gam create label/update labelsettings.
<LabelColorHex> ::=
        #000000|#076239|#0b804b|#149e60|#16a766|#1a764d|#1c4587|#285bac|
        #2a9c68|#3c78d8|#3dc789|#41236d|#434343|#43d692|#44b984|#4a86e8|
        #653e9b|#666666|#68dfa9|#6d9eeb|#822111|#83334c|#89d3b2|#8e63ce|
        #999999|#a0eac9|#a46a21|#a479e2|#a4c2f4|#aa8831|#ac2b16|#b65775|
        #b694e8|#b9e4d0|#c6f3de|#c9daf8|#cc3a21|#cccccc|#cf8933|#d0bcf1|
        #d5ae49|#e07798|#e4d7f5|#e66550|#eaa041|#efa093|#efefef|#f2c960|
        #f3f3f3|#f691b3|#f6c5be|#f7a7c0|#fad165|#fb4c2f|#fbc8d9|#fcda83|
        #fcdee8|#fce8b3|#fef1d1|#ffad47|#ffbc6b|#ffd6a2|#ffe6c7|#ffffff
gam <UserTypeEntity> [create|add] label|labels <String> [messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread] [buildpath [<Boolean>]]
        [backgroundcolor <LabelColorHex>] [textcolor <LabelColorHex>]
gam <UserTypeEntity> update labelsettings <LabelName> [name <String>] [messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread]
        [backgroundcolor <LabelColorHex>] [textcolor <LabelColorHex>]

Added countonly option to gam print users to allow getting a count of the number of users that match selected criteria.
gam print users countonly [domain <DomainName>] [(query <QueryUser>)|(queries <QueryUserList>)] [deleted_only|only_deleted]

4.57.20

Added commands to show the owner of a file when only the file ID or name is known. The command uses the Reports API audit activity
and may not find the owner if the file has not been accessed in 180 days.

gam show ownership <DriveFileID>|(drivefilename <DriveFileName>) [formatjson]
gam print ownership <DriveFileID>|(drivefilename <DriveFileName>) [todrive [<ToDriveAttribute>]] [formatjson] [quotechar <Character>]

4.57.19

Fixed a bug in gam create/update course where copyfrom was specified and only one of announcementstates and workstates was specified; a trap was thrown.

Fixed a bug where setting file descriptions with newlines (\n) or carriage returns (\r) improperly set them to the two character sequence '\ n' or '\ r'.

4.57.18

Fixed a bug where file descriptions containing carriage returns (\r) but not newlines (\n) were not properly displayed.

Added html [<Boolean>] option to gam sendemail and gam create/update user to allow specifying whether the email message is plain text or HTML.

Fixed a bug in gam sendemail and gam create/update user where the message file <FileName> charset <CharSet> option didn't properly handle <CharSet> leading to a trap.

4.57.17

Fixed bug whan handling error in gam create course.

4.57.16

Added copyfrom <GroupItem> to gam create/update group to allow copying of group attributes from one group to another.
The following attributes are not copied: name, description, email, admincreated, aliases, noneditablealiases.
Any <GroupAttribute> specified will override the copied attributes.

gam create|add group <EmailAddress> [copyfrom <GroupItem>] <GroupAttribute>*
gam update group|groups <GroupEntity> [admincreated <Boolean>] [email <EmailAddress>] [copyfrom <GroupItem>] <GroupAttribute>*

Added copyfrom <CourseID> [announcementstates <CourseAnnouncementStateList>] [workstates <CourseWorkStateList>] [members none|all|students|teachers]
to gam create/update course to allow copying of course announcements, work and members from one course to another.

In order for GAM to be able to copy course announcements and work, it must have a special oauth2.txt file for the course owner.
The create/update course commands will create the special oauth2.txt when executed by starting a browser to get authentication.
If this is not convenient, you can manually build the files before creating/updating the course.
These files will be created in the directory specified by config_dir in gam.cfg; they will be named classroom-<OwnerID>-oauth2.txt.

gam <UserTypeEntity> create classroomoauth2
gam <UserTypeEntity> delete classroomoauth2
gam <UserTypeEntity> info classroomoauth2

gam create|add course [id|alias <CourseAlias>] <CourseAttribute>*
        [copyfrom <CourseID> [announcementstates <CourseAnnouncementStateList>] [workstates <CourseWorkStateList>] [members none|all|students|teachers]]
gam update course <CourseID> <CourseAttribute>+
        [copyfrom <CourseID> [announcementstates <CourseAnnouncementStateList>] [workstates <CourseWorkStateList>] [members none|all|students|teachers]]
gam update courses <CourseEntity> <CourseAttribute>+
        [copyfrom <CourseID> [announcementstates <CourseAnnouncementStateList>] [workstates <CourseWorkStateList>] [members none|all|students|teachers]]

4.57.15

In gam get drivefile you can now include the strings #email#, #user# and #username# in targetfolder <FilePath> and targetname <FileName>
which will be replaced by the user's full email address or just the name portion.

4.57.14

Improved error message given when a duplicate teacher/student is added to a class.

The options name <String> and teacher <UserItem> are now required when creating a class.
Previously, name defaulted to "Unknown Course" and teacher defaulted to the admin user named in oauth2.txt.

Classes can only be deleted when they are in the ARCHIVED state; previously, to delete a class, you had to issue two gam commands:
gam update course <CourseID> state archived
gam delete course <CourseID>
Now you can optionally specify that the class should be archived as an option when deleting the class.
gam delete course <CourseID> [archived]

4.57.13

Fixed bug in gam print filepaths where extraneous data was output before header row.

4.57.12

Handle domainCannotUseApis error in gam print groupmembers.

4.57.11

Fixed bug in gam create vaultmatter collaborators <EmailItemList> that caused a trap.

4.57.10

Fixed error in gam print events formatjson where extraneous columns were included.

4.57.09

Added json <JSONData> option to <ContactAttribute>; this will allow creating/updating complex contacts.
If charset <Charset> is not specified, the value of charset from gam.cfg is assumed.
For example, to copy contacts from one user to another you could do the following:
gam redirect csv ./User1ContactGroups.csv user user1@domain.com print contactgroups full formatjson quotechar "'"
gam csv ./User1ContactGroups.csv gam user user2@domain.com create contactgroup json ~JSON
gam redirect csv ./User1Contacts.csv user user1@domain.com print contacts full formatjson quotechar "'"
gam csv ./User1Contacts.csv gam user user2@domain.com create contact json ~JSON

4.57.08

Added showprogress option to gam get drivefile which will show file download progress as a percentage.

4.57.07

Updated gam info/show drivefileacl to show deleted field.

4.57.06

Update cachetools, googleapiclient, httplib2, pyasn1, pyasn1_modules libraries.

4.57.05

If you copy a folder into its existing parent folder without specifying newfilename <DriveFileName> and duplicatefolders merge is set (the default),
the copied folder will be named 'Copy of <ExistingName>'.
For example, 'gam user user@domain.com copy drivefile drivefilename TestFolder' will copy 'TestFolder' to 'Copy of TestFolder'.

4.57.04

Corrected the error message "Add Failed: Invalid Role" to "Add Failed: Invalid Member address" when an invalid email address was used in gam update group add.

4.57.03

Added support for Collaborative Inbox Groups.
* Feature documentation: https://support.google.com/a/answer/167430?hl=en
* API documentation: https://developers.google.com/admin-sdk/groups-settings/v1/reference/groups
* GAM documentation: https://github.com/taers232c/GAMADV-XTD3/wiki/Groups

4.57.02

Extend drive filename escaping to all options:
drivefilename, anyownerdrivefilename, teamdrivefilename,
parentname, anyownerparentname, teamdriveparentname,
addparentname, addanyownerparentname, removeparentname, removeanyownerparentname,
tdparent

4.57.01

Drive filenames that contain a single quote (') or a backslash (\) have to be escaped before being passed to the Drive REST API;
otherwise, Google gives an invalid query error.` GAM now performs this escaping, you do not have to escape them on the command line.
drivefilename "Foo'Bar"
drivefilename "Foo\Bar"

Drive filenames that contain a double quote (") or open single quote (`), do not have to be escaped before being passed to the Drive REST API;
however, you may have to escape them on the command line for Gam to receive the correct value.
drivefilename "Foo\"Bar" - Linux, Mac OS
drivefilename "Foo\`Bar" - Linux, Mac OS
drivefilename "Foo\"Bar' - Command Prompt
drivefilename "Foo`Bar" - Command Prompt
drivefilename 'Foo`"Bar' - PowerShell
drivefilename 'Foo`Bar' - PowerShell

4.57.00

Rewrote gam copy/move drivefile to provide more options and more useful (in my opinion) default options.

In prior versions of Gam, if you copied a source file/folder to a target folder that contained a file/folder of the same name as the source,
a new copy with the same name was created. Now, a source file is copied only it it is newer than the target file of the same name
in the target folder. Now, a source folder and its contents are merged with the target folder of the same name. There are options that
allow you to get the prior behavior.

Read the dcomentation here (https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Copy-Move) and test before using in production.

4.56.18

Modified code to mitigate a Google API bug that causes gam update group sync member to erroneously delete owners and managers.
There is small performance cost but as Google has introduced the bug twice, it's probably worth it.

4.56.17

Allow customreplyto "" in gam create/update group to allow for an empty custom reply-to email address.

Added cros_sn/crosfile_sn/croscsvfile_sn to <CrOSEntity> and <CrOSTypeEntity> to allow specifying ChromeOS devices by serial number.
This requires an additional API call per serial number to convert it to the deviceId that is required by the API.
For example:
    gam cros_sn 01234,56789 update ou "/PathToOu"
    gam info cros cros_sn 01234,56789
<CrOSEntity> ::=
        <CrOSIDList> | (cros_sn <SerialNumberList>) |
        (query:<QueryCrOS>)|(query:orgunitpath:<OrgUnitPath>)|(query <QueryCrOS>) |
        <FileSelector> | <CSVkmdSelector>
<CrOSTypeEntity> ::=
        (all cros)|
        (cros <CrOSList>)|
        (cros_sn <SerialNumberList>)|
        (cros_ou|cros_org <OrgUnitItem>)|
        (cros_ou_and_children|cros_org_and_children <OrgUnitItem>)|
        (cros_ous|cros_orgs <OrgUnitList>)|
        (cros_ous_and_children|cros_orgs_and_children <OrgUnitList>)|
        (crosfile|crosfile_sn <FileName> [charset <Charset>] [delimiter <Character>])|
        (croscsvfile|croscsvfile_sn <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>])|
        (crosquery <QueryCrOS>)|
        (crosqueries <QueryCrOSList>)|
        (datafile cros|cros_sn|cros_ous|cros_ous_and_children
                <FileName> [charset <Charset>] [delimiter <Character>])|
        (csvkmd cros|cros_sn|cros_ous|cros_ous_and_children
                <FileName> [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>]
                keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                (matchfield <FieldName> <RegularExpression>)*
                [datafield <FieldName>(:<FieldName)* [delimiter <Character>]])|
        (croscsvdata <FieldName>(:<FieldName>*))

4.56.16

Added today and now options to date and time specifications.
<Date> ::=
        <Year>-<Month>-<Day> |
        (+|-)<Number>(d|w) |
        today
<DateTime> ::=
        <Year>-<Month>-<Day>(<Space>|T)<Hour>:<Minute> |
        (+|-)<Number>(m|h|d|w) |
        now|today
<Time> ::=
        <Year>-<Month>-<Day>(<Space>|T)<Hour>:<Minute>:<Second>[.<MilliSeconds>](Z|(+|-(<Hour>:<Minute>))) |
        (+|-)<Number>(m|h|d|w) |
        now|today
For <DateTime> and <Time>, now specifies the current hour, minute and second; today specifies zero for hour, minute and second.

Added elements to `<UserTypeEntity>` to allow specification of suspended members of groups and organization units:
    group_susp, groups_susp, group_users_susp, ou_susp, ou_and_children_susp, ous_susp, ous_and_children_susp

<UserTypeEntity> ::=
        (all users)|
        (user <UserItem>)|
        (users <UserList>)|
        (group|group_ns|group_susp <GroupItem>)|
        (groups|groups_ns|groups_susp <GroupList>)|
        (group_users|group_users_ns|group_users_susp <GroupList> [members] [managers] [owners] [primarydomain] [domains <DomainNameList>] [recursive] end)|
        (ou|ou_ns|ou_susp <OrgUnitItem>)|
        (ou_and_children|ou_and_children_ns|ou_and_children_susp <OrgUnitItem>)|
        (ous|ous_ns|ous_susp <OrgUnitList>)|
        (ous_and_children|ous_and_children_ns|ous_and_children_susp <OrgUnitList>)|
        (courseparticipants <CourseIDList>)|
        (students <CourseIDList>)|
        (teachers <CourseIDList>)|
        (license|licenses|licence|licences <SKUIDList>)|
        (file <FileName> [charset <Charset>] [delimiter <Character>])|
        (csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>])|
        (query <QueryUser>)|
        (queries <QueryUserList>)|
        (datafile users|groups|groups_ns|groups_susp|ous|ous_ns|ous_susp|ous_and_children|ous_and_children_ns|ous_and_children_susp|courseparticipants|students|teachers
                <FileName> [charset <Charset>] [delimiter <Character>])|
        (csvkmd users|groups|groups_ns_|groups_susp|ous|ous_ns|ous_susp|ous_and_children|ous_and_children_ns|ous_and_children_susp|courseparticipants|students|teachers
                <FileName> [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>]
                keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                (matchfield <FieldName> <RegularExpression>)*
                [datafield <FieldName>(:<FieldName)* [delimiter <Character>]])|
        (csvdata <FieldName>(:<FieldName>*))

Updated gam update group create/sync to allow specification of suspended users.
gam update group|groups <GroupEntity> create|add [owner|manager|member] [usersonly|groupsonly] [notsuspended|suspended] <UserTypeEntity>
gam update group|groups <GroupEntity> sync [owner|manager|member] [usersonly|groupsonly] [addonly|removeonly] [notsuspended|suspended] <UserTypeEntity>

Updated `gam update group clear` to allow specification of non-suspended users.
gam update group|groups <GroupEntity> clear [member] [manager] [owner] [notsuspended|suspended]

Updated gam info org to allow specification of suspended users.
gam info org|ou <OrgUnitItem> [nousers|notsuspended|suspended] [children|child]
gam info orgs|ous <OrgUnitEntity> [nousers|notsuspended|suspended] [children|child]

4.56.15

Added formatjson option to gam info/show/print drivefileacls; added quotechar <Character> option to gam print drivefileacls.
gam info drivefileacl <TeamDriveEntityAdmin> <DriveFilePermissionIDorEmail> [showtitles] [formatjson]
gam show drivefileacl <TeamDriveEntityAdmin> [oneitemperrow] [showtitles] [formatjson]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*
gam print drivefileacls <TeamDriveEntityAdmin> [todrive [<ToDriveAttribute>]] [oneitemperrow] [showtitles] [formatjson] [quotechar <Character>]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*
gam <UserTypeEntity> info drivefileacl <TeamDriveEntityAdmin> <DriveFilePermissionIDorEmail> [showtitles] [formatjson] adminaccess
gam <UserTypeEntity> show drivefileacl <TeamDriveEntityAdmin> [oneitemperrow] [showtitles] [formatjson]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])* adminaccess
gam <UserTypeEntity> print drivefileacls <TeamDriveEntityAdmin> [todrive [<ToDriveAttribute>]] [oneitemperrow] [showtitles] [formatjson] [quotechar <Character>]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])* adminaccess
gam <UserTypeEntity> info drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [showtitles] [formatjson]
gam <UserTypeEntity> show drivefileacl <DriveFileEntity> [oneitemperrow] [showtitles] [formatjson]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*
gam <UserTypeEntity> print drivefileacls <DriveFileEntity> [todrive [<ToDriveAttribute>]] [oneitemperrow] [showtitles] [formatjson] [quotechar <Character>]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*

4.56.14

Added commands to display information aboout a specific drive file ACL.
gam info drivefileacl <TeamDriveEntityAdmin> <DriveFilePermissionIDorEmail> [showtitles]
gam <UserTypeEntity> info drivefileacl <TeamDriveEntityAdmin> <DriveFilePermissionIDorEmail> [showtitles] adminaccess
gam <UserTypeEntity> info drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [showtitles]

4.56.13

Added descriptionmatchpattern <RegularExpression> to the following commands to allow filtering on the group description;
Gam applies this filter after downloading the groups from the API.
gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] ([member <UserItem>]|[query <QueryGroup>]))|[select <GroupEntity>]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>] [descriptionmatchpattern <RegularExpression>]
        [maxresults <Number>] [allfields|([settings] <GroupFieldName>* [fields <GroupFieldNameList>])]
        [members|memberscount] [managers|managerscount] [owners|ownerscount] [countsonly]
        [convertcrnl] [delimiter <Character>] [sortheaders] [formatjson] [quotechar <Character>]
gam print group-members [todrive [<ToDriveAttribute>]]
        [domain <DomainName>] ([member <UserItem>]|[query <QueryGroup>]))|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>] [descriptionmatchpattern <RegularExpression>]
        [roles <GroupRoleList>] [members] [managers] [owners] [membernames] <MembersFieldName>* [fields <MembersFieldNameList>]
        [userfields <UserFieldNameList>] [recursive [noduplicates]] [nogroupemail]
gam show group-members
        ([domain <DomainName>] ([member <UserItem>]|[query <QueryGroup>]))|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>] [descriptionmatchpattern <RegularExpression>]
        [roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>]

Modified gam update customer to use the patch API so that single fields of the customer address can be updated;
previously, all fields had to be specified in order to update a single field.

!4.56.12

Added query <QueryGroup> to gam print groups and gam print/show groupmembers to take advantage of API group filtering.
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups

The emailmatchpattern <RegularExpression> and namematchpattern <RegularExpression> already did filtering but this was after downloading
all groups; query <QueryGroup> does the filtering at Google but is limited to exact and prefix-only filtering.

The arguments member <UserItem> and query <QueryGroup> are mutually exclusive.

gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] ([member <UserItem>]|[query <QueryGroup>]))|[select <GroupEntity>]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>]
        [maxresults <Number>] [allfields|([settings] <GroupFieldName>* [fields <GroupFieldNameList>])]
        [members|memberscount] [managers|managerscount] [owners|ownerscount] [countsonly]
        [convertcrnl] [delimiter <Character>] [sortheaders] [formatjson] [quotechar <Character>]
gam print group-members [todrive [<ToDriveAttribute>]]
        [domain <DomainName>] ([member <UserItem>]|[query <QueryGroup>]))|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>]
        [roles <GroupRoleList>] [members] [managers] [owners] [membernames] <MembersFieldName>* [fields <MembersFieldNameList>]
        [userfields <UserFieldNameList>] [recursive [noduplicates]] [nogroupemail]
gam show group-members
        ([domain <DomainName>] ([member <UserItem>]|[query <QueryGroup>]))|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>]
        [roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>]

4.56.11

Allow empty replyto <EmailAddress> in gam create/update sendas and gam signature.

4.56.10

Added updateprimaryemail <RegularExpression> <EmailReplacement> option to gam update user to allow modifying the user's current primary email address.
For example, to change the domain of a set of users from the current domain to newdomain.com:
gam ou /Path/To/Ou update user updateprimaryemail "^(.+)@.*$" "\1@newdomain.com"
To change graduating students email addresses from flastname@domain.com to flastname_grad@domain.com:
gam ou /Path/To/Ou update user updateprimaryemail "^(.+)@(.+)$" "\1_grad@\2"
If the user's current primary email address does not match the <RegularExpression> then no modification is made.

4.56.09

Added support for License SKU G Suite Enterprise for Education.

4.56.08

Fixed bug in gam update calattendees.

4.56.07

Added delete <EmailAddress> option to gam update calattendees to allow for attendee deletion.
gam <UserTypeEntity> update calattendees <CalendarManageEntity> <EventEntity> [anyorganizer]
        [csv <FileName>] (replace <EmailAddress> <EmailAddress>)* (delete <EmailAddress>)* [doit]
For details, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Calendars-Events

Updated gam update user to be able to send a notification email when a user's password is changed.
For details, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Users

4.56.06

Fixed a parsing error in gam print/show tokens where an invalid argument was not caught.

Added countsonly option to gam print/show messages/threads that displays only the count of number of messages/threads, not any message content.
gam <UserTypeEntity> show messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [countsonly] [headers <SMTPHeaderList>] [showlabels] [showbody] [showsize] [showsnippet] [showattachments [attachmentnamepattern <RegularExpression>]]
gam <UserTypeEntity> print messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [countsonly] [headers <SMTPHeaderList>] [showlabels] [showbody] [showsize] [showsnippet] [convertcrnl] [delimiter <Character>] [todrive [<ToDriveAttribute>]]

Added formatjson argument to gam info/show calendars/calsettings/calendaracls/events/resources.
gam <UserTypeEntity> info calendars <CalendarManageEntity> [formatjson]
gam <UserTypeEntity> show calendars <CalendarPrintShowEntity> [permissions] [formatjson]
gam <UserTypeEntity> show calsettings [formatjson]
gam calendar|calendars <CalendarEntity> info calendaracls <CalendarACLScopeEntity> [formatjson]
gam calendar|calendars <CalendarEntity> show calendaracls [formatjson]
gam calendar|calendars <CalendarEntity> showacl [formatjson]
gam resource <ResourceID> info calendaracls <CalendarACLScopeEntity> [formatjson]
gam resource <ResourceID> show calendaracls [formatjson]
gam resources <ResourceEntity> info calendaracls <CalendarACLScopeEntity> [formatjson]
gam resources <ResourceEntity> show calendaracls [formatjson]
gam <UserTypeEntity> info calendaracls <CalendarManageEntity> <CalendarACLScopeEntity> [formatjson]
gam <UserTypeEntity> show calendaracls <CalendarManageEntity> [formatjson]
gam calendar|calendars <CalendarEntity> info events <EventEntity> [maxinstances <Number>] [formatjson]
gam calendar|calendars <CalendarEntity> show events ([allevents] <EventSelectProperties>*) <EventDisplayProperties>* [formatjson]
gam <UserTypeEntity> info events <CalendarManageEntity> <EventEntity> [maxinstances <Number>] [formatjson]
gam <UserTypeEntity> show events <CalendarPrintShowEntity> ([allevents] <EventSelectProperties>*) <EventDisplayProperties>* [formatjson]
gam show resources [allfields|<ResourceFieldName>*|(fields <ResourceFieldNameList>)] [convertcrnl] [formatjson]

Added formatjson and quotechar <Character> arguments to gam print calendars/calsettings/calendaracls/events/resources.
gam <UserTypeEntity> print calendars <CalendarPrintShowEntity> [todrive [<ToDriveAttribute>]] [permissions]
         [formatjson] [quotechar <Character>]
gam <UserTypeEntity> print calsettings [todrive [<ToDriveAttribute>]] [formatjson] [quotechar <Character>]
gam calendar|calendars <CalendarEntity> print calendaracls [todrive [<ToDriveAttribute>]] [formatjson] [quotechar <Character>]
gam resource <ResourceID> print calendaracls [todrive [<ToDriveAttribute>]] [formatjson] [quotechar <Character>]
gam resources <ResourceEntity> print calendaracls [todrive [<ToDriveAttribute>]] [formatjson] [quotechar <Character>]
gam <UserTypeEntity> print calendaracls <CalendarManageEntity> [todrive [<ToDriveAttribute>]] [formatjson] [quotechar <Character>]
gam calendar|calendars <CalendarEntity> print events [todrive [<ToDriveAttribute>]] <EventSelectProperties>*) [todrive [<ToDriveAttribute>]] <EventDisplayProperties>*
         [formatjson] [quotechar <Character>]
gam <UserTypeEntity> print events <CalendarPrintShowEntity> ([allevents] <EventSelectProperties>*) [todrive [<ToDriveAttribute>]] <EventDisplayProperties>*
         [formatjson] [quotechar <Character>]
gam print resources [todrive [<ToDriveAttribute>]] [allfields|<ResourceFieldName>*|(fields <ResourceFieldNameList>)] [convertcrnl]
        [formatjson] [quotechar <Character>]

4.56.05

Fixed a bug in gam copy drivefile that would cause a trap.

4.56.04

Fixed a bug in gam print messages that would cause a trap when the showlabels option was specified.

4.56.03

Added fields <TeamDriveFieldNameList> and formatjson arguments to gam info teamdrive and gam show teamdriveinfo/teamdrives.

gam info teamdrive <TeamDriveEntity> [fields <TeamDriveFieldNameList>] [formatjson]
gam show teamdriveinfo <TeamDriveEntity> [fields <TeamDriveFieldNameList>] [formatjson]
gam show teamdrives [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>]
        [fields <TeamDriveFieldNameList>] [formatjson]
gam <UserTypeEntity> info teamdrive <TeamDriveEntity> adminaccess [fields <TeamDriveFieldNameList>] [formatjson]
gam <UserTypeEntity> show teamdriveinfo <TeamDriveEntity> adminaccess [fields <TeamDriveFieldNameList>] [formatjson]
gam <UserTypeEntity> show teamdrives [adminaccess|asadmin [teamdriveadminquery|query <QueryTeamDrive>]] [matchname <RegularExpression>] (role <TeamDriveACLRole>)*
        [fields <TeamDriveFieldNameList>] [formatjson]

Added fields <TeamDriveFieldNameList> and formatjson and quotechar <Character> arguments to gam print teamdrives.

gam print teamdrives [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] [todrive [<ToDriveAttribute>]]
        [fields <TeamDriveFieldNameList>] [formatjson] [quotechar <Character>]
gam <UserTypeEntity> print teamdrives [adminaccess|asadmin [teamdriveadminquery|query <QueryTeamDrive>]] [matchname <RegularExpression>] (role <TeamDriveACLRole>)* [todrive [<ToDriveAttribute>]]
        [fields <TeamDriveFieldNameList>] [formatjson] [quotechar <Character>]

4.56.02

When formatjson argument is used with gam info/show contacts/contactgroups/gal, non JSON output is suppressed.

Handle "cannotChangeOrganizer - Cannot change the organizer of attendees copy of the event." error in the following commands:
gam calendar|calendars <CalendarEntity> move events <EventEntity> to <CalendarItem> [notifyattendees]
gam <UserTypeEntity> move events <CalendarManageEntity> <EventEntity> to <CalendarItem> [notifyattendees]

4.56.01

Added formatjson argument to gam info/show contacts/contactgroups/gal.
gam info contacts <ContactEntity> [basic|full] [showgroups]
        [fields <ContactFieldNameList>] [formatjson]
gam show contacts [query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]
        [fields <ContactFieldNameList>] [formatjson]
gam <UserTypeEntity> info contacts <ContactEntity> [basic|full] [showgroups]
        [fields <ContactFieldNameList>] [formatjson]
gam <UserTypeEntity> show contacts [query <QueryContact>] [contactgroup <ContactGroupItem>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]
        [fields <ContactFieldNameList>] [formatjson]
gam <UserTypeEntity> print contacts [todrive [<ToDriveAttribute>]] [query <QueryContact>] [contactgroup <ContactGroupItem>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]
        [fields <ContactFieldNameList>] [formatjson] [quotechar <Character>]
gam <UserTypeEntity> info contactgroups <ContactGroupEntity> [formatjson]
gam <UserTypeEntity> show contactgroups [updated_min <Date>]
        [basic|full] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]
gam info gal <ContactEntity> [basic|full]
        [fields <ContactFieldNameList>] [formatjson]
gam show gal [query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
        [basic|full] [orderby <ContactOrderByFieldName> [ascending|descending]]
        [fields <ContactFieldNameList>] [formatjson]

Added formatjson and quotechar <Character> arguments to gam print contacts/contactgroups/gal.
gam print contacts [todrive [<ToDriveAttribute>]] [query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]
        [fields <ContactFieldNameList>] [formatjson] [quotechar <Character>]
gam <UserTypeEntity> print contactgroups [todrive [<ToDriveAttribute>]] [updated_min <Date>]
        [basic|full] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]
        [formatjson] [quotechar <Character>]
gam print gal [todrive [<ToDriveAttribute>]] [query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]
        [basic|full] [orderby <ContactOrderByFieldName> [ascending|descending]]
        [fields <ContactFieldNameList>] [formatjson] [quotechar <Character>]

4.56.00

Update httplib2 to 0.11.3.

4.55.59

Added formatjson argument to gam info customer/instance/domain.
gam info customer [formatjson]
gam info instance [logo <FileName>] [formatjson]
gam info domain [<DomainName>] [formatjson]

Added formatjson argument to gam info course/courses.
gam info course <CourseID> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]
gam info courses <CourseEntity> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson]

Added formatjson and quotechar <Character> arguments to gam print domains/courses/course-participants/course-announcements/course-work/course-submissions.
gam print domains [todrive [<ToDriveAttribute>]] [formatjson] [quotechar <Character>]
gam print courses [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [owneremail] [owneremailmatchpattern <RegularExpression>] [alias|aliases][delimiter <Character>] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>] [formatjson] [quotechar <Character>]
gam print course-participants [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [show all|students|teachers] [formatjson] [quotechar <Character>]
gam print course-announcements [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
        (announcementids <CourseAnnouncementIDEntity>)|((announcementstates <CourseAnnouncementStateList>)* (orderby <CourseAnnouncementOrderByFieldName> [ascending|descending])*)
        [creatoremail] [fields <CourseAnnouncementFieldNameList>] [formatjson] [quotechar <Character>]
gam print course-work [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
        (workids <CourseWorkIDEntity>)|((workstates <CourseWorkStateList>)* (orderby <CourseWorkOrderByFieldName> [ascending|descending])*)
        [creatoremail] [fields <CourseWorkFieldNameList>] [formatjson] [quotechar <Character>]
gam print course-submissions [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
        (workids <CourseWorkIDEntity>)|((workstates <CourseWorkStateList>)* (orderby <CourseWorkOrderByFieldName> [ascending|descending])*)
        (submissionids <CourseSubmissionIDEntity>)|((submissionstates <CourseSubmissionStateList>)*) [late|notlate]
        [fields <CourseSubmissionFieldNameList>] [formatjson] [quotechar <Character>] [showuserprofile]

4.55.58

Improved error handling for gam update/delete/info mobile when an invalid <MobileID> is given. The API returns an error indicating that Gam should retry the command
but this will usually never succeed. Gam now retries the command once rather than ten times and then generates an error.

Mobile devices can have a deviceId with an embedded newline (NL) character; these are now converted to "\n" in gam print mobile if gam.cfg csv_output_convert_cr_nl = True.

4.55.57

GAM has been updated to address the issues addressed in the article: "Discontinuing support for JSON-RPC and Global HTTP Batch Endpoints" at https://developers.googleblog.com/.

GAM has been updated to use the `patch` method with `gam update calendar` so that the values of parameters `selected` and `hidden` are preserved.

Thanks to Jan Almeroth for suggesting the following enhancement.
Added [csv [todrive [<ToDriveAttribute>]]] to gam create drivefile so that the user, name and drive file ID
of the created files will be written to a CSV file.
gam <UserTypeEntity> create|add drivefile [drivefilename <DriveFileName>] <DriveFileAddAttribute>* [csv [todrive [<ToDriveAttribute>]]]

Added the ability to transfer all of a user's assets: drive files, calendars and Google+ information, in a single command.
<DataTransferService> ::=
        calendar|
        googledrive|gdrive|drive|"drive and docs"|
        gplus|googleplus|google+
<DataTransferServiceList> ::= "<DataTransferService>(,<DataTransferService>)*"

gam create|add datatransfer|transfer <OldOwnerID> <DataTransferServiceList> <NewOwnerID>
        [private|shared|all] (<ParameterKey> <ParameterValue>)*
        [release_resources]

Added a command to display transfer requests in a formatted form.
gam show datatransfers|transfers [olduser|oldowner <UserItem>] [newuser|newowner <UserItem>] [status <String>] [delimiter <Character>]

4.55.56

In gam info group/user, aliases will be displayed as `alias: <EmailAddress>` to be consistent with other items.

4.55.55

Fixed a bug where <FileName>(:<FieldName>)+ was not parsed correctly on Windows when <FileName> contained a drive specification;
e.g., csvfile C:\Users\Admin\Downloads\Data.csv:primaryEmail.

<CrOSTypeEntity> ::=
        croscsvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>]
<UserTypeEntity> ::=
        csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>]
<FileSelector> ::=
        csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>]

4.55.54

Code cleanup.

Added onlyteamdrives to <CorporaAttribute>; this is used in gam print filelist/filecounts to limit the operation to files/folders on Team Drives.
The <CorporaAttribute> allteamdrives actually means files owned by or shared to the user and Team Drive files.
<CorporaAttribute> ::= allteamdrives|domain|onlyteamdrives|user

The Drive REST API V3 does not return permissions for Team Drive files, only permissionsIds which are not typically useful.
gam show fileinfo/print filelist have been enhanced to get permissions for Team Drive files if permissions is explicitly
specified in <DriveFieldName>*|(fields <DriveFieldNameList>). This requires an extra API call per Team Drive file so use sparingly.

4.55.53

Update to Google API CLient 1.6.5. This should resolve a problem with downloading large Google Docs.

4.55.52

Allow having an empty buildingid with gam create/update resource; this is only valid for resources with
category category_unknown.

4.55.51

Added cacerts_pem variable to gam.cfg to allow specification of an alternative SSL Root CA certificates file.
This would typically be used when your site uses SSL decryption and you need a vendor specific certificate.
By default, GAM uses an internal copy of the cacerts.pem file found in the folder containing gam.py/gam.exe.
If you need to add a vendor specific certificate, copy cacerts.pem to the folder containing gam.cfg, append your
vendor certificate PEM file to the copied file and change gam.cfg/cacerts_pem to point to the copied file.
cacerts_pem
        SSL Root CA certificates file
        Default: Blank, internal cacerts.pem will be used

Fixed a bug where a duplicate extension was added to a file downloaded from Google Drive; this occurred when the file
had an uppercase extension on Google Drive.

4.55.50

Added category synonyms category_unknown and unknown to <ResourceAttribute>.
<ResourceAttribute> ::=
        (category other|room|conference_room|category_unknown|unknown)|

4.55.49

Added the ability to specify multiple queries in the following print commands.
gam print alias|aliases [todrive [<ToDriveAttribute>]]
        [(query <QueryUser>)|(queries <QueryUserList>)]
gam [<CrOSTypeEntity>] print cros [todrive [<ToDriveAttribute>]]
        [(query <QueryCrOS>)|(queries <QueryCrOSList>)|(select <CrOSTypeEntity>)] [limittoou <OrgUnitItem>]
gam [<CrOSTypeEntity>] print crosactivity [todrive [<ToDriveAttribute>]]
        [(query <QueryCrOS>)|(queries <QueryCrOSList>)|(select <CrOSTypeEntity>)] [limittoou <OrgUnitItem>]
gam print mobile [todrive [<ToDriveAttribute>]]
        [(query <QueryMobile>)|(queries <QueryMobileList>)]
gam print printer|printers [todrive [<ToDriveAttribute>]]
        [(query <QueryPrinter>)|(queries <QueryPrinterList>)] [type <String>] [status <String>]
gam printjob|printjobs <PrinterID>|any fetch
        [(query <QueryPrintJob>)|(queries <QueryPrintJobList>)] [olderthan|newerthan <PrintJobAge>] [status <PrintJobStatus>]
gam print printjob|printjobs [todrive [<ToDriveAttribute>]] [printer|printerid <PrinterID>]
        [(query <QueryPrintJob>)|(queries <QueryPrintJobList>)] [olderthan|newerthan <PrintJobAge>] [status <PrintJobStatus>]
gam print users [todrive [<ToDriveAttribute>]]
        ([domain <DomainName>] [(query <QueryUser>)|(queries <QueryUserList>)] [deleted_only|only_deleted])|[select <UserTypeEntity>]

4.55.48

Added the ability to specify multiple queries when specifying collections of Users or ChromeOS devices.
<QueryCrOSList> ::= "<QueryCrOS>(,<QueryCrOS>)*"
<QueryUserList> ::= "<QueryUser>(,<QueryUser>)*"
<CrOSTypeEntity> ::=
        (crosqueries <QueryCrOSList>)|
<UserTypeEntity> ::=
        (queries <QueryUserList>)|

Quoting a query list takes some thought, in particular if a query contains a space, a comma or a single quote.
In all cases, the list of queries is surrounded with double quotes.
If a query doesn't contain spaces or single quotes, no special quoting is required.
gam queries "orgTitle=Specialist,orgTitle=Technician" print users allfields
gam cros_queries "id:HY3,id:5CD" print cros allfields nolists
If a query does contain a single quote, you surround it with escaped double quotes.
gam queries "\"orgName='Sales Org' orgTitle=Manager\",\"orgName='Marketing Org'\"" print users allfields

For quoting rules, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Lists

4.55.47

The Google Reports API does not have complete data available in real time, you must go back some number of days to get the full report data.
The fulldatarequired all|<ReportsAppList> option tells Gam to go backward a day at a time until the Reports API indicates that full data is
available for the applications specified in <ReportsAppList>.
<ReportsApp> ::=
      accounts|
      app_maker|
      apps_scripts|
      calendar|
      classroom|
      cros|
      device_management|
      drive|
      gmail|
      gplus|
      meet|
      mobile|
      sites
<ReportsAppList> ::= "<ReportsApp>(,<ReportsApp>)*"

gam report users|user [todrive [<ToDriveAttribute>]] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
        [(user all|<UserItem>)|(select <UserTypeEntity>)] [filter|filters <String>] [fields|parameters <String>]
        [maxactivities <Number>] [maxresults <Number>]
gam report customers|customer|domain [todrive [<ToDriveAttribute>]] [date <Date>] [nodatechange | (fulldatarequired all|<ReportsAppList>)]
        [fields|parameters <String>]

A good example is user drive quotas: accounts:drive_used_quota_in_mb,accounts:gmail_used_quota_in_mb,accounts:total_quota_in_mb,accounts:used_quota_in_mb.
These items are not available immediately, you must go back several days to get the full data.

gam report users user user@domain.com fulldatarequired accounts

4.55.46

Handle errors when gamcache directory is not accessible.

4.55.45

Fixed incompatibility with Basic Gam when the fields option is used with gam print group-members.
With Basic Gam, the command "gam print group-members fields email,type" produced three columns: group,email,type
With Advanced Gam, the command "gam print group-members fields email,type" produced two columns: email,type
The group email address column was included only if group was in the fields list; now, Advanced Gam will also output the group
email address column even if it's not in the field list. In the special case where you don't want the group email address column,
use the option nogroupemail.
gam print group-members [todrive [<ToDriveAttribute>]]
        [domain <DomainName>] [member <UserItem>])|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>]
        [roles <GroupRoleList>] [members] [managers] [owners] [membernames] <MembersFieldName>* [fields <MembersFieldNameList>]
        [userfields <UserFieldNameList>] [recursive [noduplicates]] [nogroupemail]

4.55.44

Improve MacOS version of GAM's use of OpenSSL 1.0.2n.
Recode pyinstaller .spec files.

4.55.43

Added Team Drive support to print/show file counts by MIME type for users.
gam <UserTypeEntity> show filecounts [corpora <CorporaAttribute>] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>] [showmimetype [not] <MimeTypeList>]
        [select <TeamDriveEntity>]
gam <UserTypeEntity> print filecounts [todrive [<ToDriveAttribute>]] [corpora <CorporaAttribute>] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>] [showmimetype [not] <MimeTypeList>]
        [select <TeamDriveEntity>]

4.55.42

Added commands to print/show file counts by MIME type for users.
gam <UserTypeEntity> show filecounts [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>] [showmimetype [not] <MimeTypeList>]
gam <UserTypeEntity> print filecounts [todrive [<ToDriveAttribute>]] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>] [showmimetype [not] <MimeTypeList>]

4.55.41

Fixed bug that made some gam print commands throw an exception.

4.55.40

Update MacOS version of GAM to use OpenSSL 1.0.2n.

4.55.39

Fixed bug in gam update group sync when the command was of the following form:
gam update group csvkmd groups.csv keyfield group matchfield role MEMBER datafield email sync member csvdata email

4.55.38

Display allowedConferenceSolutionTypes in gam info/print/show calendars.

4.55.37

Added command to print classic sites ACLs.
gam [<UserTypeEntity>] print siteacls <SiteEntity> [todrive [<ToDriveAttribute>]]

4.55.36

Changed gam print filelist to display parents information in the same format regardless of the value of drive_v3_native_name in gam.cfg.
Previously, if drive_v3_native_names was false, the columns were:
* parents - The number of parents
# parents.N.id - The id of parent N: N repeats from 0 to number of parents-1
Previously, if drive_v3_native_names was true, the single column was:
* parents - The space separated list of parent ids
Now, regardless of the value of drive_v3_native_names, the columns are:
* parents - The number of parents
# parents.N.id - The id of parent N: N repeats from 0 to number of parents-1
# parents.N.isRoot - True if parents.N.id is the root folder id, False otherwise

4.55.35

Code cleanup.

Fixed bug in gam print filelist where specifying the field owners.emailaddress caused an exception.

4.55.34

Added showstudentemails option to gam show/print guardians so that the student email address will be displayed in addition to the student ID.
This requires an additional API call per guardian.
gam show guardian|guardians invitations [showstudentemails] [states <GuardianStateList>] [invitedguardian <EmailAddress>] [student <StudentItem>] [<UserTypeEntity>]
gam print guardian|guardians invitations [todrive [<ToDriveAttribute>]] [showstudentemails] [states <GuardianStateList>] [invitedguardian <EmailAddress>] [student <StudentItem>] [<UserTypeEntity>]
gam show guardian|guardians [showstudentemails] [invitedguardian <EmailAddress>] [student <StudentItem>] [<UserTypeEntity>]
gam print guardian|guardians [todrive [<ToDriveAttribute>]] [showstudentemails] [invitedguardian <EmailAddress>] [student <StudentItem>] [<UserTypeEntity>]

4.55.33

Added formatjson argument to gam info cros/print cros/print crosactivity to cause output to be in JSON format.

By default, when writing CSV files, Gam uses a quote character of double quote ". The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the gam print cros/crosactivity commands with the formatjson option, double quotes are used extensively in the data resulting in hard to read/process output.
The quotechar <Character> option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
quotechar defaults to gam.cfg/csv_output_quote_char.

gam info cros <CrOSEntity> [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [downloadfile latest|<Time>] [targetfolder <FilePath>] [formatjson]
gam <CrOSTypeEntity> info [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [downloadfile latest|<Time>] [targetfolder <FilePath>] [formatjson]
gam [<CrOSTypeEntity>] print cros [todrive [<ToDriveAttribute>]] [query <QueryCrOS>]|[select <CrOSTypeEntity>] [limittoou <OrgUnitItem>]
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [nolists|recentusers|timeranges|devicefiles] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [sortheaders] [formatjson] [quotechar <Character>]
gam [<CrOSTypeEntity>] print crosactivity [todrive [<ToDriveAttribute>]] [query <QueryCrOS>]|[select <CrOSTypeEntity>] [limittoou <OrgUnitItem>]
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [recentusers] [timeranges] [both] [devicefiles] [all] [listlimit <Number>] [start <Date>] [end <Date>]
        [delimiter <Character>] [formatjson] [quotechar <Character>]

4.55.32

Add special handling for Organizational Unit names containing the characters + and %.

4.55.31

Fixed error in `gam update drivefileacl/updatedrivefileacl` where specifying a group email address caused the command to fail.

Added support for domain/user contact photos.
gam update contactphotos <ContactEntity>|([query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]) [drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>]
gam get contactphotos <ContactEntity>|([query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]) [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>]
gam delete contactphotos <ContactEntity>|([query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>])
gam <UserTypeEntity> update contactphotos <ContactEntity>|([query <QueryContact>] [contactgroup <ContactGroupItem>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]) [drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>]
gam <UserTypeEntity> get contactphotos <ContactEntity>|([query <QueryContact>] [contactgroup <ContactGroupItem>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]) [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>]
gam <UserTypeEntity> delete contactphotos <ContactEntity>|([query <QueryContact>] [contactgroup <ContactGroupItem>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>])
The default directory is the current working directory, drivedir specifies the value of drive_dir from gam.cfg and
sourcefolder/targetfolder <FilePath> specifies a user-chosen path.
<FileNamePattern> can contain the strings #email# and #contactid# which will be replaced by the contact's primary email address or the contact ID.
If not specified, <FileNamePattern> defaults to "#contactid#.jpg".

Previously, when upating a user's photo, you specified a <FileNamePattern> that> had to specify a full file path and
could contain the strings #email#, #user# and #username# which would be replaced by the user's full email address or just the name portion.
<FileNamePattern> can now be omitted, it defaults to "#email#.jpg".
gam <UserTypeEntity> update photo [<FileNamePattern>]

A new form of the command allows you to separate the directory and file name specifications.
The default directory is the current working directory, drivedir specifies the value of drive_dir from gam.cfg and
sourcefolder <FilePath> specifies a user-chosen path.
If not specified, <FileNamePattern> defaults to "#email#.jpg".
gam <UserTypeEntity> update photo [drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>]

Previously, when downloading a user's photo, the file name was always the user's email address with a .jpg extension.
You can now specify a <FileNamePattern> that can contain the strings #email#, #user# and #username# which will be replaced by the user's full email address or just the name portion.
<FileNamePattern> defaults to "#email#.jpg".
gam <UserTypeEntity> get photo [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>] [noshow]

4.55.30

Handle mysterious start_time and end_time values in gam report calendar.

4.55.29

Fixed bug where {RT}...{Tag}...{/RT} was not properly deleted when Tag was not defined/empty.

4.55.28

Added the ability to update domain/user contacts by querying for them.
gam update contacts <ContactEntity>|([query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>]) <ContactAttribute>+
gam <UserTypeEntity> update contacts <ContactEntity>|([query <QueryContact>] [contactgroup <ContactGroupItem>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min <Date>] [endquery]) [contactgroup <ContactGroupItem>] <ContactAttribute>+

4.55.27

Fixed bug in gam get drivefile where Google Docs files would not be downloaded if format <FileFormatList> was not specified.

4.55.26

Added targetname <FileName> and overwrite [<Boolean>] to gam get drivefile. By default, the target (local) filename is the Google Drive filename; targetname <FileName>
let's you specify the target filename. By default, an existing target file will not be overwritten; a numeric prefix is added to the filename.
Specifying overwrite or overwrite true will cause the target file to be overwritten. Not specifying overwrite or specifying overwrite false means a new file will be created.
gam <UserTypeEntity> get drivefile <DriveFileEntity> [format <FileFormatList>] [targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]] [revision <DriveFileRevisionID>]

4.55.25

Added the ability to select owners subfields in gam show fileinfo and gam print filelist; these fields are included
in <DriveFieldName> and <DriveFieldNameList>.
<DriveOwnersSubfieldName> ::=
        owners.displayname|
        owners.emailaddress|
        owners.isauthenticateduser|
        owners.me|
        owners.permissionid|
        owners.photolink|
        owners.picture

4.55.24

Commands that use the emailmatchpattern, owneremailmatchpattern, namematchpattern or attachmentnamepattern options will now
perform case insensitive matches. The same is true for the matchfield option in gam info/show/print events.

4.55.23

Added emailmatchpattern <RegularExpression> and namematchpattern <RegularExpression> to the following commands to
allow filtering on the group email address and name; Gam applies these filters after downloading the groups from the API.
gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>]
        [maxresults <Number>] [allfields|([settings] <GroupFieldName>* [fields <GroupFieldNameList>])]
        [members|memberscount] [managers|managerscount] [owners|ownerscount] [countsonly]
        [convertcrnl] [delimiter <Character>] [sortheaders] [formatjson] [quotechar <Character>]
gam print group-members [todrive [<ToDriveAttribute>]]
        [domain <DomainName>] [member <UserItem>])|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>]
        [roles <GroupRoleList>] [members] [managers] [owners] [membernames] <MembersFieldName>*
        [fields <MembersFieldNameList>] [userfields <UserFieldNameList>] [recursive [noduplicates]]
gam show group-members
        ([domain <DomainName>] [member <UserItem>])|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [emailmatchpattern <RegularExpression>] [namematchpattern <RegularExpression>]
        [roles <GroupRoleList>] [members] [managers] [owners] [depth <Number>]

4.55.22

Improve error reporting when scopes are not authorized.

4.55.21

Added owneremailmatchpattern <RegularExpression> option to gam print courses to allow filtering of courses based on the owner email address.
The `<RegularExpression>` can be used to match a specific address "foo@bar.com", a pattern ".*test.*" or the special value "Unknown user" for those
courses where the owner has been deleted.
gam print courses [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [owneremail] [owneremailmatchpattern <RegularExpression>] [alias|aliases][delimiter <Character>] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]

4.55.20

Added from and replyto options to gam sendemail. By default, emails will be from the admin user named in oauth2.txt, override this with the from <UserItem> option.
gam sendemail <EmailAddressEntity> [from <UserItem>] [replyto <EmailAddress>] subject <String> (message <String>)|(file <FileName> [charset <CharSet>]) (replace <Tag> <String>)*
        [newuser <UserItem> firstname|givenname <String> lastname|familyname <string> password <Password>]

4.55.19

Added error handling for invalid ownerId/creatorUserId in gam print courses/course-announcements/course-work.

4.55.18

Many gam print commands display "Getting ... (n/m)" messages while stepping through lists of items; this let's you monitor Gam's progress.
Other gam print commands display no output as they progress; a "Getting ... (n/m)" message has been added to these commands.

Added enabledonly option to gam print forward/vacation to disable output of users with these options disabled.
gam <UserTypeEntity> print forward [enabledonly] [todrive [<ToDriveAttribute>]]
gam <UserTypeEntity> print vacation [enabledonly] [todrive [<ToDriveAttribute>]]

Added retainname option to gam update drivefile to allow updating a Google Drive file from a local file without renaming it.
gam <UserTypeEntity> update drivefile <DriveFileEntity> [copy] [retainname | (newfilename <DriveFileName>)] <DriveFileUpdateAttribute>*
Here are the file naming rules:
create drivefile localfile "LocalFile.csv" - Google Drive file is named "LocalFile.csv"
create drivefile drivefilename "GoogleFile.csv" localfile "LocalFile.csv" - Google Drive file is named "GoogleFile.csv"
update drivefile drivefilename "GoogleFile.csv" localfile "NewLocalFile.csv" - Google Drive file "GoogleFile.csv" is renamed "NewLocalFile.csv"
update drivefile drivefilename "GoogleFile.csv" newfilename "NewGoogleFile.csv" localfile "NewLocalFile.csv" - Google Drive file "GoogleFile.csv" is renamed "NewGoogleFile.csv"
update drivefile drivefilename "GoogleFile.csv" retainname localfile "NewLocalFile.csv" - Google Drive file "GoogleFile.csv" is not renamed

Added matchname <RegularExpression> argument to all commands that print or show Team Drives to allow retrieving Team Drives with names that match a pattern.
It is more flexible that the administrator query for a Team Drive name described here: https://developers.google.com/drive/v3/web/search-parameters#team_drive_fields
It can be used with all commands, the administrator query can ony be used when adminaccess is implied or explicitly specified.

gam print teamdrives [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] (role <TeamDriveACLRole>)* [todrive [<ToDriveAttribute>]]
gam show teamdrives [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] (role <TeamDriveACLRole>)*

gam <UserTypeEntity> print teamdrives adminaccess [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] (role <TeamDriveACLRole>)* [todrive [<ToDriveAttribute>]]
gam <UserTypeEntity> show teamdrives adminaccess [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] (role <TeamDriveACLRole>)*

gam <UserTypeEntity> print teamdrives [matchname <RegularExpression>] (role <TeamDriveACLRole>)* [todrive [<ToDriveAttribute>]]
gam <UserTypeEntity> show teamdrives [matchname <RegularExpression>] (role <TeamDriveACLRole>)*

Added commands to display Team Drive ACLs. These commands can be time consuming as Gam gets the list of Team Drives with one API call and then makes an API call per Team Drive to get the ACL information.
gam print teamdriveacls [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] [user|group <EmailAddress> [checkgroups]] (role <TeamDriveACLRole>)* [oneitemperrow] [todrive [<ToDriveAttribute>]]
gam show teamdriveacls [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] [user|group <EmailAddress> [checkgroups]] (role <TeamDriveACLRole>)*
gam <UserTypeEntity> print teamdriveacls adminaccess [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] [user|group <EmailAddress> [checkgroups]] (role <TeamDriveACLRole>)* [oneitemperrow] [todrive [<ToDriveAttribute>]]
gam <UserTypeEntity> show teamdriveacls adminaccess [teamdriveadminquery|query <QueryTeamDrive>] [matchname <RegularExpression>] [user|group <EmailAddress> [checkgroups]] (role <TeamDriveACLRole>)*

4.55.17

Added fulltimeequivalent <Integer> field to organization item in <UserAttribute>.
From the API documentation: the full-time equivalent percent within the organization (100000 = 100%).

Added showuserprofile option to gam print course-submissions to display the user email address and name in addition to the numeric userId.

Updated sync operations for classrooms, groups and printers to allow more control over adds and removes.
A sync operation gets the current roster for an entity and compares it to the proposed roster.

Current/Default:
* members in the proposed roster that are not in the current roster will be added
* members in the current roster that are not in the proposed roster will deleted

When the addonly option is specified:
* members in the proposed roster that are not in the current roster will be added
* members in the current roster that are not in the proposed roster will not be deleted

When the removeonly option is specified:
* members in the proposed roster that are not in the current roster will not be added
* members in the current roster that are not in the proposed roster will be deleted

gam courses <CourseEntity> sync teachers|students [addonly|removeonly] <UserTypeEntity>
gam update group|groups <GroupEntity> sync [owner|manager|member] [usersonly|groupsonly] [addonly|removeonly] [notsuspended] <UserTypeEntity>
gam printer|printers <PrinterIDEntity> sync user|manager|owner [usersonly|groupsonly] [addonly|removeonly] <PrinterACLScopeEntity> [notify]

Added a command to simplify moving a Drive file/folder to a new location; this command replaces all existing parents with a new parent.
Use gam <UserTypeEntity> update for more complex parent changes.
<DriveFileMoveAttribute> ::=
        ((parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>))|
         (teamdriveparentid <DriveFolderID>)|
         ((teamdriveparentid <TeamDriveID>)|(teamdriveparent <TeamDriveName>) [teamdriveparentname <DriveFolderName>]))
gam <UserTypeEntity> move drivefile <DriveFileEntity> [newfilename <DriveFileName>] <DriveFileMoveAttribute>*

Moving a Drive folder to a Team Drive is not directly supported by the API; Gam has to make a copy of the folder on the Team Drive and
recursively adjust the files/folders within it to point to the new parent folder.

Added the ability to replace tags with user attributes in the following commands: import message, insert message, create sendas, update sendas, signature, vacation.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Tag-Replace

4.55.16

The following command has been restored.
gam <UserTypeEntity> create|add teamdrive <Name> [(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]

4.55.15

Improved error handling for gam audit commands.
Miscellaneous cleanup.

4.55.14

Added the ability to add/remove attachments to/from calendar events.
<EventAttribute> ::=
        (attachment <String> <URL>)
<EventUpdateAttribute> ::=
        clearattachments

On an add or update, you can specify multiple attachments; <String> is the title of the attachment and <URL> is a sharable link from Google Drive.
You must specify all attachments in each command, you can not incrementally add attachmets. You delete all attachments with the clearattachments option.

4.55.13

Fixed error where the following collections of users were not recognized; these all select non-suspended users from OUs.
<UserTypeEntity> ::=
        (ou_ns <OrgUnitItem>)|
        (ou_and_children_ns <OrgUnitItem>)|
        (ous_ns <OrgUnitList>)|
        (ous_and_children_ns <OrgUnitList>)

4.55.12

Fixed errors in gam transfer drive command.

4.55.11

Fixed error in setting file properties.

4.55.10

Update 4.55.07 broke the error message handling for unknown/inapplicable users, it has been corrected.

4.55.09

Fixed bug in gam add/delete permissions that caused an exception.
Improved output formatting in gam add/delete permissions.

4.55.08

Added options to gam show filetree to allow additional fields beyond the file/folder name to be shown.

See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Files

4.55.07

Based on initial work by Jay, converted service account access to use the google-auth library for authentication rather than the deprecated oauth2client library.

4.55.06

Properly output tpmVersionInfo field in gam info/print cros.

4.55.05

Handle API exception when trying to update an unknown group.

4.55.04

Fixed bug related to using fields argument with gam info/print/show commands.

4.55.03

Fixed a bug in gam delete contacts where using just the emailmatchpattern option threw an exception.

Cleaned up code for print courses, print course-work, print course-submissions, print course_participants.

Added command to print course announcements.
You need to execute the following command to enable the scope that authorizes this command: gam oauth create

See: https://github.com/taers232c/GAMADV-XTD3/wiki/Courses

gam print course-announcements [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
        (courseannouncementids <CourseAnnouncementIDEntity>)|((announcementstates <CourseAnnouncementStateList>)* (orderby <CourseAnnouncementOrderByFieldName> [ascending|descending])*)
        [creatoremail] [fields <CourseAnnouncementFieldNameList>]

4.55.02

Fixed bug in gam transfer drive.

4.55.01

Fixed bug in gam sendemail.

4.55.00

The GAMADV-X and GAMADVX-TD version numbers are now the same.

Added option to allow setting Google Drive file properties.
See: https://developers.google.com/drive/v2/reference/properties#resource

<DriveFileAttribute> ::=
        (privateproperty <PropertyKey> <PropertyValue>)|
        (publicproperty <PropertyKey> <PropertyValue>)|
        (property <PropertyKey> <PropertyValue> [private|public])|
The first two forms are similar to other Gam commands, the third form can accept fields from a CSV files produced by print filelist.
In the third form, if neither private or public is specified, public is assumed.
To clear a property, set <PropertyValue> to the empty string "".

Based on initial work by Jay, added support for ChromeOS device files; these are associated with ChromeOS devices running in kiosk mode.
See: https://support.google.com/chrome/a/answer/1375678?hl=en#kiosk
See: https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices

<CrOSFieldName> ::=
        devicefiles|
gam [<CrOSTypeEntity>] print cros [todrive [<ToDriveAttribute>]] [query <QueryCrOS>]|[select <CrOSTypeEntity>] [limittoou <OrgUnitItem>]
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [nolists|recentusers|timeranges|devicefiles] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]
gam [<CrOSTypeEntity>] print crosactivity [todrive [<ToDriveAttribute>]] [query <QueryCrOS>]|[select <CrOSTypeEntity>] [limittoou <OrgUnitItem>]
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [recentusers] [timeranges] [both] [devicefiles] [all] [listlimit <Number>] [start <Date>] [end <Date>]
        [delimiter <Character>]

gam info cros <CrOSEntity> [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [downloadfile latest|<Time>] [targetfolder <FilePath>]
gam <CrOSTypeEntity> info [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [downloadfile latest|<Time>] [targetfolder <FilePath>]

You can download a ChromeOS device file by specifying the downloadfile latest|<Time> option in the previous two commands.
The following commands provide more options for downloading device files.

gam get devicefile <CrOSEntity> [select <DeviceFileEntity>] [targetfolder <FilePath>]
gam <CrOSTypeEntity> get devicefile [select <DeviceFileEntity>] [targetfolder <FilePath>]

Based on initial work by Jay, added support for buildings and features in resource calendars.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Resource-Calendars

Added command to allow Gam to send emails.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Send-Email

4.54.59

Fix reporting of target free space in gam transfer drive.

4.54.58

Updated options in gam transfer drive to give more control over processing files.

See: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Transfer

gam <UserTypeEntity> transfer drive <UserItem> [select <DriveFileEntity>]
        [(targetfolderid <DriveFolderID>)|(targetfoldername <DriveFolderName>)] [targetuserfoldername <DriveFolderName>] [targetuserorphansfoldername <DriveFolderName>]
        [keepuser | (retainrole reader|commenter|writer|editor|none)] [noretentionmessages]
        [nonowner-retainrole reader|commenter|writer|editor|current|none] [nonowner-targetrole reader|commenter|writer|editor|current|none|source]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*
        [preview] [todrive [<ToDriveAttribute>]]

Added commands to print course work and course submissions.
You need to execute the following command to enable the scope that authorizes these commands: gam oauth create

See: https://github.com/taers232c/GAMADV-XTD3/wiki/Courses

gam print course-work [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
        (courseworkids <CourseWorkIDEntity>)|((workstates <CourseWorkStateList>)* (orderby <CourseWorkOrderByFieldName> [ascending|descending])*)
        [fields <CourseWorkFieldNameList>]
gam print course-submissions [todrive [<ToDriveAttribute>]] (course|class <CourseEntity>)*|([teacher <UserItem>] [student <UserItem>] states <CourseStateList>])
        (courseworkids <CourseWorkIDEntity>)|((workstates <CourseWorkStateList>)* (orderby <CourseWorkOrderByFieldName> [ascending|descending])*)
        (coursesubmissionids <CourseSubmissionIDEntity>)|((submissionstates <CourseSubmissionStateList>)*) [late|notlate]
        [fields <CourseSubmissionFieldNameList>]

4.54.57

Fixed bug in gam oauth create where entering `e` to exit without changes didn't exit.

4.54.56

Added options to allow getting only non-suspended users from groups and OUs. Using a type with a trailing _ns causes Gam to get only
the non-suspended users.
<UserTypeEntity> ::=
        (group|group_ns <GroupItem>)|
        (groups|groups_ns <GroupList>)|
        (group_users|group_users_ns <GroupList> [members] [managers] [owners] [primarydomain] [domains <DomainNameList>] [recursive] end)|
        (ou|ou_ns <OrgUnitItem>)|
        (ou_and_children|ou_and_children_ns <OrgUnitItem>)|
        (ous|ous_ns <OrgUnitList>)|
        (ous_and_children|ous_and_children_ns <OrgUnitList>)|

gam print group-members [todrive [<ToDriveAttribute>]]
        [domain <DomainName>] [member <UserItem>])|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [members] [managers] [owners] [membernames] <MembersFieldName>*
        [fields <MembersFieldNameList>] [userfields <UserFieldNameList>] [recursive [noduplicates]]
gam show group-members
        ([domain <DomainName>] [member <UserItem>])|[group|group_ns <GroupItem>]|[select <GroupEntity>] [notsuspended]
        [members] [managers] [owners] [depth <Number>]

To maintain compatabiity with Jay Lee's Gam, gam oauth create has been changed to prompt for the G Suite admin email address
after the scopes have been selected.

4.54.55

Handle error when trying to delete a Team Drive that contains files/folders.

4.54.54

Fixed bug in gam info group.

Made gam info group and gam info user consistent when printing aliases.
Previously:
* gam info user showed the Aliases: and Non-Editable Aliases: lines even if there were no aliases of the type; counts for each alias type were not shown.
* gam info group showed the Aliases: and Non-Editable Aliases: lines only if there were aliases of the type; counts for each alias type were shown.

Currently:
* gam info user shows the Aliases: and Non-Editable Aliases: lines only if there are aliases of the type; counts for each alias type are shown.
* gam info group shows the Aliases: and Non-Editable Aliases: lines only if there are aliases of the type; counts for each alias type are shown.

4.54.53

Code cleanup for "Getting ..." messages.

4.54.52

* Added noretentionmessages option to the following commands.
It causes GAM to suppress the progress messages that detail what role the original owner retains.
(If there is an error in assigning the retained role, it will be displayed.)

gam <UserTypeEntity> transfer calendars <CalendarManageEntity> <UserItem> [keepuser | (retainrole <CalendarACLRole>)] [noretentionmessages]
gam <UserTypeEntity> claim ownership <DriveFileEntity> ...  [keepuser | (retainrole commenter|reader|writer|none)] [noretentionmessages]
gam <UserTypeEntity> transfer drive <UserItem> ... [keepuser | (retainrole commenter|reader|writer|none)] [noretentionmessages]

* Added usersonly|groupsonly option to the following commands.

gam update group|groups <GroupEntity> create|add [owner|manager|member] [usersonly|groupsonly] [notsuspended] <UserTypeEntity>
gam update group|groups <GroupEntity> delete|remove [owner|manager|member] [usersonly|groupsonly] <UserTypeEntity>
gam update group|groups <GroupEntity> sync [owner|manager|member] [usersonly|groupsonly] [notsuspended] <UserTypeEntity>
gam update group|groups <GroupEntity> update [owner|manager|member] [usersonly|groupsonly] <UserTypeEntity>

gam printer|printers <PrinterIDEntity> create|add user|manager|owner [usersonly|groupsonly] <PrinterACLScopeEntity> [notify]
gam printer|printers <PrinterIDEntity> delete [usersonly|groupsonly] <PrinterACLScopeEntity>
gam printer|printers <PrinterIDEntity> sync user|manager|owner [usersonly|groupsonly] <PrinterACLScopeEntity> [notify]

Assume that at your school there is a group for each grade level and the members come from an OU; here is a sample CSV file GradeOU.csv
Grade,OU
seniors@domain.org,/Students/ClassOf2018
juniors@domain.org,/Students/ClassOf2019
...

This allows you to do: gam csv GradeOU.csv gam update group ~Grade sync members ou ~OU
But suppose that at each grade level there are additional group members that are groups of faculty/staff; e.g., senioradvisors@domain.org.
In this scenario, you can't do the update group sync command as the members that are groups will be deleted; the usersonly option allows
the update group sync command to work: gam csv GradeOU.csv gam update group ~Grade sync members usersonly ou ~OU
The users from the OU are matched against the user members of the group and adds/deletes are done as necessary to synchronize them;
the group members of the group are unaffected.

The usersonly option is most useful when used with the sync option, it can be used with create/delete/update when <UserTypeEntity> specifies
a group or groups. In ths case, only the user members from the specified groups are processed.

The groupsonly option works in the same manner as the usersonly option; it only processes group members that are groups.
It only makes sense to use it when <UserTypeEntity> specifies a group or groups.

* Updated handling of group name and description to account for Google API behavior.

There are two APIs that can set a group name or description: the Directory API and the Group Settings API;
they have different behaviors when updating these two fields.

Define four fields: d-name, d-description, gs-name and gs-description.
The Directory API sets d-name and d-description: newline (\n), <, > and = are not allowed.
The Group Settings API sets gs-name and gs-description, all characters are allowed.
If you set d-name/d-description with the Directory API, gs-name/gs-description are unaffected.
If you set gs-name/gs-description with the Group Settings API, d-name/d-description are unaffected.

When retrieving these fields for an individual group, the Directory API returns d-name and d-description and
the Group Settings API returns gs-name and gs-description. However, when using the Directory API to retrieve these fields
for a list of groups, the gs-name and gs-description values are returned.

If you use the Admin console, the character limitations for the Directory API still apply, but both d-name/gs-name and d-description/gs-description are set.

If you use groups.google.com, there are no character limitations, and both d-name/gs-name and d-description/gs-description are set.

When you update a group name or description, GAM will use both APIs to set the values. When updating the value with the Directory API,
each disallowed character is replaced by a space.

When you print groups, the name and description columns contain the gs-name and gs-description values. When you get info for a single grooup,
the name and description lines contain the gs-name and gs-description values. If the d-name value differs from the gs-name value, it will
shown on a separate line as groupName. If the d-description value differs from the gs-description  value, it will shown on a separate line as groupDescription.

* Added capabilty to add/remove parent folders by name when updating a Google Drive file/folder.

Previously, the gam update drivefile command had the following options for adding/removing parent folders:
        (addparents <DriveFolderIDList>)|
        (removeparents <DriveFolderIDList>)|
You had to specify the parents by ID. The following new options have been added to allow specification of the parents by folder name.
        (addparentname <DriveFolderName>)|
        (addanyownerparentname <DriveFolderName>)|
        (removeparentname <DriveFolderName>)|
        (removeanyownerparentname <DriveFolderName>)|
Gam performs a query to convert <DriveFolderName> to its <DriveFolderID>.
* addparentname|removeparentname <DriveFolderName> - The query is: "'me' in owners and name='<DriveFolderName>'".
* addanyownerparentname|removeanyownerparentname <DriveFolderName> - The query is: "name='<DriveFolderName>'".

4.54.51

Fixed bug where "utf-8" was written to empty fields when todrive was specified.

4.54.50

Added nodetails option to gam create/update drivefileacl to allow suppression of the output of the ACL details.
gam create|add drivefileacl <TeamDriveEntityAdmin> anyone|(user <UserItem>)|(group <GroupItem>)|(domain <DomainName>)
        (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])] [expires|expiration <Time>] [sendemail] [emailmessage <String>] [showtitles] [nodetails]
gam update drivefileacl <TeamDriveEntityAdmin> <DriveFilePermissionIDorEmail>
        (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])] [expires|expiration <Time>] [removeexpiration [<Boolean>]] [showtitles] [nodetails]
gam <UserTypeEntity> create|add drivefileacl <DriveFileEntity> anyone|(user <UserItem>)|(group <GroupItem>)|(domain <DomainName>)
        (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])] [expires|expiration <Time>] [sendemail] [emailmessage <String>] [showtitles] [nodetails]
gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
        (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])] [expires|expiration <Time>] [removeexpiration [<Boolean>]] [showtitles] [nodetails]

4.54.49

Updated gam add filter to send actions to the API in a particular order so that Google will correctly identify duplicate filters.

Fixed bug in gam info user where primary field was not printed for addresses.

4.54.48

Fixed bug in gam update teamdrive command line parsing.

Added customtheme and color options to gam create teamdrive. These options are not supported in the API when creating a Team Drive so GAM
creates the Team Drive and then updates it with the specified values. If you use the theme|themeid option, no update is necessary as that
option is supported when creating a Team Drive.

gam <UserTypeEntity> create teamdrive <Name> [(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
* customtheme - set the backgroundImageFile property described here:  https://developers.google.com/drive/v3/reference/teamdrives
* color - set the Team Drive color

4.54.47

Added commands to stay compatible with Jay's Gam.
gam show teamdriveinfo <TeamDriveEntity>
gam <UserTypeEntity> show teamdriveinfo <TeamDriveEntity> adminaccess
gam <UserTypeEntity> show teamdriveinfo <TeamDriveEntity>

Equivalent GAMADVX-TD commands.
gam info teamdrive <TeamDriveEntity>
gam <UserTypeEntity> info teamdrive <TeamDriveEntity> adminaccess
gam <UserTypeEntity> info teamdrive <TeamDriveEntity>

4.54.46

Improved memory usage of print filelist/show filetree.

Added additional column headers to gam print users output when groups or licenses options are specified.
* groups - a column labeled GroupsCount is output indicating the number of groups to which the user belongs.
* licenses - a column labeled LicensesCount is output indicating the number of licenses the user holds.

Thanks to Jay for providing a color name table for use when specifying colors for calendars, drive folders and Team Drives.
For example, you can now specify purple instead of #800080.

<ColorName> ::=
        aliceblue|antiquewhite|aqua|aquamarine|azure|beige|bisque|black|blanchedalmond|blue|blueviolet|brown|burlywood|
        cadetblue|chartreuse|chocolate|coral|cornflowerblue|cornsilk|crimson|cyan|
        darkblue|darkcyan|darkgoldenrod|darkgray|darkgrey|darkgreen|darkkhaki|darkmagenta|darkolivegreen|darkorange|darkorchid|darkred|
        darksalmon|darkseagreen|darkslateblue|darkslategray|darkslategrey|darkturquoise|darkviolet|deeppink|deepskyblue|dimgray|dimgrey|dodgerblue|
        firebrick|floralwhite|forestgreen|fuchsia|gainsboro|ghostwhite|gold|goldenrod|gray|grey|green|greenyellow|
        honeydew|hotpink|indianred|indigo|ivory|khaki|
        lavender|lavenderblush|lawngreen|lemonchiffon|lightblue|lightcoral|lightcyan|lightgoldenrodyellow|lightgray|lightgrey|lightgreen|lightpink|
        lightsalmon|lightseagreen|lightskyblue|lightslategray|lightslategrey|lightsteelblue|lightyellow|lime|limegreen|linen|
        magenta|maroon|mediumaquamarine|mediumblue|mediumorchid|mediumpurple|mediumseagreen|mediumslateblue|
        mediumspringgreen|mediumturquoise|mediumvioletred|midnightblue|mintcream|mistyrose|moccasin|navajowhite|navy|
        oldlace|olive|olivedrab|orange|orangered|orchid|palegoldenrod|palegreen|paleturquoise|palevioletred|
        papayawhip|peachpuff|peru|pink|plum|powderblue|purple|red|rosybrown|royalblue|
        saddlebrown|salmon|sandybrown|seagreen|seashell|sienna|silver|skyblue|slateblue|slategray|slategrey|snow|springgreen|steelblue|
        tan|teal|thistle|tomato|turquoise|violet|wheat|white|whitesmoke|yellow|yellowgreen
<ColorHex> ::= #<Hex><Hex><Hex><Hex><Hex><Hex>
<ColorValue> ::= <ColorName>|<ColorHex>

<CalendarAttribute> ::=
        (backgroundcolor <ColorValue>)|
        (foregroundcolor <ColorValue>)
<DriveFileAttribute> ::=
        (folderColorRgb <ColorValue>)

Thanks to Jay for providing impetus to add customtheme and color options to gam update teamdrive.

gam <UserTypeEntity> update teamdrive <TeamDriveEntity> [name <Name>] [(theme|themeid <String>) | ([customtheme <DriveFileID> <Float> <Float> <Float>] [color <ColorValue>])]
gam <UserTypeEntity> show teamdrivethemes
* customtheme - set the backgroundImageFile property described here:  https://developers.google.com/drive/v3/reference/teamdrives
* color - set the Team Drive color

Google enhanced the ability of domain administrators to manage Team Drives.
See: https://developers.google.com/drive/v3/web/manage-teamdrives#managing_team_drives_for_domain_administrators

See: https://github.com/taers232c/GAMADV-XTD3/wiki/Domain-Administrator-Team-Drives

4.54.45

Code cleanup for email settings commands: arrows, language, pagesize, shortcuts, snippets, utf, webclips.

4.54.44

The following commands have been removed as the Google Email Audit API no longer supports them.

gam audit activity request <EmailAddress>
gam audit activity delete <EmailAddress> <RequestID>
gam audit activity download <EmailAddress> <RequestID>
gam audit activity status [<EmailAddress> <RequestID>]

The gam audit uploadkey command was enhanced to take the public key file name as a parameter.
gam audit uploadkey [<FileName>]
Previously, the key file was read from stdin; you had to do: cat <FileName> | gam audit uploadkey

4.54.43

Added two special-purpose commands for importing/exporting oauth2.txt.

Because of all the scopes that GAM uses, it has to split the set of scopes into two lists, get client credentials
for each list and then store them in a specially formatted oauth2.txt file that is base64 encoded.
GAM can now export its oauth2.txt into a JSON formatted file so its contents can be viewed.
gam oauth export [<FileName>]
If <FileName> is not specified, the JSON data is written to stdout.

Because of the special format of the oauth2.txt that GAM uses, it is not possible to directly use a traditional
oauth2.txt file from a third-party. GAM can now import traditional oauth2.txt files and convert them to its special format.
gam oauth import <FileName>

4.54.42

Added command gam show group-members that displays a hierarchical membership list for groups.
gam show group-members
        ([domain <DomainName>] [member <UserItem>])|[group <GroupItem>]|[select <GroupEntity>]
        [members] [managers] [owners] [depth <Number>]

For details, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Group-Membership

4.54.41

Previously, in gam print filelist, when the filepath option was specified, the paths column appeared after all path.n columns.
Now, the paths column will come before the path.n columns.

4.54.40

Extended gam print/show teamdrives role processing. Previously, a user had to directly have one of the specified roles
for a Team Drive for it to be included in the output. Now, the checkgroups options causes a Team Drive to be displayed
if a group has one of the specified roles and the user is a member of the group.

gam <UserTypeEntity> print teamdrives (role commenter|organizer|owner|reader|writer)* [checkgroups] [todrive [<ToDriveAttribute>]]
gam <UserTypeEntity> show teamdrives (role commenter|organizer|owner|reader|writer)* [checkgroups]

4.54.39

Added csv_output_line_terminator variable to gam.cfg.
csv_output_line_terminator
        Allowed values: cr, lf, crlf
        Designates character(s) used to terminate the lines of a CSV file.
        For Linux and Mac OS, this would typically be lf.
        For Windows, this would typically be crlf.
        Default: lf
        Environment variable: GAM_CSV_OUTPUT_LINE_TERMINATOR

4.54.38

By default, Gam displays all Team Drives to which the user has access; you can limit the display
by using the `role` option; multiple instances of `role` are allowed.

gam <UserTypeEntity> print teamdrives (role commenter|organizer|owner|reader|writer)* [todrive [<ToDriveAttribute>]]
gam <UserTypeEntity> show teamdrives (role commenter|organizer|owner|reader|writer)*

4.54.37

Thanks to Jay for suggesting extending gam delete asps to delete all of a user's Application Specific Passwords or a list of ASPs.
gam <UserTypeEntity> delete asps|applicationspecificpasswords all|<ASPIDList>

Extended commands relating to administrators.
gam print privileges [todrive [<ToDriveAttribute>]]
gam show privileges
gam print adminroles|roles [todrive [<ToDriveAttribute>]] [privileges]
gam show adminroles|roles [privileges]
gam print admins [todrive [<ToDriveAttribute>]] [user <UserItem>] [role <RoleItem>]
gam show admins [user <UserItem>] [role <RoleItem>]

4.54.36

Added formatjson argument to gam print groups/users to cause output to be in JSON format.
By default, when writing CSV files, Gam uses a quote character of double quote ". The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
When using the gam print groups/users commands with the formatjson option, double quotes are used extensively in the data resulting in hard to read/process output.
The quotechar <Character> option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
quotechar defaults to gam.cfg/csv_output_quote_char.

gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [maxresults <Number>] [allfields|([settings] <GroupFieldName>* [fields <GroupFieldNameList>])]
        [members|memberscount] [managers|managerscount] [owners|ownerscount] [countsonly]
        [convertcrnl] [delimiter <Character>] [sortheaders] [formatjson] [quotechar <Character>]
gam [<UserTypeEntity>] print users [todrive [<ToDriveAttribute>]] ([domain <DomainName>] [query <QueryUsers>] [deleted_only|only_deleted])|[select <UserTypeEntity>]
        [groups] [license|licenses|licence|licences] [emailpart|emailparts|username] [schemas|custom all|<SchemaNameList>]
        [orderby <UserOrderByFieldName> [ascending|descending]]
        [userview] [basic|full|allfields | <UserFieldName>* | fields <UserFieldNameList>]
        [delimiter <Character>] [sortheaders] [formatjson] [quotechar <Character>]

4.54.35

Allow user attribute gender to be cleared.
<UserAttribute> ::=
        (gender clear|(female|male|unknown|(other <String>) [addressmeas <String>]))

4.54.34

Added new user attributes.
<UserAttribute> ::=
        (gender type female|male|unknown|(other <String>) [addressmeas <String>])|
        (keyword|keywords clear|(type occupation|outlook|(custom <string>) <String>))|
        (language|languages clear|<LanguageList>)|
<UserFieldName> ::=
        gender|
        keyword|keywords|
        language|languages|

4.54.33

Added the ability to select subfields in gam show fileinfo and gam print filelist; these fields are included
in <DriveFieldName> and <DriveFieldNameList>.

<DriveParentsSubfieldName> ::=
        parents.id

<DrivePermissionsSubfieldName> ::=
        permissions.additionalroles|
        permissions.allowfilediscovery|
        permissions.deleted|
        permissions.displayname|
        permissions.domain|
        permissions.emailaddress|
        permissions.expirationdate|
        permissions.expirationtime|
        permissions.id|
        permissions.name|
        permissions.photolink|
        permissions.role|
        permissions.teamdrivepermissiondetails|
        permissions.type|
        permissions.withlink

<DrivePropertiesSubfieldName> ::=
        properties.key|
        properties.value|
        properties.visibility

<DriveLastModifyingUserSubfieldName> ::=
        lastmodifyinguser.displayname|
        lastmodifyinguser.emailaddress|
        lastmodifyinguser.isauthenticateduser|
        lastmodifyinguser.me|
        lastmodifyinguser.name|
        lastmodifyinguser.permissionid|
        lastmodifyinguser.photolink|
        lastmodifyinguser.picture

<DriveSharingUserSubfieldName> ::=
        sharinguser.displayname|
        sharinguser.emailaddress|
        sharinguser.isauthenticateduser|
        sharinguser.me|
        sharinguser.name|
        sharinguser.permissionid|
        sharinguser.photolink|
        sharinguser.picture

<DriveTrashingUserSubfieldName> ::=
        trashinguser.displayname|
        trashinguser.emailaddress|
        trashinguser.isauthenticateduser|
        trashinguser.me|
        trashinguser.name|
        trashinguser.permissionid|
        trashinguser.photolink|
        trashinguser.picture

gam <UserTypeEntity> show fileinfo <DriveFileEntity> [filepath] [allfields|<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])*
gam <UserTypeEntity> print|show filelist [todrive [<ToDriveAttribute>]] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>]
        [select <DriveFileEntityListTree>] [selectsubquery <QueryDriveFile>] [mimetype [not] <MimeTypeList>] [depth <Number>] [showparent]
        [filepath] [buildtree] [allfields|<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])* [delimiter <Character>]

4.54.32

Fixed additional error handling in gam copy drivefile.

4.54.31

Added additional error handling to gam copy drivefile.

4.54.30

Code cleanup.

4.54.29

Added showparent option to gam print filelist. By default, when the select <DriveFileEntityListTree> option is used,
only the children of the selected folder are displayed; the showparent option causes the selected folder to also be displayed.
gam <UserTypeEntity> print|show filelist [todrive [<ToDriveAttribute>]] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>]
        [select <DriveFileEntityListTree>] [selectsubquery <QueryDriveFile>] [mimetype [not] <MimeTypeList>] [depth <Number>] [showparent]
        [filepath] [buildtree] [allfields|<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])* [delimiter <Character>]

4.54.28

Added retainrole reader|commenter|writer|editor|none option to gam claim ownership to allow specification of the role
that the original owner will retain; by default, the orginal owner retains writer access.
gam <UserTypeEntity> claim ownership <DriveFileEntity> [includetrashed]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*
        [skipids <DriveFileEntity>] [skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>]
        [restricted [<Boolean>]] [writerscanshare|writerscantshare [<Boolean>]] [keepuser | (retainrole reader|commenter|writer|editor|none)]
        [preview] [filepath] [buildtree] [todrive [<ToDriveAttribute>]]

For details, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Drive-Ownership

4.54.27

Flush stdout before every write to stderr to keep output in sync.

4.54.26

Handle input errors in gam update customer.

4.54.25

Improve handling of Google Internal errors.

4.54.24

Added batchsuborgs [<Boolean>] option to gam print orgs and gam show orgtree to handle a special case when the
account has thousands of organizational units. By default, these commands issue a single API call to get the
list of organizational units. If the number is large, greater than 4000 in an observed case, the API call may fail.
When batchsuborgs is specified, Gam gets all of the top level org units with one API call; then Gam uses batch processing
in subsequent API calls to get the sub org units. There is no benefit to using this option unless the commands fail
without it. The number of sub org units processed in each batch is controlled by batch_size in gam.cfg.

gam print orgs|ous [todrive [<ToDriveAttribute>]] [showparent] [toplevelonly] [fromparent <OrgUnitItem>]
        [allfields|<OrgUnitFieldName>*|(fields <OrgUnitFieldNameList>)] [convertcrnl] [batchsuborgs [<Boolean>]]
gam show orgtree [fromparent <OrgUnitItem>] [batchsuborgs [<Boolean>]]

4.54.23

Code cleanup.

4.54.22

Correct processing of owneremail option in gam info/print courses.

4.54.21

Eliminate superfluous header `capabilities` in gam print filelist.

4.54.20

Handle uncopyable files in gam copy drivefile.

4.54.19

Added additional error handling to gam copy drivefile.

4.54.18

When todrive is specified on a print command and todrive_conversion = true in gam.cfg, Gam checks to see if the CSV file being uploaded meets
Google's requirements for the maximum number of cells and columns for a Google Sheet. If the requirements are met, the file is uploaded as a Google Sheet,
otherwise it is uploaded as a CSV file. The limit for the number of columns is 256, the limit for the maximum number of cells has been raised to 2000000.

If a group has a member of type CUSTOMER (all users in domain are members), the gam print group-members command puts the Customer ID in the
id column and leaves the email column blank in the CSV file. This means that the email column of the CSV file can't be used in
subsequent commands processing group membership because the blank value will cause an error. Gam now puts the Customer ID in the id and email columns
to avoid this error. All Gam commands that process group membership properly recognize the Customer ID in the email column.

Users that have applied to join a group or who have been invited to join a group but have not accepted are in a PENDING state. If you
print the group membership, the PENDING members do not appear. However, if you try to add a member to a group and the member is in
the PENDING stete, you will get a duplicate member error. When Gam gets a duplicate member error from the API, it checks to see if the member is
already in the group; if so, the duplicate error is appropriate. If the member is not found in the group, then it must be in the PENDING state.
In this case Gam deletes and adds the user which changes it from the PENDING state to the ACTIVE state.
Thanks to Jay for suggesting this solution.

4.54.17

Added states <CourseStateList> option to gam print courses/course-participants to allow selection of courses by state.

<CourseState> ::= active|archived|provisioned|declined
<CourseStateList> ::= "<CourseState>(,<CourseState>)*"
gam print courses [todrive [<ToDriveAttribute>]] (course|class <CourseID>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [owneremail] [alias|aliases][delimiter <Character>] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
gam print course-participants [todrive [<ToDriveAttribute>]] (course|class <CourseID>)*|([teacher <UserItem>] [student <UserItem>] [states <CourseStateList>])
        [show all|students|teachers]

By default, all course states are selected.

4.54.16

Added quick option to gam info groups/users as a way to quickly suppress some output.
* For groups, quick is equivalent to noaliases nousers
* For users, quick is equivalent to noaliases nogroups nolicenses noschemas

gam info groups <GroupEntity> [members] [managers] [owners] [quick] [noaliases] [nousers] [groups] <GroupFieldName>* [fields <GroupFieldNameList>] [formatjson]
gam info users <UserTypeEntity> [quick] [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas|custom <SchemaNameList>]
        [userview] <UserFieldName>* [fields <UserFieldNameList>] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)] [formatjson]
gam <UserTypeEntity> info users [quick] [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas|custom <SchemaNameList>]
        [userview] <UserFieldName>* [fields <UserFieldNameList>] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)] [formatjson]

4.54.15

Added maxactivities <Number> option to gam report to allow specification of the maximum number of activities to report.

gam report users|user [todrive [<ToDriveAttribute>]] [nodatechange] [maxresults <Number>] [maxactivities <Number>]
        [date <Date>] [(user all|<UserItem>)|(select <UserTypeEntity>)] [filter|filters <String>] [fields|parameters <String>]
gam report admin|calendar|calendars|drive|docs|doc|groups|group|logins|login|mobile|tokens|token [todrive [<ToDriveAttribute>]] [maxresults <Number>] [maxactivities <Number>]
        [([start <Time>] [end <Time>])|yesterday] [(user all|<UserItem>)|(select <UserTypeEntity>)] [event <String>] [filter|filters <String>] [ip <String>] [countsonly] [summary]

(n.b., maxresults <Number> limits the number of activities downloaded per API call, not the total number of activities.)

4.54.14

Make `ERROR: 500: unknownError - Unknown` recoverable in Drive operations.

4.54.13

Fixed bug where <SpreadsheetJSONRangeValuesList> was not handled properly.

4.54.12

Added commands to create, update and display information about spreadsheets.

gam <UserTypeEntity> create sheet json <SpreadsheetJSONCreateRequest> [formatjson]
        [parentid <DriveFolderID>] | [parentname <DriveFolderName>] | [anyownerparentname <DriveFolderName>]
        [teamdriveparentid <DriveFolderID>] [teamdriveparent <TeamDriveName>] [teamdriveparentname <DriveFolderName>]
gam <UserTypeEntity> update sheet <DriveFileEntity> json <SpreadsheetJSONUpdateRequest> [formatjson]
gam <UserTypeEntity> info sheet <DriveFileEntity> (range <SpreadsheetRange>)* [includegriddata [<Boolean>]] [formatjson]

For details, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Spreadsheets

4.54.11

Added json <SpreadsheetJSONRangeValuesList> argument to gam append/update sheetrange so that these commands can directly process the output
from gam print sheetrange formatjson.

In the following lines defining Spreadsheet items, the following right-hand side characters are literal: {}[],'":
The following right-hand side characters are part of the meta-syntax: <>()*|
<SpreadsheetRange> ::= <String>
<SpreadsheetValue> ::= "<String>"|<Number>|true|false
<SpreadsheetValueList> ::= [<SpreadsheetValue>(,<SpreadsheetValue>)*]
<SpreadsheetJSONRangeValues> ::= {"range": <String>, "values": [<SpreadsheetValueList>(,<SpreadsheetValueList>)*], "majorDimension": ROWS|COLUMNS}
<SpreadsheetJSONRangeValuesList> ::= '[<SpreadsheetJSONRangeValues>(,<SpreadsheetJSONRangeValues>)*]'

gam <UserTypeEntity> append sheetrange <DriveFileEntity> json <SpreadsheetJSONRangeValues>|<SpreadsheetJSONRangeValuesList> [overwrite|insertrows]
        [raw|userentered] [formula|formattedvalue|unformattedvalue] [serialnumber|formattedstring]
        [includevaluesinresponse [<Boolean>]] [formatjson]
gam <UserTypeEntity> update sheetrange <DriveFileEntity> (json <SpreadsheetJSONRangeValues>|<SpreadsheetJSONRangeValuesList>)+
        [raw|userentered] [formula|formattedvalue|unformattedvalue] [serialnumber|formattedstring]
        [includevaluesinresponse [<Boolean>]] [formatjson]

The output from gam append/update/clear/show sheetranges formatjson has been changed to match the style of output from gam print sheetranges formatjson.
The output will look like this: {"User": "user@domain.com", "spreadsheetId": "xxxxx", "JSON": <Command JSON output here>}

Added csv_input_quote_char and csv_output_quote_char variables to gam.cfg.

By default, when writing CSV files, Gam uses a quote character of double quote ". The quote character is used to enclose columns that contain
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
By default, when reading CSV files, Gam uses a quote character of double quote ". Previously, Gam could not read CSV files that used a different quote character.

csv_input_quote_char
        A one-character string used to quote fields containing special characters, such as the csv_input_column_delimiter or csv_input_quote_char,
        or new-line characters. This typically used when reading CSV files produced by gam print ranges formatjson where csv_output_char
        was set to a value other than double quote.
        Defaults: '"'
        Environment variable: GAM_CSV_INPUT_QUOTE_CHAR

csv_output_quote_char
        A one-character string used to quote fields containing special characters, such as the csv_output_column_delimiter or csv_output_quote_char,
        or new-line characters. This is most useful with gam print sheetranges formatjson where the JSON column contains many
        double quotes; by setting csv_output_quote_char to a single quote, the output is much cleaner.
        Defaults: '"'
        Environment variable: GAM_CSV_OUTPUT_QUOTE_CHAR

When specifying a CSV file as input, you can define the quote character as part of the file specification. This would typically be used when you have
been supplied a CSV file from an external source that uses a different quote character.

<CrOSTypeEntity> ::=
        (croscsvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>])|
        (csvkmd cros|cros_ous|cros_ous_and_children <FileName> [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>]
                keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                (matchfield <FieldName> <RegularExpression>)*
                [datafield <FieldName>(:<FieldName)* [delimiter <Character>]])
<UserTypeEntity> ::=
        (csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>])|
        (csvkmd users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>]
                keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
                (matchfield <FieldName> <RegularExpression>)*
                [datafield <FieldName>(:<FieldName)* [delimiter <Character>]])
<CSVkmdSelector> ::=
        csvkmd <FileName> [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>]
               keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
               subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <Character>]
               (matchfield <FieldName> <RegularExpression>)*
               [datafield <FieldName>(:<FieldName)* [delimiter <Character>]]
<FileSelector> ::=
        (csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <Character>])
gam csv <FileName>|- [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>
gam loop <FileName>|- [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>

When specifying a CSV file as output, you can define the quote character as part of the file specification. This would typically be used when you have
to supply a CSV file to an external source that uses a different quote character.
<Redirect> ::=
        redirect csv <FileName> [multiprocess] [append] [noheader] [charset <Charset>] [columndelimiter <Character>] [quotechar <Character>]

When using the gam print sheetranges command with the formatjson option, double quotes are used extensively in the data resulting in hard to read output.
This command allows you to define the quote character directly.

gam <UserTypeEntity> print sheetrange <DriveFileEntity> (range <SpreadsheetRange>)+  [todrive [<ToDriveAttribute>]]
        [rows|columns] [formula|formattedvalue|unformattedvalue] [serialnumber|formattedstring]
        [formatjson] [quotechar <Character>]

4.54.10

Clean up gam import/insert message code.

4.54.09

Added formatjson to gam clear sheetrange.
    gam <UserTypeEntity> clear sheetrange <DriveFileEntity> (range <SpreadsheetRange>)+
        [formatjson]

4.54.08

Fixed an error in gam append/update sheetrange that caused an exception when includevaluesinresponse was not specified.

4.54.07

Added commands to manipulate spreadsheets.

    <SpreadsheetRange> ::= <String>
    <SpreadsheetValue> ::= "<String>"|<Number>|true|false
    <SpreadsheetValueList> ::= [<SpreadsheetValue>(,<SpreadsheetValue>)*]
    <SpreadsheetJSONValues> ::= '{"values": [<SpreadsheetValueList>(,<SpreadsheetValueList>)*]}'

    gam <UserTypeEntity> append sheetrange <DriveFileEntity> (range <SpreadsheetRange> <SpreadsheetJSONValues>) [overwrite|insertrows]
        [raw|userentered] [rows|columns] [formula|formattedvalue|unformattedvalue] [serialnumber|formattedstring]
        [includevaluesinresponse [<Boolean>]] [formatjson]
    gam <UserTypeEntity> update sheetrange <DriveFileEntity> (range <SpreadsheetRange> <SpreadsheetJSONValues>)+
        [raw|userentered] [rows|columns] [formula|formattedvalue|unformattedvalue] [serialnumber|formattedstring]
        [includevaluesinresponse [<Boolean>]] [formatjson]

    gam <UserTypeEntity> clear sheetrange <DriveFileEntity> (range <SpreadsheetRange>)+

    gam <UserTypeEntity> print sheetrange <DriveFileEntity> (range <SpreadsheetRange>)+  [todrive [<ToDriveAttribute>]]
        [rows|columns] [formula|formattedvalue|unformattedvalue] [serialnumber|formattedstring]
        [formatjson]
    gam <UserTypeEntity> show sheetrange <DriveFileEntity> (range <SpreadsheetRange>)+
        [rows|columns] [formula|formattedvalue|unformattedvalue] [serialnumber|formattedstring]
        [formatjson]

For details, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Spreadsheets

To use these commands, you must update your project to use the Google Sheets API and you must update your service account authorization.
You can update your project manually or with the command: gam update project
Update your service account authorization with the command: gam user user@domain.com check serviceaccount

4.54.06

Calendars can now be transferred from one user to another.
    <DataTransferService> ::= googledrive|gdrive|drive|"drive and docs"|calendar
    gam create datatransfer|transfer <OldOwnerID> <DataTransferService> <NewOwnerID> [private|shared|all] (<ParameterKey> <ParameterValue>)*

4.54.05

Update code to reflect changes in PyInstaller.

4.54.04

Update passlib to 1.7.1.

4.54.03

Import a message into a user's mailbox, with standard email delivery scanning and classification similar to receiving via SMTP.
API Documentation: https://developers.google.com/gmail/api/v1/reference/users/messages/import
    gam <UserTypeEntity> import message (<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)* (addlabel <LabelName>)*
        (textmessage <String>)|(textfile <FileName> [charset <CharSet>]) (htmlmessage <String>)|(htmlfile <FileName> [charset <CharSet>])
        (replace <Tag> <String>)* (attach <FileName>)*
        [deleted [<Boolean>]] [nevermarkspam [<Boolean>]] [processforcalendar [<Boolean>]]

Insert a message into a user's mailbox similar to IMAP APPEND, bypassing most scanning and classification.
API Documentation: https://developers.google.com/gmail/api/v1/reference/users/messages/insert
    gam <UserTypeEntity> insert message (<SMTPDateHeader> <Time>)* (<SMTPHeader> <String>)* (header <String> <String>)* (addlabel <LabelName>)*
        (textmessage <String>)|(textfile <FileName> [charset <CharSet>]) (htmlmessage <String>)|(htmlfile <FileName> [charset <CharSet>])
        (replace <Tag> <String>)* (attach <FileName>)*
        [deleted [<Boolean>]]

For details, see: https://github.com/taers232c/GAMADV-XTD3/wiki/Users-Gmail-Messages-Threads

4.54.02

Add a User column to the CSV file produced by gam print teamdrives.

4.54.01

In gam update cros, the handling of the quickcrosmove option has changed.
See: https://github.com/taers232c/GAMADV-XTD3/wiki/ChromeOS-Devices

4.54.00

File display

Added showmimetype [not] <MimeTypeList> option to print|show filelist and show filetree to allow filtering of the output by MIME type.
By default, all types of files and folders are displayed. You can specify a list of MIME types to display or a list of MIME types to suppress.
    <MimeType> ::=
        gdoc|gdocument|
        gdrawing|
        gfolder|gdirectory|
        gform|
        gfusion|
        gmap|
        gpresentation|
        gscript|
        gsite|
        gsheet|gspreadsheet|
        <String>
    <MimeTypeList> ::= "<MimeType>(,<MimeType>)*"
    gam <UserTypeEntity> print|show filelist [todrive [<ToDriveAttribute>]] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>]
        [select <DriveFileEntityListTree>] [selectsubquery <QueryDriveFile>] [mimetype [not] <MimeTypeList>] [depth <Number>]
        [filepath] [buildtree] [allfields|<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])* [delimiter <String>]
    gam <UserTypeEntity> show filetree [anyowner|(showownedby any|me|others)]
        [select <DriveFileEntityListTree>] [selectsubquery <QueryDriveFile>] [showmimetype [not] <MimeTypeList>] [depth <Number>]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*

The gam print|show filelist command has been updated to provide two modes of operation when you use
the select <DriveFileEntityListTree> option. Currently, GAM downloads the user's entire list of files with one API call
(of course, there may be many entries downloaded) and then uses that information to build a file tree. The file tree is used to
display the list of files/folders contained in the selected folder. Some GAM users find this big download confusing.

The new mode, which will be the default when you use the select <DriveFileEntityListTree> option, makes recursive API calls to get the children
of the specified folder to display. The new mode will make N API calls instead of 1 API call; N is the number of folders
recursively beneath the specified folder. Depending on the number of folders, this mode may be faster even though
additional API calls are being made.

The buildtree argument specifies that you want the first mode (build file tree) mode of operation.
    gam <UserTypeEntity> print|show filelist [todrive [<ToDriveAttribute>]] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [<DriveFileQueryShortcut>]
        [select <DriveFileEntityListTree>] [showmimetype [not] <MimeTypeList>] [depth <Number>]
        [filepath] [buildtree] [allfields|<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])* [delimiter <String>]

The filepath option is used to display the path to each file. If buildtree is specified, you will see the full path to each file.
If buildtree is not specified, you will see the relative file path starting from the top level folder being displayed.

If you don't use the select <DriveFileEntityListTree> option, the user's entire list of folders is downloaded and the filepath option will show
the full path to each file.

Claim ownership

The gam claim ownership command has been updated to provide two modes of operation.
Currently, GAM downloads the user's entire list of files with one API call (of course, there may be many
entries downloaded) and then uses that information to build a file tree. The file tree is used to
recursively find the children of the specified folders to transfer. Some GAM users find this big download
confusing.

The new mode, which will be the default, makes recursive API calls to get the children of the specified
folders to transfer. The new mode will make N API calls instead of 1 API call; N is the number of folders
recursively beneath the specified folder. Depending on the number of folders, this mode may be faster even though
additional API calls are being made.

The buildtree argument specifies that you want the first mode (build file tree) mode of operation.
    gam <UserTypeEntity> claim ownership <DriveFileEntity> [skipids <DriveFileEntity>] [skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>]
        [includetrashed] [restricted [<Boolean>]] [writerscantshare [<Boolean>]]
        [filepath] [preview] [buildtree] [todrive [<ToDriveAttribute>]]

Typically, the filepath option is used with the preview option so you can verify what files are going to be transferred.
If buildtree is specified, you will see the full path to each file. If buildtree is not specified, you will see the
relative file path starting from the top level folder being transferred.

User attributes

There are several user attributes that can have multiple values; each value can be marked notprimary or primary.
It is a Google API error to mark more than one value primary; Gam now checks that only one value is marked primary.
The affected attributes are: addresses, ims, organizations, posixaccounts, phones, websites.
For posixaccounts, no two values with the same systemId can be marked primary.

4.53.26

With thanks to Jay for the initial code, new user attributes have been added.
See: https://developers.google.com/admin-sdk/directory/v1/reference/users#resource

    <UserAttribute> ::=
        (location|locations clear|([type default|desk|<String>] area <String> [building|buildingid <String>] [floor|floorname <String>] [section|floorsection <String>] [desk|deskcode <String>] endlocation))|
        (posix|posixaccounts clear|(username <String> uid <Integer> [gid <Integer>] [system|systemid <String>] [home|homedirectory <String>] [shell <String>] [gecos <String>] [primary <Boolean>] endposix))|
        (ssh|sshkeys|sshpublickeys clear|(key <String> [expires <Integer>] endssh))|

* location - area <String> is required; all other items are optional.
* posix - username <String> and uid <Integer> are required; all other items are optional. The uid must be >= 1000.
* ssh - key <strings> is required; ; all other items are optional.

4.53.25

Fix CSV file reader to accept universal newlines; this allows Mac users to save files from Excel as Comma Separated Values (.csv) files;
that format uses \r as a line terminator and it was not recognized by Gam.

4.53.24

Added command to print Gmail labels to a CSV file.
    gam <UserTypeEntity> print labels|label [onlyuser [<Boolean>]] [showcounts [<Boolean>]] [todrive [<ToDriveAttribute>]]

Added select <DriveFileEntity> argument to gam transfer drive to allow transferring selected files/folders of a source user
to a target user rather that all of the source users file/folders.
    gam <UserTypeEntity> transfer drive <UserItem> [select <DriveFileEntity>] [keepuser | (retainrole reader|commenter|writer|editor)]
        (orderby <DriveFileOrderByFieldName> [ascending|descending])*
        [(targetfolderid <DriveFolderID>)|(targetfoldername <DriveFolderName>)] [targetuserfoldername <DriveFolderName>]
        [preview] [todrive [<ToDriveAttribute>]]

Added owneremail option to gam info/print courses to have Gam display the course owners email address. There is an extra API call per course to
get the email address.
    gam info course <CourseID> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
    gam info courses <CourseEntity> [owneremail] [alias|aliases] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]
    gam print courses [todrive [<ToDriveAttribute>]] (course|class <CourseID>)*|([teacher <UserItem>] [student <UserItem>])
        [owneremail] [alias|aliases][delimiter <String>] [show all|students|teachers] [countsonly]
        [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]

4.53.23

Fixed error in gam transfer ownership where My Drive was included in list of files to transfer; this, of course, is not allowed.

4.53.22

Anywhere you can specify an absolute <Date> or <DateTime> value,
you can now specify a positive or negative offset from the current time.
    <Date> ::=
        <Year>-<Month>-<Day> |
        (+|-)<Number>(d|w)
    <DateTime> ::=
        <Year>-<Month>-<Day>(<Space>|T)<Hour>:<Minute> |
        (+|-)<Number>(m|h|d|w)
m - minutes
h - hours
d - days
w - weeks

Example: gam user user@domain.com print filerevisions drivefilename "Test File" select range -10d -5d

4.53.21

Fix error when specifying delta <Time> and timezone is utc.

4.53.20

Handle Unicode issues in error messages with accented/extended characters.

Thanks to DanielX for suggesting the following enhancement. Anywhere you can specify an absolute <Time> value,
you can now specify a positive or negative offset from the current time.
    <Time> ::=
        <Year>-<Month>-<Day>(<Space>|T)<Hour>:<Minute>:<Second>[.<MilliSeconds>](Z|(+|-(<Hour>:<Minute>))) |
        (+|-)<Number>(m|h|d|w)
m - minutes
h - hours
d - days
w - weeks

Example: gam report logins start -1w end -1d

4.53.19

Improve filepath display in gam transfer ownership.

4.53.18

The gam transfer ownership command has been updated to provide two modes of operation.
Currently, GAM downloads the user's entire list of files with one API call (of course, there may be many
entries downloaded) and then uses that information to build a file tree. The file tree is used to
recursively find the children of the specified folders to transfer. Some GAM users find this big download
confusing.

The new mode, which will be the default, makes recursive API calls to get the children of the specified
folders to transfer. The new mode will make N API calls instead of 1 API call; N is the number of folders
recursively beneath the specified folder. Depending on the number of folders, this mode may be faster even though
additional API calls are being made.

The buildtree argument specifies that you want the first mode (build file tree) mode of operation.
    gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem> [includetrashed] (orderby <DriveFileOrderByFieldName> [ascending|descending])*
        [filepath] [preview] [buildtree] [todrive [<ToDriveAttribute>]]

Typically, the filepath option is used with the preview option so you can verify what files are going to be transferred.
If buildtree is specified, you will see the full path to each file. If buildtree is not specified, you will see the
relative file path starting from the top level folder being transferred.

Added notify option to gam printers add/sync to allow control over sending notifications when a printer is shared with a user.
    gam printer|printers <PrinterIDEntity> add user|manager|owner <PrinterACLScopeEntity> [notify]
    gam printer|printers <PrinterIDEntity> sync user|manager|owner <PrinterACLScopeEntity> [notify]
If notify is not specified, no notification will be sent.

4.53.17
Fixed code so that forwardingaddress is recognized as documented.
    gam <UserTypeEntity> delete forwardingaddress|forwardingaddresses <EmailAddressEntity>

4.53.16

Due to Google limitations, Gam now preserves the case of all aliases when calling the Directory API.
In particular, you must use the exact case of an alias in order to delete it.

4.53.15

Updated todrive to allow choosing whether to open a browser to view the uploaded file.
The default value is the value of no_browser from gam.cfg.
    <ToDriveAttribute> ::=
        (tduser <EmailAddress>)|
        (tdtitle <String>)|
        (tdparent id:<DriveFolderID>|<DriveFolderName>)|(tdfileid <DriveFileID>)
        (tdtimestamp [<Boolean>] [tddaysoffset <Number>] [tdhoursoffset <Number])|
        (tdlocalcopy [<Boolean>])|
        (tdnobrowser [<Boolean>])

4.53.14

Correct errors in gam update group add|remove|sync|update member when the members are specified by user/group IDs rather than email addresses.

4.53.13

Corrected gam delete guardian to properly delete a guardian specified by email address.

4.53.12

Updated todrive to allow updating an existing file rather than creating a new file.
<ToDriveAttribute> ::=
        (tduser <EmailAddress>)|
        (tdtitle <String>)|
        (tdparent id:<DriveFolderID>|<DriveFolderName>)|(tdfileid <DriveFileID>)
        (tdtimestamp [<Boolean>] [tddaysoffset <Number>] [tdhoursoffset <Number])|
        (tdlocalcopy [<Boolean>])

tdfileid <DriveFileID> specifies the file to be updated.

4.53.11

Recoded gam print|show drivesettings to provide more flexibility; print and show are now separate
and you can select the desired output fields.
The field names are always the Google Drive REST API v3 native names; drive_v3_native_names in gam.cfg is not used.

<DriveSettingsFieldName> ::=
        appinstalled|
        exportformats|
        foldercolorpalette|
        importformats|
        largestchangeid|
        limit|
        maximportsizes|
        maxuploadsize|
        name|
        permissionid|
        rootfolderid|
        teamdrivethemes|
        usage|
        usageindrive|
        usageindrivetrash
<DriveSettingsFieldNameList> ::= "<DriveSettingsFieldName>(,<DriveSettingsFieldName>)*"

gam <UserTypeEntity> print drivesettings [todrive [<ToDriveAttribute>]] [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)] [delimiter <String>]
gam <UserTypeEntity> show drivesettings [allfields|<DriveSettingsFieldName>*|(fields <DriveSettingsFieldNameList>)] [delimiter <String>]

If no fields are selected, these fields will be displayed:
    name,appInstalled,largestChangeId,limit,maxUploadSize,permissionId,rootFolderId,usage,usageInDrive,usageInDriveTrash

When executing commands in batches, GAM may exceed Google's rate limits on command execution; added inter_batch_wait to gam.cfg to allow rate limiting.
    inter_batch_wait
        When processing items in batches, how many seconds should GAM wait between batches
        Default: 0
        Range: 0 - 60
        Environment variable: GAM_INTER_BATCH_WAIT
For example, when removing users from groups, batch_size = 25 and inter_batch_wait = 2 seems to avoid exceeding the rate limit.

4.53.10

Handle additional API errors when updating the teacher of a course.

4.53.09

Added teacher <UserItem> to gam update course as Google now supports updating the teacher for a course.
See: https://support.google.com/edu/classroom/answer/7477648

4.53.08

Fix coding error in gam print groups.

4.53.07

In <CrOSTypeEntity>, a selection name was changed to make it consistent with other selection names.
If you have scripts that use the previous name, uopdate them to have the current name.
Previous: csvcros <FieldName>(:<FieldName>*)
Current:  croscsvdata <FieldName>(:<FieldName>*)

Handle quotaExceeded errors when deleting members from groups.

Fix coding error in gam add permissions.

4.53.06

Added new method (query:orgunitpath:<OrgUnitPath>) of specifying CrOS OU for backwards compatibility with Jay's version.
    <CrOSItem> ::= <CrOSID>|(query:<QueryCrOS>)|(query:orgunitpath:<OrgUnitPath>)|(query <QueryCrOS>)
    <CrOSEntity> ::= <CrOSItem> | <CrOSList> | <FileSelector> | <CSVkmdSelector>
    gam info cros <CrOSEntity> [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]
    gam update cros <CrOSEntity> (<CrOSAttribute>+ [quickcrosmove [<Boolean>]])|(action <CrOSAction> [acknowledge_device_touch_requirement])
Example: move CrOS devices from one OU to another:
    gam update cros query:orgunitpath:/Students/2017 ou /Students/2018
The simpler way to do this is:
    gam cros_ou /Students/2017 update ou /Students/2018

Google has introduced a new, faster method for moving CrOS devices to a new OU. The quickcrosmove argument in the
following commands causes Gam to use the new method; if not specified, the previous individual/batch method is used.
In the CrOS update commands, the quickcrosmove is applicable only if the OU is the only <CrOSAttribute> being updated;
if other <CrOSAttribute> are being updated, each CrOS device is updated individually.
In the new method, Google doesn't seem to do any error checking of the CrOS deviceIds, there is no error message
given if invalid CrOS deviceIds are specified.
    gam update cros <CrOSEntity> (<CrOSAttribute>+ [quickcrosmove [<Boolean>]])|(action <CrOSAction> [acknowledge_device_touch_requirement])
    gam <CrOSTypeEntity> update (<CrOSAttribute>+ [quickcrosmove [<Boolean>]])|(action <CrOSAction> [acknowledge_device_touch_requirement])
    gam update org|ou <OrgUnitItem> add|move <CrOSTypeEntity> [quickcrosmove [<Boolean>]]
    gam update orgs|ous <OrgUnitEntity> add|move <CrOSTypeEntity> [quickcrosmove [<Boolean>]]
If <Boolean> is not specified for quickcrosmove, the default is True.

4.53.05

Improved performance of gam print group-members when recursive noduplicates is specified.

Added additional error checking for gam add drivefileacl.

4.53.04

Fix coding error in gam print groups that caused trap.

4.53.03

Changed anyparentname to sharedparentname in gam add/copy/update drivefile.

4.53.02

Added members, managers, owners arguments to gam info group and gam print group-members to allow display of specific roles.
By default, all members, managers and owners are displayed.
    gam info group|groups <GroupEntity> [members] [managers] [owners] [nousers] [noaliases] [groups] <GroupFieldName>* [fields <GroupFieldNameList>] [formatjson]
    gam print group-members|groups-members [todrive [<ToDriveAttribute>]] ([domain <DomainName>] [member <UserItem>])|[group <GroupItem>]|[select <GroupEntity>]
        [members] [managers] [owners] [membernames] <MembersFieldName>* [fields <MembersFieldNameList>] [userfields <UserFieldNameList>] [recursive [noduplicates]]

Added sharedparentname argument to gam add/copy/update drivefile to allow specifying a parent folder owned by anyone,
not just the user in the command. This is typically used to specify a shared folder.
    <DriveFileAddAttribute> ::=
        <DriveFileAttribute>|
        ignoredefaultvisibility|
        (modifieddate|modifiedtime <Time>)|
        (parentid <DriveFolderID>)|
        (parentname <DriveFolderName>)|
        (sharedparentname <DriveFolderName>)|
        (teamdriveparent <TeamDriveName>)|
        (teamdriveparentid <TeamDriveID>|<DriveFolderID>)|
        (teamdriveparentname <DriveFolderName>)|
        usecontentasindexabletext
    gam <UserTypeEntity> add drivefile [drivefilename <DriveFileName>] <DriveFileAddAttribute>*

    <DriveFileCopyAttribute> ::=
        <DriveFileAttribute>|
        ignoredefaultvisibility|
        (parentid <DriveFolderID>)|
        (parentname <DriveFolderName>)|
        (sharedparentname <DriveFolderName>)|
        (teamdriveparent <TeamDriveName>)|
        (teamdriveparentid <TeamDriveID>|<DriveFolderID>)|
        (teamdriveparentname <DriveFolderName>)
    gam <UserTypeEntity> copy drivefile <DriveFileEntity> [newfilename <DriveFileName>] [recursive [depth <Number>]] <DriveFileCopyAttribute>*

    <DriveFileUpdateAttribute> ::=
        <DriveFileAttribute>|
        (addparents <DriveFolderIDList>)|
        (removeparents <DriveFolderIDList>)|
        (parentid <DriveFolderID>)|
        (parentname <DriveFolderName>)|
        (sharedparentname <DriveFolderName>)|
        usecontentasindexabletext
    gam <UserTypeEntity> update drivefile <DriveFileEntity> [copy] [newfilename <DriveFileName>] <DriveFileUpdateAttribute>*

parentid <DriveFolderID> - Specify parent folder by Id
parentname <FolderName> - Specify parent folder by name, folder is owned by user in command
sharedparentname <FolderName> - Specify parent folder by name, folder is owned by any user
If none of the parent options are specified, the parent folder is the root folder,

Added commands to import events into calendars; this is useful when you want to import
events from .ics files. Importing events is similar to adding events; the principal difference
is that you must specify an iCalUID. All instances of recurring events will have the same
iCalUID but different event IDs. The import command supports two new attributes to set the
event organizer, but the API doesn't seem to honor the values; the organizer is set to
the calendar owner.
See: https://developers.google.com/google-apps/calendar/v3/reference/events/import
    <EventImportAttribute> ::=
        <EventAttribute>|
        (organizername <String>)|
        (organizeremail <EmailAddress>)
    gam calendar|calendars <CalendarEntity> import event icaluid <iCalUID> <EventImportAttribute>+
    gam <UserTypeEntity> import event <CalendarEntity> icaluid <iCalUID> <EventImportAttribute>+

Added maxinstances argument to gam info events to allow display of instances of recurring events.
    gam calendar|calendars <CalendarEntity> info events <EventEntity> [maxinstances <Number>]
    gam <UserTypeEntity> info events <CalendarManageEntity> <EventEntity> [maxinstances <Number>]
maxinstances -1 - Default, display base event
maxinstances 0 - Display all instances of a recurring event
maxinstances N - Display first N instances of a recurring event

Added event_max_results to gam.cfg
    event_max_results
        When retrieving lists of Calendar events/event instances from API, how many should be retrieved in each chunk
        Default: 250

4.53.01

Fix coding error in gam print/show contacts.

4.53.00

It's a batch from the past; added command gam tbatch to allow gam batch files to invoke gam csv commands.
    gam tbatch <FileName>|- [charset <Charset>] [showcmds]
In Gam version 4.36.00, multithreading was changed to multiprocessing to increase performance; unfortunately,
this change broke the ability of a Gam batch file to invoke gam csv commands. With tbatch, multithreading
is again used to process the batch file and gam csv commands can be included in the batch file. You should also use
tbatch if auto_batch_min in gam.cfg  has a value greater than zero and there are commands in the batch file that would
invoke auto batch processing. If you're not using gam csv or auto_batch_min is zero, use gam batch as performance will be better.

Added num_tbatch_threads to gam.cfg,
    num_tbatch_threads
        Number of threads for gam tbatch
        Default: 2
With gam tbatch there are potentially 1+num_tbatch_threads*num_threads Gam threads/processes running simultaneously;
exercise caution to avoid overloading your system.

With gam tbatch, Gam has no ability to intelligently process redirected stdout/stderr files.
For example, if you execute: gam redirect stdout ./Batch.out redirect stderr ./Batch.err tbatch Batch.bat
all of the threads will have stdout set to ./Batch.out and stderr to ./Batch.err, but the multiple threads will be
writing to the output files simultaneously. Of course, you can use redirect on the commands within the batch file
to precisely control the output.

Added showcmds argument to gam batch and gam tbatch commands; this causes Gam to display each command to stderr
as it is initiated so you can monitor Gam's progress.
    gam batch <FileName>|- [charset <Charset>] [showcmds [<Boolean>]]
    gam tbatch <FileName>|- [charset <Charset>] [showcmds [<Boolean>]]
If <Boolean> is omitted, True is assumed.
If stderr is redirected, the commands will be written to the redirected stderr and to sys.stderr so you can still
monitor Gam's progress on your screen.

Added print <String> command that can be embedded in Gam batch files.  <String> will be written to any
redirected stderr and to sys.stderr.

4.52.03

Added shownames argument to gam info vaulthold to control whether account and org unit names are displayed.
This makes info consistent with show and print.
Additional API calls are required to get the names.
    gam info vaulthold|hold <HoldItem> matter <MatterItem> [shownames]

4.52.02

In the Vault commands, matters and holds are displayed as Name(ID).
In gam print holds the matterName column was added.

4.52.01

Fixed error in copy drivefile recursive where only the first 100 files in a folder were copied.

4.52.00

Added arguments to print aliases to allow selection of aliases to print.
    gam print alias|aliases [todrive [<ToDriveAttribute>]] [shownoneditable] [nogroups] [nousers] [query <QueryUser>]
By default, all group and user aliases are printed.
nogroups - Print only user aliases
nousers - Print only group aliases
query <QueryUser> - Print aliases for selected users

Based on initial code provided by Jay Lee, Google Vault is now supported.
    gam create vaulthold|hold corpus drive|groups|mail matter <MatterItem> [name <String>] [query <QueryVaultCorpus>]
        [(accounts|groups|users <EmailItemList>) | (orgunit|ou <OrgUnit>)]
        [starttime <Date>|<DateTime>] [endtime <Date>|<DateTime>]
    gam update vaulthold|hold <HoldItem> matter <MatterItem> [query <QueryVaultCorpus>]
        [([addaccounts|addgroups|addusers <EmailItemList>] [removeaccounts|removegroups|removeusers <EmailItemList>]) | (orgunit|ou <OrgUnit>)]
        [starttime <Date>|<DateTime>] [endtime <Date>|<DateTime>]
    gam delete vaulthold|hold <HoldItem> matter <MatterItem>
    gam info vaulthold|hold <HoldItem> matter <MatterItem>
    gam show vaultholds|holds [matter|matters <MatterItemList>] [shownames]
    gam print vaultholds|holds [todrive [<ToDriveAttribute>]] [matter|matters <MatterItemList>] [shownames]

    gam create vaultmatter|matter [name <String>] [description <string>]
        [collaborator|collaborators <CollaboratorItemList>]
    gam update vaultmatter|matter <MatterItem> [name <String>] [description <string>]
        [addcollaborator|addcollaborators <CollaboratorItemList>] [removecollaborator|removecollaborators <CollaboratorItemList>]
    gam close vaultmatter|matter <MatterItem>
    gam reopen vaultmatter|matter <MatterItem>
    gam delete vaultmatter|matter <MatterItem>
    gam undelete vaultmatter|matter <MatterItem>
    gam info vaultmatter|matter <MatterItem>
    gam show vaultmatters|matters [basic|full]
    gam print vaultmatters|matters [todrive [<ToDriveAttribute>]] [basic|full]


To use Vault commands you must do the following two steps.
Add Google Vault API to your project; do this manually in the Developer's Console or with the following command if you used Gam to create your project.
    gam update project

Update authentication; select Vault API and then continue to authorization.
    gam oauth create

4.51.09

Code cleanup.

4.51.08

Handle httplib2.ServerNotFoundError in callGData and callGAPI.

4.51.07

Fix error where gam csvkmd cros_ous/cros_ous_and_children ... was not handled properly.

4.51.06

Extend notsuspended argument of gam update group <GroupItem> add/sync to allow suspended users in other groups to be excluded from being added to the group.
    gam update group <GroupItem> add [owner|manager|member] [notsuspended] <UserTypeEntity>
    gam update group <GroupItem> sync [owner|manager|member] [notsuspended] <UserTypeEntity>
This option is effective for the following values of <UserTypeEntity>:
    all users|
    group <GroupItem>|
    groups <GroupList>|
    group_users <GroupList> [members] [managers] [owners] [primarydomain] [domains <DomainNameList>] [recursive] end|
    ou|org <OrgUnitPath|ou_and_children|ou_and_child <OrgUnitPath>|
    query <Query>

4.51.05

Code cleanup.

4.51.04

Update googleapiclient library from 1.6.1 to 1.6.2.

Handle additional Team Drive errors.

4.51.03

* Suspend/Unsuspend Users
Added commands to suspend/unsuspend users; these are equivalent to update user with the suspended argument.
    gam suspend user <UserItem>
    gam unsuspend user <UserItem>
    gam suspend users <UserTypeEntity>
    gam unsuspend users <UserTypeEntity>
    gam <UserTypeEntity> suspend users
    gam <UserTypeEntity> unsuspend users

* Add Drivefile
When adding a drive file, the fileId will be output along with the name.

4.51.02

* Create Course
Change in 4.51.01 reversed, courses are created in the PROVISIONED state by default.

4.51.01

* Print Delegates
The column headings in gam print delegates are controlled by gam.cfg print_native_names.
    print_native_names = false - Delegator,Delegate,Delegate Email,Status
    print_native_names =  true - User,delegateName,delegateAddress,delegationStatus

4.51.00

* Create Course
Courses are now created in the ACTIVE state, previously they were created in the PROVISIONED state.

* Create Group
Updated gam create group to avoid a Google API issue that generated an error when the group description contains a <, > or =.

* Create User
Added arguments to gam create user to allow sending a message with account details to a secondary email address upon successful creation.
    gam create user <EmailAddress> <UserAttribute>* [notify <EmailAddress>] [subject <String>] [message <String>|(file <FileName> [charset <CharSet>])]
In the subject and message, these strings will be replaced with the specified values:
#givenname# - first/given name
#familyname# - last/family name
#email# - user's email address
#user# - user's email address
#username# - portion of user's email address before @
#domain# - portion of user's email after after @
#password# - password

If subject is not specified, the following value will be used:
    Welcome to #domain#
If message is not specified, the following value will be used:
    Hello #givenname# #familyname#,\n\nYou have a new account at #domain#\nAccount details:\n\nUsername\n#user#\n\nPassword\n#password#\n\n
    Start using your new account by signing in at\nhttps://www.google.com/accounts/AccountChooser?Email=#user#&continue=https://apps.google.com/user/hub\n
If you want a language/organization specific message, use a template file: message file <FileName> [charset <CharSet>]

The email is sent from the admin user identified in oauth2.txt, gam oauth info will show the value.
Gam gets no indication as to the status of the message delivery; the admin user user will get a non-delivery receipt if the message
could not be sent to the notify <EmailAddress>.

* Print Delegates
The column headings for gam print delegates were changed to match Jay Lee's Gam. The Delegation ID column was dropped as it was redundant.
Old: Delegator,Delegate,Delegate Email,Delegation ID,Status
New: User,delegateName,delegateAddress,delegationStatus

* Print Groups/Orgs
A variable, print_native_names (default value is False), has been added to gam.cfg to control the field names used in gam print groups/orgs.
When true, the native Directory API field names are used; when false, Gam specific field names are used. When true, the field names output
in gam print groups/orgs will match the fields names output in gam info group/org.

Groups:
    print_native_names = false - Email,ID,Name,Description,DirectMembersCount,Aliases,NonEditableAliases,Admin_Created
    print_native_names =  true - email,id,name,description,directMembersCount,aliases,nonEditableAliases,adminCreated
Orgs:
    print_native_names = false - Path,ID,Parent,ParentID,Name,Description,InheritanceBlocked
    print_native_names =  true - orgUnitPath,OrgUnitId,parentOrgUnitPath,parentOrgUnitId,name,description,blockInheritance

Added showparent argument to gam print orgs.
    gam print orgs|ous [todrive [<ToDriveAttribute>]] [showparent] [toplevelonly] [fromparent <OrgUnitItem>]
        [allfields|<OrgUnitFieldName>*|(fields <OrgUnitFieldNameList>)] [convertcrnl]
By default, gam print orgs prints all child org units of /; if fromparent <OrgUnitItem> is specified, gam prints all child org units of <OrgUnitItem>.
The showparent argument causes the parent org unit, / or fromparent <OrgUnitItem>, to be printed as well.
Previously, if no fields were specified, only the Path field was displayed. Now, the default fields printed are:
    print_native_names = false - Path,ID,Name,ParentID.
    print_native_names =  true - orgUnitPath,orgUnitId,name,orgUnitParentId.

* Update Mobile
Eliminated model, os and useragent arguments from gam update mobile as the Directory API no longer supports them.

* Print Mobile
Added arguments to gam info/print mobile to allow field specification.
    <MobileFieldName> ::=
        adbstatus|
        applications|
        basebandversion|
        bootloaderversion|
        brand|
        buildnumber|
        defaultlanguage|
        developeroptionsstatus|
        devicecompromisedstatus|
        deviceid|
        devicepasswordstatus|
        email|
        encryptionstatus|
        firstsync|
        hardware|
        hardwareid|
        imei|
        kernelversion|
        lastsync|
        managedaccountisonownerprofile|
        manufacturer|
        meid|
        model|
        name|
        networkoperator|
        os|
        otheraccountsinfo|
        privilege|
        releaseversion|
        resourceid|
        securitypatchlevel|
        serialnumber|
        status|
        supportsworkprofile|
        type|
        unknownsourcesstatus|
        useragent|
        wifimacaddress

    <MobileFieldNameList> ::= "<MobileFieldName>(,<MobileFieldName>)*"

    <MobileOrderByFieldName> ::=
        deviceid|email|lastsync|model|name|os|status|type

    gam info mobile <MobileEntity>
        [basic|full|allfields] <MobileFieldName>* [fields <MobileFieldNameList>]
    gam print mobile [todrive [<ToDriveAttribute>]] [query <QueryMobile>]
        [orderby <MobileOrderByFieldName> [ascending|descending]]
        [basic|full|allfields] <MobileFieldName>* [fields <MobileFieldNameList>]
        [delimiter <String>] [appslimit <Number>] [listlimit <Number>]

The email, name and otheraccountsinfo fields can have multiple values; the listlimit argument controls how these fields are displayed.
listlimit -1 - print no values for the field
listlimit 0 - print all values for the field
listlimit 1 - print one value for the field, default
listlinit N - print the first N values for the field

The applications field can have multiple values; the appslimit argument controls how this field is displayed.
appslimit -1 - print no values for the field, default
appslimit 0 - print all values for the field
appslinit N - print the first N values for the field

delimiter - The items in the applications, email, name and otheraccountsinfo fields are separated by delimiter, it defaults to the value of csv_output_field_delimiter in gam.cfg.

4.50.11

When gam copy drivefile is copying a folder and the parentname <DriveFolderName> option is specified, the folder is copied to the root folder,
not <DriveFolderName>; this has been corrected.

Added depth <Number> argument to gam copy drivefile to control folder copying.
    gam <UserTypeEntity> copy drivefile <DriveFileEntity> [newfilename <DriveFileName>] [recursive [depth <Number>]]
        [parentid <DriveFolderID>] [parentname <DriveFolderName>]
        [teamdriveparentid <DriveFolderID>] [teamdriveparent <TeamDriveName>] [teamdriveparentname <DriveFolderName>]

To copy a folder, you must specify the recursive argument; this copies the folder and all of its descendants to the new location.
Specifying depth <Number> allows you to specify that you do not want to copy all descendants but only decendants to the specified depth.
depth -1 - copy the folder and all descendants, default
depth 0 - copy the folder and no descendants
depth 1 - copy the folder and its immediate descendants
depth N - copy the folder and N levels of descendants

Added arguments to gam add/copy drivefile to allow adding/copying files to Team Drives.
    <DriveFileAddAttribute> ::=
        <DriveFileAttribute>|
        ignoredefaultvisibility|
        (modifieddate|modifiedtime <Time>)|
        (parentid <DriveFolderID>)|
        (parentname <DriveFolderName>)|
        (teamdriveparent <TeamDriveName>)|
        (teamdriveparentid <TeamDriveID>|<DriveFolderID>)|
        (teamdriveparentname <DriveFolderName>)|
        usecontentasindexabletext
    <DriveFileCopyAttribute> ::=
        <DriveFileAttribute>|
        ignoredefaultvisibility|
        (parentid <DriveFolderID>)|
        (parentname <DriveFolderName>)|
        (teamdriveparent <TeamDriveName>)|
        (teamdriveparentid <TeamDriveID>|<DriveFolderID>)|
        (teamdriveparentname <DriveFolderName>)
    gam <UserTypeEntity> add drivefile [drivefilename <DriveFileName>] <DriveFileAddAttribute>*
    gam <UserTypeEntity> copy drivefile <DriveFileEntity> [newfilename <DriveFileName>] [recursive [depth <Number>]] <DriveFileCopyAttribute>*
To add/copy a file to the root folder of a Team Drive, specify one of the following arguments:
    teamdriveparentid <TeamDriveID> - <TeamDriveID> identifies a Team Drive by ID
    teamdriveparent <TeamDriveName> - <TeamDriveName> identifies a Team Drive by name
To add/copy a file to a folder by identified by name on a Team Drive, specify one of the following arguments and the third argument:
    teamdriveparentid <TeamDriveID> - <TeamDriveID> identifies a Team Drive by ID
    teamdriveparent <TeamDriveName> - <TeamDriveName> identifies a Team Drive by name
    teamdriveparentname <DriveFolderName> - <DriveFolderName> identifies a folder on the Team Drive identified by the previous argument
To add/copy a file to a folder identified by ID on a Team Drive, specify the following argument:
    teamdriveparentid <DriveFolderID> - <DriveFolderID> identifies a drive folder on a Team Drive

4.50.10

Handle international characters in socket error message.

4.50.09

Sort rows in gam report customer.

4.50.08

Fix error when redirecting stdout with gam loop.

4.50.07

Improve getUsersToModify memory use.

4.50.06

Error handling cleanup.

4.50.05

Fix issue where gam org "/" ... fails when a domain has a very large number of users.

4.50.04

Added additional query shortcuts.
    <DriveFileQueryShortcut> ::=
        all_files | all_folders | all_google_files | all_non_google_files | all_items |
        my_files | my_folders | my_google_files | my_non_google_files | my_items |
        others_files | others_folders | others_google_files | others_non_google_files | others_items |
        writable_files
    <TeamDriveFileQueryShortcut> ::=
        all_files | all_folders | all_google_files | all_non_google_files | all_items

Keyword to query mappings:
all_files - "mimeType != application/vnd.google-apps.folder"
all_folders - "mimeType = application/vnd.google-apps.folder"
all_google_files - "mimeType != application/vnd.google-apps.folder and mimeType contains 'vnd.google'"
all_non_google_files - "not mimeType contains 'vnd.google'"
all_items - "" (An empty query specifies all files and folders)
my_files - "'me' in owners and mimeType != application/vnd.google-apps.folder"
my_folders - "'me' in owners and mimeType = application/vnd.google-apps.folder"
my_google_files - "'me' in owners and mimeType != application/vnd.google-apps.folder and mimeType contains 'vnd.google'"
my_non_google_files - "'me' in owners and not mimeType contains 'vnd.google'"
my_items - "'me' in owners"
others_files - "not 'me' in owners and mimeType != application/vnd.google-apps.folder"
others_folders - "not 'me' in owners and mimeType = application/vnd.google-apps.folder"
others_google_files - "not 'me' in owners and mimeType != application/vnd.google-apps.folder and mimeType contains 'vnd.google'"
others_non_google_files - "not 'me' in owners and not mimeType contains 'vnd.google'"
others_items - "not 'me' in owners"
writable_files - "'me' in writers and mimeType != application/vnd.google-apps.folder"

4.50.03

Added sorting capability to the following commands.
    gam <UserTypeEntity> show drivefileacl <DriveFileEntity> [showtitles] (orderby <DriveFileOrderByFieldName> [ascending|descending])*
    gam <UserTypeEntity> print drivefileacls <DriveFileEntity> [todrive [<ToDriveAttribute>]]> [oneitemperrow] [showtitles] (orderby <DriveFileOrderByFieldName> [ascending|descending])*
    gam <UserTypeEntity> show filerevisions <DriveFileEntity> [select <DriveFileRevisionIDEntity>] [previewdelete]
        [showtitles] [<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])*
    gam <UserTypeEntity> print filerevisions <DriveFileEntity> [todrive [<ToDriveAttribute>]] [oneitemperrow] [select <DriveFileRevisionIDEntity>] [previewdelete]
        [showtitles] [<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])*
    gam <UserTypeEntity> show fileinfo <DriveFileEntity> [filepath] [allfields|<DriveFieldName>*|(fields <DriveFieldNameList>)] (orderby <DriveFileOrderByFieldName> [ascending|descending])*
    gam <UserTypeEntity> show filepath <DriveFileEntity> (orderby <DriveFileOrderByFieldName> [ascending|descending])*

Added print filepath command. gam print/show filepath require multiple API calls per file to construct the filepath, plan your use accordingly.
    gam <UserTypeEntity> print filepath <DriveFileEntity> [todrive [<ToDriveAttribute>]] [oneitemperrow] (orderby <DriveFileOrderByFieldName> [ascending|descending])*

Several shortcuts have been introduced to allow specifying basic Drive file queries.
They can be used in any command that uses <DriveFileEntity>.
They can not be used in the select <DriveFileEntityListTree> option of gam print filelist/filetree.
The shortcuts can be used as standalone arguments to gam print filelist.
    <DriveFileQueryShortcut> ::= all_files | all_folders | all_items | my_files | my_folders | my_items | others_files | others_folders | others_items
    <TeamDriveFileQueryShortcut> ::= all_files | all_folders | all_items
    <DriveFileEntity> ::=
        <DriveFileIDEntity> |
        <DriveFileNameEntity> |
        <DriveFileQueryEntity> |
        <DriveFileQueryShortcut> |
        root |
        <TeamDriveIDEntity> [<TeamDriveFileQueryShortcut>] |
        <TeamDriveNameEntity> [<TeamDriveFileQueryShortcut>] |
        <TeamDriveFileNameEntity> |
        <TeamDriveFileQueryEntity> |
        <FileSelector> | <CSVkmdSelector> | <CSVSubkeySelector>) | <CSVDataSelector>)

Keyword to query mappings:
all_files - "mimeType != application/vnd.google-apps.folder"
all_folders - "mimeType = application/vnd.google-apps.folder"
all_items - "" (An empty query specifies all files and folders)
my_files - "'me' in owners and mimeType != application/vnd.google-apps.folder"
my_folders - "'me' in owners and mimeType = application/vnd.google-apps.folder"
my_items - "'me' in owners"
others_files - "not 'me' in owners and mimeType != application/vnd.google-apps.folder"
others_folders - "not 'me' in owners and mimeType = application/vnd.google-apps.folder"
others_items - "not 'me' in owners"

Examples:
Show ACls for folders not owned by the user: gam user testuser@domain.com show drivefileacls others_folders
Print revisions for files owned by the user: gam user testuser@domain.com print filerevisions my_files one_item_per_row
Print a file list of all of the users folders: gam user testuser@domain.com print filelist my_folders

4.50.02

Added argument oneitemperrow to print drivefileacls.
    gam <UserTypeEntity> print drivefileacls <DriveFileEntity> [showtitles] [oneitemperrow] [todrive [<ToDriveAttribute>]]

With print drivefileacls, by default the ACLs selected for display are all output on one line as a repeating item with the matching file id.
When oneitemperrow is specified, each ACL is output on a separate row with the matching file id. This simplifies processing the CSV file
with subsequent Gam commands.

Enhanced commands for managing Drive file revisions. The info filerevisions command was deleted
as the enhancements to show filerevisions made it superfluous. You can now select sets of revisions
to process. For delete filerevisions, the selection is required, for print and show it is optional;
if not specified, all file revisions are processed.
    <DriveFileRevisionID> ::= <String>
    <DriveFileRevisionIDList> ::= "<DriveFileRevisionID>(,<DriveFileRevisionID>)*"
    <DriveFileRevisionIDEntity> ::=
        (<DriveFileRevisionID>) | (id <DriveFileRevisionID>) | (id:<DriveFileRevisionID>) | (ids <DriveFileRevisionIDList>) | (ids:<DriveFileRevisionIDList>) |
        (first|last|allexceptfirst|allexceptlast <Number>) |
        (before|after <DateTime>) | (range <DateTime> <DateTime>)

<DriveFileRevisionIDEntity> can select specific revisions by ID or can select revisions by position in the list or by modification date.
first <Number> - process the first <Number> revisions.
last <Number> - process the last <Number> revisions.
allexceptfirst <Number> - process all revisions except the first <Number> revisions.
allexceptlast <Number> - process all revisions except the last <Number> revisions.
before <DateTime> - process all revisions with a modification date before <DateTime>.
after <DateTime> - process all revisions with a modification date equal to or after <DateTime>.
range <DateTime> <DateTime> - process all revisions with a modification date equal to or after the first <DateTime> and before the second <DateTime>.

    gam <UserTypeEntity> delete filerevisions <DriveFileEntity> select <DriveFileRevisionIDEntity> [previewdelete]
        [showtitles] [doit] [max_to_delete <Number>]

showtitles - output file title as well as file id in messages; this requires an additional API call per file.
previewdelete - output revisions to be deleted but do not delete them
doit - no revisions are deleted unless doit is specified
max_to_delete <Number> - no revisions are deleted if the number of revisions to delete exceeds <Number>; the default value is one. Set <Number> to 0 for no limit.

When deleting revisions, the last remaining revision can not be deleted. If the <Number> or <DateTime> selections identify all of the revisions for a file,
the following adjustments are made:
first <Number> - leave the latest revision
last <Number> - leave the earliest revision
allexceptfirst <Number> - not applicable, can't select all revisions
allexceptlast <Number> -  not applicable, can't select all revisions
before <DateTime> - leave the latest revision
after <DateTime> - leave the earleist revision
range <DateTime> <DateTime> - leave the earliest revision

    <RevisionsFieldName> ::=
        filesize|
        id|
        keepforever|
        lastmodifyinguser|
        lastmodifyingusername|
        md5checksum|
        mimetype|
        modifieddate|
        modifiedtime|
        originalfilename|
        pinned|
        publishauto|
        published|
        publishedoutsidedomain|
        size

    gam <UserTypeEntity> show filerevisions <DriveFileEntity> [select <DriveFileRevisionIDEntity>] [previewdelete]
        [showtitles] [<DriveFieldName>*|(fields <DriveFieldNameList>)]
    gam <UserTypeEntity> print filerevisions <DriveFileEntity> [todrive [<ToDriveAttribute>]] [select <DriveFileRevisionIDEntity>] [previewdelete]
        [showtitles] [oneitemperrow] [<DriveFieldName>*|(fields <DriveFieldNameList>)]

When select <DriveFileRevisionIDEntity> is omitted, all revisions are displayed. When select <DriveFileRevisionIDEntity> is specified,
previewdelete will make the list of revisions displayed match the list that would be processed by delete filerevisions.

showtitles - output file title as well as file id in output; this requires an additional API call per file.

With print filerevisions, by default the revisions selected for display are all output on one line as a repeating item with the matching file id.
When oneitemperrow is specified, each revision is output on a separate row with the matching file id. This simplifies processing the CSV file
with subsequent Gam commands.

4.50.01

Extended commands for managing Drive file revisions.
    gam <UserTypeEntity> delete filerevision <DriveFileEntity> <DriveFileRevisionID> [showtitles]
    gam <UserTypeEntity> info filerevision <DriveFileEntity> <DriveFileRevisionID> [showtitles]
    gam <UserTypeEntity> show filerevisions <DriveFileEntity> [showtitles]
    gam <UserTypeEntity> print filerevisions <DriveFileEntity> [todrive [<ToDriveAttribute>]] [showtitles]

4.50.00

This version of Gam has two major areas of change: a new version of the Google Drive API is used and Team Drives are supported.

Google Drive API

All Google Drive API calls have been converted from v2 to v3, see: https://developers.google.com/drive/v3/web/migration
Many of the changes are internal to Gam and have no visible effect. Google has modified/renamed many field names and these will affect
scripts that parse the output from gam print/show drivesettings/drivefileacls/fileinfo/filelist/filerevisions. Additionally, Google has dropped
some fields and their values are no longer available. On input, Gam accepts both the old and new field names.

A variable, drive_v3_native_names (default value is False), has been added to gam.cfg to control the field names on output.
When True, the v3 native field names are used; when False, the v3 native field names are mapped to the v2 field names.

If you have scripts that process the output from these print commands, you may have to make modifications to your scripts.
Run your print/show commands with a previous version of Gam and save the output.
With drive_v3_native_names = False, run your print/show commands with this version of Gam and compare the output to that saved in the previous run;
modify your scripts that process the output as appropriate.

There is a cost to mapping the v3 field names back to the v2 field names; you can avoid this cost by setting drive_v3_native_names = True,
running your print/show commands, comparing the output and making the appropriate script modifications.

print/show drivesettings
Dropped fields:
        DRIVE
        GMAIL
        PHOTOS
        domainSharingPolicy
        lauguageCode
Renamed fields (Old->New):
        name->displayName,
        quotaBytesTotal->limit
        quotaBytesUsed->usageInDrive
        quotaBytesUsedAggregate->usage
        quotaBytesUsedInTrash->usageInDriveTrash

print/show drivefileacls
Dropped fields:
        authKey
Renamed fields (Old->New):
        name->displayName
        withLink->allowFileDiscovery

print/show fileinfo/filelist
Dropped fields:
        defaultOpenWithLink
        embedLink
        exportLinks
        labels(hidden)
        markedViewedByMeDate
        openWithLinks
        selfLink
        parents(isRoot)
        parents(parentLink)
        parents(selfLink)
        permissions(selfLink)
        selfLink
        userPermission(selfLink)
Renamed fields (Old->New):
        alternateLink->webViewLink
        capabilities(canChangeRestrictedDownload)->capabilities(canChangeViewersCanCopyContent)
        createdDate->createdTime
        expirationDate->expirationTime
        fileSize->size
        lastViewedByMeDate->viewedByMeTime
        modified->modifiedByMe
        modifiedByMeDate->modifiedByMeTime
        modifiedDate->modifiedTime
        restricted->viewersCanCopyContent
        sharedWithMeDate->sharedWithMeTime
        title->name
        trashedDate->trashedTime
        viewed->viewedByMe
        withLink->allowFileDiscovery

print/show filerevisions
Dropped fields:
        exportLinks
        publishedLink
        selfLink
Renamed fields (Old->New):
        fileSize->size
        isAuthenticatedUser->me
        modifiedDate->modifiedTie
        picture.url->photoLink
        pinned->keepForever

The parents field of a file has undergone the most change. In Drive v2 it was a list of compound items with three sub-fields per item: id, isRoot, parentLink.
In Drive v3 the parents field is a list of simple items, the parent ids. The following examples show how the parents field is output in a CSV file for a
file with two parents.
Previous versions of Gam:
Owner,title,parents,parents.0.isRoot,parents.0.id,parents.0.parentLink,parents.1.isRoot,parents.1.id,parents.1.parentLink
testuser@domain.com,TestFile,2,True,PPPP1111,https://www.googleapis.com/drive/v2/files/PPPP1111,False,PPPP2222,https://www.googleapis.com/drive/v2/files/PPPP2222

Current version of Gam with drive_v3_name_names = false
Owner,title,parents,parents.0.id,parents.1.id
testuser@domain.com,TestFile,2,PPPP1111,PPPP2222

Current        version        of Gam with drive_v3_name_names        = true
Owner,name,parents
testuser@domain.com,TestFile,PPPP1111 PPPP2222

TeamDrive

Added commands to directly manipulate Team Drives.

    <TeamDriveID> ::= <String>
    <TeamDriveName> ::= <String>
    <TeamDriveEntity> ::= <TeamDriveID> | (teamdriveid <TeamDriveID>) | (teamdriveid:<TeamDriveID>) | (teamdrive <TeamDriveName>) | (teamdrive:<TeamDriveName>)

    gam <UserTypeEntity> create teamdrive <Name> [themeid <String>]
    gam <UserTypeEntity> update teamdrive <TeamDriveEntity> [name <Name>] [themeid <String>]
    gam <UserTypeEntity> delete teamdrive <TeamDriveEntity>
    gam <UserTypeEntity> info teamdrive <TeamDriveEntity>
    gam <UserTypeEntity> print teamdrives [todrive [<ToDriveAttribute>]]
    gam <UserTypeEntity> show teamdrives

The Team Drive theme IDs are available with gam <UserTypeEntity> show drivesettings.

Added support for Team Drives to various drive commands.

A Google Drive (My Drive) can be accessed by its ID or by the identifier root.
A Team Drive can be accessed by its ID or name. This latter capability is supplied by Gam as the Drive API
considers all Team Drives to have the same name, Team Drive; the name you specify when creating a Team Drive
is not used by the Drive API.

The user that creates a Team Drive is given the permission role organizer for the Team Drive;
to manage permission roles for other users for the Team Drive itself, the drivefileacl commands are used.
These commands must be issued by a user with permission role organizer.
For these commands, <DriveFileEntity> is extended:
    <TeamDriveIDEntity> ::= (teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>)
    <TeamDriveNameEntity> ::= (teamdrive <TeamDriveName>) | (teamdrive:<TeamDriveName>)
    <DriveFileEntity> ::=
        <TeamDriveIDEntity> |
        <TeamDriveNameEntity>

    gam <UserTypeEntity> add drivefileacl <DriveFileEntity> anyone|(user <UserItem>)|(group <GroupItem>)|(domain <DomainName>)
        (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])] [expiration <Time>] [sendemail] [emailmessage <String>] [showtitles]
    gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail>
        (role <DriveFileACLRole>) [withlink|(allowfilediscovery|discoverable [<Boolean>])] [expiration <Time>] [removeexpiration [<Boolean>]] [showtitles]
    gam <UserTypeEntity> delete drivefileacl <DriveFileEntity> <DriveFilePermissionIDorEmail> [showtitles]
    gam <UserTypeEntity> show drivefileacl <DriveFileEntity> [showtitles]
    gam <UserTypeEntity> print drivefileacl <DriveFileEntity> [todrive [<ToDriveAttribute>]] [showtitles]

To manage permission roles for files/folders on a Team Drive, <DriveFileEntity> is extended:
    <TeamDriveFileNameEntity> ::= (teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>)
    <TeamDriveFileQueryEntity> ::= (teamdrivequery <QueryDriveFile>) | (teamdrivequery:<QueryDriveFile>)
    <DriveFileEntity> ::=
        <TeamDriveFileNameEntity> |
        <TeamDriveFileQueryEntity>

When adding/updating/copying files/folders on Team Drives, <DriveFileAttribute> is extended to support Team Drives.
    <DriveFileAttribute> ::=
        (teamdriveparent <TeamDriveName>)|
        (teamdriveparentid <DriveFolderID>)|
        (teamdriveparentname <DriveFolderName>)
If the parent is the top level of the Team Drive, use: teamdriveparent <TeamDriveName>
If you know the ID of the parent folder, use: teamdriveparentid <DriveFolderID>
If the parent is some folder on the Team Drive, use: teamdriveparentname <DriveFolderName>

To display information about Team Drives and Team Drive files, <DriveFileEntity> is extended:
    <TeamDriveIDEntity> ::= (teamdriveid <DriveFileItem>) | (teamdriveid:<DriveFileItem>)
    <TeamDriveNameEntity> ::= (teamdrive <TeamDriveName>) | (teamdrive:<TeamDriveName>)
    <TeamDriveFileNameEntity> ::= (teamdrivefilename <DriveFileName>) | (teamdrivefilename:<DriveFileName>)
    <TeamDriveFileQueryEntity> ::= (teamdrivequery <QueryDriveFile>) | (teamdrivequery:<QueryDriveFile>)
    <DriveFileEntity> ::=
        <TeamDriveIDEntity> |
        <TeamDriveNameEntity> |
        <TeamDriveFileNameEntity>|
        <TeamDriveFileQueryEntity>
    gam <UserTypeEntity> show fileinfo <DriveFileEntity> [filepath] [allfields|<DriveFieldName>*|(fields <DriveFiledNameList>)]
    gam <UserTypeEntity> show filerevisions <DriveFileEntity>
    gam <UserTypeEntity> show filepath <DriveFileEntity>

To display a file tree for a Team Drive, select <DriveFileEntity> is extended:
    <DriveFileEntity> ::=
        <TeamDriveIDEntity> |
        <TeamDriveNameEntity> |
        <TeamDriveFileNameEntity>

    gam <UserTypeEntity> show filetree [anyowner|(showownedby any|me|others)]
        [select <DriveFileEntity>|orphans] [depth <Number>] (orderby <DriveOrderByFieldName> [ascending|descending])*

To display a file list for a Team Drive, select <DriveFileEntity> is extended:
    <DriveFileEntity> ::=
        <TeamDriveIDEntity> |
        <TeamDriveNameEntity> |
        <TeamDriveFileNameEntity> |
        <TeamDriveFileQueryEntity>

To display a file list that spans Team Drives, use the corpora <CorporaAttribute> option.
    CorporaAttribute> ::= allteamdrives|domain|user
allteamdrives: Lists files that the user has accessed and all Team Drives in which they are a member.
domain: Lists files that are shared to the domain, including both Team Drive and non-Team Drive files.
user: Lists files that the user has accessed, including both Team Drive and non-Team Drive files.

    gam <UserTypeEntity> print|show filelist [todrive [<ToDriveAttribute>]] [corpora <CorporaAttribute>] [anyowner|(showownedby any|me|others)]
        [query <QueryDriveFile>] [fullquery <QueryDriveFile>]
        [select <DriveFileEntity>|orphans] [depth <Number>] (orderby <DriveOrderByFieldName> [ascending|descending])*
        [filepath] [allfields|<DriveFieldName>*|(fields <DriveFiledNameList>)] [delimiter <String>]

To delete empty folders on a Team Drive, the delete emptydrivefolders command has been extended.
    gam <UserTypeEntity> delete emptydrivefolders [<TeamDriveEntity>]

To empty the trash on a Team Drive, the empty drivetrash command has been extended.
    gam <UserTypeEntity> empty drivetrash [<TeamDriveEntity>]

The following commands are not applicable to Team Drives.
    gam <UserTypeEntity> transfer drive <UserItem> [keepuser]
    gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem> [includetrashed] (orderby <DriveOrderByFieldName> [ascending|descending])* [preview] [filepath] [todrive [<ToDriveAttribute>]]
    gam <UserTypeEntity> claim ownership <DriveFileEntity> [skipids <DriveFileEntity>] [skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>] [includetrashed] [restricted [<Boolean>]] [writerscantshare [<Boolean>]] [preview] [filepath] [todrive [<ToDriveAttribute>]]
    gam <UserTypeEntity> collect orphans (orderby <DriveOrderByFieldName> [ascending|descending])*
        [targetuserfoldername <DriveFileName>] [preview] [todrive [<ToDriveAttribute>]]

4.44.53

Modified progress messages in gam claim ownership to match those in gam transfer ownership.

4.44.52

When all users is specified with gam info users, suspended users are now included.

4.44.51

Courtesy of Jay, show detailed license counts for gam info customer/domain/instance.

4.44.50

Fix bug affecting internationalized headers in gam print/show messages.

4.44.49

Handle incorrectly encoded internationalized headers in gam print/show messages.

4.44.48

Updated gam create group to avoid Google API issue that generated an error when the group description contains a newline.

4.44.47

Updated gam create/update group to use update semantics for group settings to avoid unexpected results due to Google issue #32460496.

4.44.46

Placed name at top of permissions section for gam show fileinfo.

4.44.45

Handle internationalized headers in gam print/show messages.

4.44.44

Process text/rfc822-headers in print/show messages when showbody is specified.

4.44.43

When collecting orphaned files into a target folder, only orphaned files owned by the user are collected.

4.44.42

Fix bug in add/update drivefileacl where role commenter was not properly handled.

4.44.41

Update gam print drivesettings to handle teamDriveThemes columns.

4.44.40

Added arguments to show messages/threads to display plain text attachments. Selected attachments can be shown by specifying an attachmentnamepattern.
    gam <UserTypeEntity> show messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [headers <String>] [showlabels] [showbody] [showsize] [showsnippet] [showattachments [attachmentnamepattern <RegularExpression>]]

Show all attachments:
    gam user testuser@domain.com show messages showattachments
Show attachments named sample.txt:
    gam user testuser@domain.com show messages showattachments attachmentnamepattern "sample.txt"
Show attachments with 2017 in their name:
    gam user testuser@domain.com show messages showattachments attachmentnamepattern ".*2017.*"

4.44.39

When collecting orphaned files into a target folder, the folder is not created unless orphaned files are located.

4.44.38

Fix bug with print/show messages when showbody is specified.

Added command to collect a users orphaned Drive files/folders into a single folder.
Only orphaned files not in the trash are processed.

    gam <UserTypeEntity> collect orphans (orderby <DriveOrderByFieldName> [ascending|descending])*
        [targetuserfoldername <DriveFileName>] [preview] [todrive [<ToDriveAttribute>]]

(orderby <DriveOrderByFieldName> [ascending|descending])* - Specify the order in which files are processed.

[targetuserfoldername <DriveFileName>] - This is the parent folder name for the orphaned files; the default is "#user# orphaned files".
In this string, #user# and #email# will be replaced by the source user email address, #username# will be replaced by the source user mail address without the domain.

[preview] - If preview is specified, no files are collected; a CSV file listing the files to be collected is output.
[todrive [<ToDriveAttribute>]] - Specifies that the CSV file be written to Google Drive.

Example:
Collect a users orphaned files into the folder "Orphans - testuser@domain.com" on their Drive.
    gam user testuser@domain.com collect orphans targetuserfoldername "Orphans - #user#"

4.44.37

Following Jay's suggestion, gam delete token now reports an error if you attempt to delete a non-existent token.

gam print/show messages now prints the original message when you get a non-delivery message from Google.

4.44.36

Fix bug with print/show messages when showbody is specified.

4.44.35

Handle ERROR: 403: domainPolicy - The domain policy has disabled third-party Drive apps

4.44.34

Added charset option to file option of note option of contact attributes.
Added charset option to file option of note option of user attributes.
    <ContactAttribute> ::=
        ...
        (note <String>|(file <FileName> [charset <Charset>]))|
        ...
    <UserAttribute> ::=
        ...
        (note|notes clear|([text_plain|text_html] <String>|(file <FileName> [charset <Charset>])))|
        ...
    gam update contact 1234 note file contact1234notes.txt charset UTF-8
    gam update user testuser@domain.com note file testusernotes.txt charset UTF-8

4.44.33

Added never_time to gam.cfg to specify the value to be substituted whenever a Google datetime variable
has the value "1970-01-01T00:00:00.000Z"; the default value is 'Never'.
To keep the Google value: never_time = 1970-01-01T00:00:00.000Z
To use some other date/time value: never_time = 1999-12-31T23:59:59.999Z
To use some distinguished value: never_time = 0
To continue using Never: never_time = Never

Improved Unicode character handling for gam csv and Windows.

4.44.32

Update gam create project with Jay's latest changes: client_secrets.json and oauth2service.json must not exist;
Client ID and Client Secret are validated.

Fix gam show labels display basename to properly handle labels with embedded slashes.

4.44.31

Handle additional OAuth error.

4.44.30

Added display argument to gam show labels to allow choice of data to display.
    gam <UserTypeEntity> show labels|label [onlyuser [<Boolean>]] [showcounts [<Boolean>]] [nested [<Boolean>]] [display allfields|basename|fullname]
If display is not specified or display allfields is specified, the full name of the label and the fields (type, id, labelListVisibility, messageListVisibility) are displayed.
If showCounts is specified, the fields (messagesTotal, messagesUnread, threadsTotal, threadsUnread) are also displayed.
If display fullname is specified, the full name of the label, and no other fields, is displayed.
If display basename is specified, the base name (rightmost component) of the label, and no other fields, is displayed.
The display fullname/basename options are most useful in conjunction with nested.

4.44.29

gam show labels now prints labels sorted by type (system, user) and name making it much easier to read.
Added nested argument to gam show labels; this causes nested labels to be indented under their parent label
to allow the hierarchy to be more clearly visible.
    gam <UserTypeEntity> show labels|label [onlyuser [<Boolean>]] [showcounts [<Boolean>]] [nested [<Boolean>]]
For the onlyuser, showcounts and nested arguments, if <Boolean> is omitted, True is assumed.

Added buildpath argument to gam add label; this causes Gam to build all components of a multi-level label.
If buildpath is omitted or set to False, all parent labels in a multi-level label must be present for the add to succeed.
If buildpath is present and <Boolean> is omitted or set to True, all parent labels in a multi-level label are created
as necessary for the add to succeed.
    gam <UserTypeEntity> [add] label|labels <String> [messagelistvisibility hide|show] [labellistvisibility hide|show|showifunread] [buildpath [<Boolean>]]
Example: gam user user@domain.com add label "Top/Middle/Bottom" buildpath

4.44.28

Fix bug when deleting/updating label containing accented characters.

4.44.27

Optimized gam print printjobs and gam printjob fetch when olderthan/newerthan <PrintJobAge> is specified so that
additional printjobs are not downloaded from Google once a printjob out of range is encountered. For newerthan, this works
because the printjobs are downloaded in reverse chronological order; once a printjob is found to be older
than the newerthan <PrintJobAge>, all remaining printjobs can be ignored. To get this optimization for olderthan,
the download order must be reversed so that the printjobs are downloaded in ascending order. The following three cases are optimized:
    gam print printjobs newerthan <PrintJobAge>
    gam print printjobs newerthan <PrintJobAge> orderby createtime descending
    gam print printjobs olderthan <PrintJobAge> orderby createtime ascending

4.44.26

Added countsonly argument to gam print courses; in conjunction with show all|students|teachers, it eliminates
the student/teacher profile columns and outputs only the columns with student/teacher counts.
    gam print courses [todrive [<ToDriveAttribute>]] [teacher <UserItem>] [student <UserItem>]
        [delimiter <String>] [alias|aliases] [show all|students|teachers] [countsonly] [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]

4.44.25

At Jay's suggestion, added activeTimeRanges.minutes column to gam print cros/crosactivity.
activeTimeRanges.activeTime: milliseconds
activeTimeRanges.duration: hh:mm:ss
activeTimeRanges.minutes: minutes

The column headers for the following print commands have been adjusted to make the most common headers appear at the left
and the remaining headers be sorted: courses, course-participants, domainaliases, mobile, printers, printjobs.

4.44.24

Added start <Date> and end <Date> arguments to gam info cros and gam print cros to allow filtering of activeTimeRanges.
These arguments have no effect unless the activetimeranges|timeranges field name is specified.
If start <Date> is not specified, then there is no filtering for starting date.
If end <Date> is not specified, then there is no filtering for ending date.
    gam info cros <CrosEntity> [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]
    gam <CrOSTypeEntity> info [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]
    gam [<CrOSTypeEntity>] print cros [todrive [<ToDriveAttribute>]] [query <QueryCrOS>]|[select <CrOSTypeEntity>]
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]

Based on code by Jay, added a command to get CrOS device activity.
    gam [<CrOSTypeEntity>] print crosactivity [todrive [<ToDriveAttribute>]] [query <QueryCrOS>]|[select <CrOSTypeEntity>]
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [recentusers] [timeranges] [listlimit <Number>] [start <Date>] [end <Date>]
        [delimiter <String>]

The basic column headers are: deviceId,annotatedAssetId,annotatedLocation,serialNumber,orgUnitPath.
If recentusers is specified, all of the recent users email addresses, separated by the delimiter <String>,
are put on a separate row, with header recentUsers.email, in addition to the basic headers.
If timeranges is specified, each pair of time range values, activeTimeRanges.date and activeTimeRanges.duration,
are put on a separate row with the basic headers.
The default is to include both recentusers and timeranges.
The listlimit <Number> argument limits the number of recent users and time ranges to <Number>. If <Number> equals zero, there is no limit.
The start <Date> and end <Date> arguments filter the time ranges.

Example: gam print crosactivity recentusers start 2017-03-01 end 2017-03-31 listlimit 10 delimiter " "
For each CrOS device, thus will yield a space delimited list of the 10 most recent users for the month of March.

4.44.23

When todrive is specified and gam.cfg/no_browser is true, the email regarding the upload will be sent to the
email address specified in gam.cfg/todrive_user or the email address specified with the tduser command line argument.
If neither of these options is specified, the email is sent to the G Suite administrator.
Previously, the email was always sent to the G Suite administrator.

4.44.22

Use service account for uploading todrive reports and sending email messages when no_browser is true.

4.44.21

Corrected my error in add smime. S/MIME .p12 files are binary, there is no need for a charset option; in fact, even if you didn't specify a charset,
the code didn't operate correctly.
    gam <UserTypeEntity> add smime file <FileName> [password <Password>] [sendas|sendasemail <EmailAddress>] [default]

4.44.20

Fix gam <UserTypeEntity> add smime, original code from Jay was not correct.

4.44.19

Courtesy of Jay, handle additional values in gam report customer.
Handle Google changes that broke gam create project.

4.44.18

Courtesy of Jay, show customer license info in gam info customer/instance.
Handle bad data from Google in gam report customer.

4.44.17

gam print contacts/contactgroups now output user placeholder rows as necessary when csv_output_users_audit is true.

4.44.16

Handle Google change that dropped domain and admin email address from credentials.

4.44.15

Improved error messages for gam add/delete delegates, they should be easier to understand.

4.44.14

Email addresses in the gmail.com domain can have arbitrary dots in the name. When adding such an address to a group,
Google maps the name to have the dots specified when the account was set up regardless of the dots specified in the address to be added.
Email addresses in the gmail.com domain have an equivalent email address in the googlemail.com domain. When adding such an address to a group,
Google maps the domain name to the domain name specified when the account was set up regardless of the domain name specified in the address to be added.
These mappings cause erroneous deletes and duplicate adds when syncing group membership as the email address in the group may not match
the email address in the list of email addresses to sync even though they are equivalent.
Gam now maps all email addresses in the gmail.com and googlemail.com domains to a canonical form before comparing the current group email addresses
with the email addresses on the command line. If an email address is to be added, it is added with the email address specified on the command line.
If an email address is to be deleted, it is deleted using the email address from the group.

4.44.13

Added csv_output_users_audit to gam.cfg, its default value is False.
Gam print commands that print objects belonging to users don't print rows for users that don't have
any of the following objects: calendars, calendar ACLs, calendar events, delegates, filters,
forwarding addresses, sendas addresses, S/MIME certificates and tokens. When csv_output_users_audit is true,
a placeholder row will be output with the user's email address; these rows will useful for auditing purposes only,
they can not be successfuly used in a gam csv command.
Example:, produce an audit CSV file showing the delegates for the Sales group.
     gam config auto_batch_min 1 csv_output_users_audit true redirect csv SalesDelegatesAudit.csv multiprocess group Sales print delegates

4.44.12

Fixed bug where extra \r was output on each line when writing CSV files on Windows.

4.44.11

Previously, specifying todrive with a print command caused the CSV file to be uploaded to Google Drive,
it could not be saved locally at the same time. Now, you can have the CSV file saved locally and uploaded to Google Drive
in the same command. The tdlocalcopy subargument to todrive causes the CSV file to be saved and uploaded.
Added todrive_localcopy to gam.cfg with a default value of false; this value is the default for tdlocalcopy.
You can specify tdlocalcopy false/true on the command line to override the default value from gam.cfg.
    <ToDriveAttribute> ::=
        (tdtitle <String>)|
        (tduser <EmailAddress>)|
        (tdparent id:<DriveFolderID>|<DriveFolderName>)|
        (tdtimestamp [<Boolean>] [tddaysoffset <Number>] [tdhoursoffset <Number])|
        (tdlocalcopy [<Boolean>])
Current options:
  Output to stdout:
    gam print users
    gam redirect csv - print users
  Save file locally:
    gam print users > ./Users.csv
    gam redirect csv - print users > ./Users.csv
    gam redirect csv ./Users.csv print users
  Upload file to Google Drive:
    gam print users todrive
    gam redirect csv - print users todrive
Current options that don't perform as expected, data is not saved locally:
  Save file locally and upload to Google Drive:
    gam print users todrive > ./Users.csv
    gam redirect csv - print users todrive > ./Users.csv
    gam redirect csv ./Users.csv print users todrive
New options:
  Output to stdout and upload to Google Drive:
    gam print users todrive tdlocalcopy true
    gam redirect csv - print users todrive tdlocalcopy true
  Save file locally and upload to Google Drive:
    gam print users todrive tdlocalcopy true > ./Users.csv
    gam redirect csv - print users todrive tdlocalcopy true > ./Users.csv
    gam redirect csv ./Users.csv print users todrive tdlocalcopy true

4.44.10

Handle corrupt files in gamcache by turning caching off for the current command.

4.44.09

Reduce default value for num_threads in gam.cfg from 25 to 5; 25 is too high for some APIs, e.g., Google+.
Handle additional errors from oauthclient/client.py.
Improve error handling for mobile device operations.

4.44.08

Allow empty values for customer_id and domain in gam.cfg.

4.44.07

Clean up exception handling.

4.44.06

Changed headings of gam print vacation CSV file to match command line arguments.
    User,enabled,contactsonly,domainonly,startdate,enddate,subject,html,message

4.44.05

Added print vacation command.
    gam <UserTypeEntity> print vacation [todrive [<ToDriveAttribute>]]

Handle 1801 - Invalid value error in gam audit export.

Handle 111 - Connection refused error in gam print gplusprofile.

4.44.04

Handle Unknown Error when getting G+ profile.

4.44.03

Handle "Domain cannot use apis." error.

4.44.02

Added nocache argument to gam get drivefile to prevent the Google API from caching a file download. Due to a flaw in a Python library,
caching the download of certain files throws an exception preventing the file from being downloaded.
    gam <UserTypeEntity> get drivefile <DriveFileEntity> [format <FileFormatList>] [targetfolder <FilePath>] [revision <Number>] [nocache]

4.44.01

Clean up error messages when Google API requires that Gam wait before retrying.

4.44.00

Added Reseller API support, derived from Jay's initial code.
    <ResoldCustomerAttribute> ::=
        (email|alternateemail <EmailAddress>)|
        (contact|contactname <String>)|
        (phone|phonenumber <String>)|
        (name|organizationname <String>)|
        (address|address1|addressline1 <String>)|
        (address2|addressline2 <String>)|
        (address3|addressline3 <String>)|
        (city|locality <String>)|
        (state|region <String>)|
        (zipcode|postal|postalcode <String>)|
        (country|countrycode <String>)

    gam create resoldcustomer <CustomerDomain> (customer_auth_token <String>) <ResoldCustomerAttribute>+
    gam update resoldcustomer <CustomerID> [customer_auth_token <String>] <ResoldCustomerAttribues>+
    gam info resoldcustomer <CustomerID>

    gam create resoldsubscription <CustomerID> (sku <SKUID>)
         (plan annual_monthly_pay|annual_yearly_pay|flexible|trial) (seats <NumberOfSeats> <MaximumNumberOfSeats>)
         [customer_auth_token <String>] [deal <String>] [purchaseorderid <String>]
    gam update resoldsubscription <CustomerID> <SKUID>
        activate|suspend|startpaidservice|
        (renewal auto_renew_monthly_pay|auto_renew_yearly_pay|cancel|renew_current_users_monthly_pay|renew_current_users_yearly_pay|switch_to_pay_as_you_go)|
        (seats <NumberOfSeats> [<MaximumNumberOfSeats>])|
        (plan annual_monthly_pay|annual_yearly_pay|flexible|trial [deal <String>] [purchaseorderid <String>] [seats <NumberOfSeats> [<MaximumNumberOfSeats>]])
    gam delete resoldsubscription <CustomerID> <SKUID> cancel|downgrade|transfer_to_direct
    gam info resoldsubscription <CustomerID>  <SKUID>
    gam show resoldsubscriptions [customerid <CustomerID>] [customer_auth_token <String>] [customer_prefix <String>]
    gam print resoldsubscriptions [todrive [<ToDriveAttribute>]] [customerid <CustomerID>] [customer_auth_token <String>] [customer_prefix <String>]

Added createifnotfound to update users. If, when attempting to update a single user, the user is not found, this argument causes Gam to create the user.
This is a special purpose feature, it will typically be used when an information system outputs a CSV file of user data but does not indicate which
users are new.
    gam update user <UserItem> <UserAttribute>* [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [createifnotfound]
    gam update users <UserTypeEntity> <UserAttribute>* [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [createifnotfound]
    gam <UserTypeEntity> update users <UserAttrubutes>* [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [createifnotfound]
Example:
    gam  redirect stdout Update.log multiprocess redirect stderr stdout csv Users.csv gam update user "~Email" firstname "~Firstname" lastname "~Lastname" password "~Password" org "~Org" createifnotfound

4.43.04

Make no_cache = False and cache_discovery_only = True be the default.
Change the signal file for cache_discovery_only to allcache.txt
When gam.cfg is being initialized, cache_discovery_only will be set to false if the file is present, otherwise true.

4.43.03

Improve error messages for invalid queries and custom schemas in info/print users.

4.43.02

Fix bug in gam add drivefileacl where incorrect parameter was passed to API.

4.43.01

When todrive tdparent id:<DriveFolderID>|<DriveFolderName> is specified, in addition to checking that the parent is an existing folder, the folder is verified as being writable.

4.43.00

Continued code refactoring.

The elements of a <ProductIDList> or <SKUIDList> must be separated by commas not spaces; this applies to gam print licenses, gam info users, gam print users
and gam licenses <SKUIDLIst> <Command> ...

Added LicensesDisplay column to CSV file for gam print users licenses to show descriptive name of license SKU.
The Licenses column still displays the actual SKU.

Added tduser <EmailAddress> to <ToDriveAttribute>.
Added todrive_user to gam.cfg
Anywhere you can specify todrive, there are additional subarguments following the todrive argument that let you title the file,
direct the uploaded file to a particular user and location and add a timestamp to the file title.
    <ToDriveAttribute> ::=
        (tdtitle <String>)|(tduser <EmailAddress>)|(tdparent id:<DriveFolderID>|<DriveFolderName>)|(tdtimestamp <Boolean> [tddaysoffset <Number>] [tdhoursoffset <Number])
The tdtitle argument specifies the title for the uploaded file, if not specified, the Gam default title is used.
The tduser argument specifies the user to receive the uploaded file; if not specified, the todrive_user value from gam.cfg is used;
that value defaults to the user named in oauth2.txt.
The tdparent argument specifies an existing/writable parent folder for the uploaded file; if not specified, the todrive_parent value from gam.cfg is used;
that value defaults to the root folder.
The tdtimestamp argument specifies whether a timestamp (of the time the file is uploaded to Google) will be added to the title of the uploaded file;
if not specified, the todrive_timestamp value from gam.cfg is used, that value defaults to False.
The tddaysoffset and tdhoursoffset arguments let you specify values that subtract time from the timestamp, they default to 0.
A possible use for these values is as documentation to reflect the end of the time period that the uploaded report covers.
Example: generate a list of user IDs and names, title the file "User IDs and Names", upload it to the "GAM Reports" folder of usermgr@domain.com, add a timestamp to the title.
    gam print users todrive tdtitle "User IDs and Names" tduser usermgr@domain.com tdparent "GAM Reports" tdtimestamp true id name

4.42.10

Define NullHandler for logging to accommodate Python 2.6.

4.42.09

Handle unbalanced quotes errors in gam batch.
If errors are encountered a batch file, none of the commands will be executed.

4.42.08

Fixed bug where the file description was not set on a redirected multiprocess CSV file when todrive was specified.

4.42.07

For print courses, sort column headings in a more meaningful order, put courseMaterialSets in rightmost columns.

4.42.06

In gam print courses, length columns are not included for the materials field in courseMaterialSets as this makes for too many columns.

4.42.05

Added restricted argument to gam claim ownership to restrict viewers and commenters from copying, downloading and printing the claimed files.
    gam <UserTypeEntity> claim ownership <DriveFileEntity> [skipids <DriveFileEntity>] [skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>] [includetrashed]
        [restricted [<Boolean>]] [writerscantshare [<Boolean>]] [preview] [filepath] [todrive [<ToDriveAttribute>]]

4.42.04

When debug_level is > 0 and stdout is redirected, the http debug output is now properly redirected as well.

4.42.03

Handle error where the batch.bat file in gam batch batch.bat contains a gam batch/csv command or a command that invokes an auto batch.
Fix control-C handling.

4.42.02

Handle httplib.ResponseNotReady error.

4.42.01

Changed gam info user formatjson to show licenses in SKU ID (SKU Display Name) format.

4.42.00

Fixed problem where control-C was not recognized when multiple processes were running via gam batch/csv.
Gam terminates cleanly on Linux/MacOS when you hit control-C in this situation; on Windows exceptions are
thrown but Gam does terminate.

4.41.08

Eliminate unnecessary/possibly invalid use of fields=u'' in various API calls.

4.41.07

Added labelidsonly argument to gam print/show filters to improve performance in special cases.
When you get a filter from Google, all labels mentioned in the filter are specified with their internal Id, not the label name the user sees.
Gam has to make an extra API call to get the labels so it can map from id to name so the output reflects the label names that are familiar to the user.
If you don't need to see the label names, you can eliminate the extra API call by specifying labelidsonly.
    gam <UserTypeEntity> show filters [labelidsonly]
    gam <UserTypeEntity> print filters [labelidsonly] [todrive [<ToDriveAttribute>]]

4.41.06

More fixes to gam user deprovision.

4.41.05

Fix coding error in gam user deprovision that prevented tokens from being deleted if there were no ASPs.

4.41.04

Additional license SKU cleanup.
Speed up gam print users licenses.

4.41.03

Additional license SKU cleanup.

4.41.02

Added skuDisplay column to CSV file for gam print licenses to show descriptive name of license SKU.
The skuId column still displays the actual SKU.

4.41.01

Add product <ProductID> argument to license commands to allow for future changes by Google.
Improve license handling courtesy of Jay.
    gam <UserTypeEntity> add license <SKUID> [product|productid <ProductID>]
    gam <UserTypeEntity> update license <SKUID> [product|productid <ProductID>] [from] <SKUID>
    gam <UserTypeEntity> delete license <SKUID> [product|productid <ProductID>]

4.41.00

Thanks to Kim Nilsson for inspiring the following change.
Many Gam commands have this form:
    gam <UserTypeEntity> command arguments
    gam <CrOSTypeEntity> command arguments
<UserTypeEntity> and <CrOSTypeEntity> get data either from Google via API calls or from local files.
Previously, Gam would get the data and then parse the command and arguments; any syntax error terminated processing.
If the data was coming from Google via API calls, all of the time/bandwidth spent getting the data was wasted.
Now, if the data is coming from Google via API calls, it is not retrieved unless command/argument processing is successfully completed.
If auto_batch_min from gam.cfg is greater than zero, the data is retrieved immediately as the data must be passed to the Gam subprocesses.

4.40.12

Fix redirect csv/stdout/stderr file error handling.

4.40.11

G Suite Enterprise SKU changed from Google-Apps-Enterprise to 1010020020.
Improve redirect csv/stdout/stderr.

4.40.10

Code clean up.

4.40.09

Improve redirect stdout multiprocess with auto_batch.

4.40.08

Handle SSLHandshakeError as a retryable error.

4.40.07

Previously, auto_batch processing was disabled for info, show and print because the output from the
multiple processes was mixed together. With the introduction of redirect csv/stdout multiprocess in 4.40.00,
this restriction has been eliminated. The following template illustrates the proper form of the command.
    gam config num_threads 10 auto_batch_min 1 redirect csv ./output.csv multiprocess all users print ...
    gam config num_threads 10 auto_batch_min 1 redirect stdout ./output.txt multiprocess all users show ...

4.40.06

Added support for reporting user's two step verification status.
Additional work on calendars.
Additional code cleanup.

Added S/MIME support thanks to Jay. You must be a G Suite Enterprise customer to use these commands.
    gam <UserTypeEntity> add smime file <FileName> [password <Password>] [sendas|sendasemail <EmailAddress>] [default]
    gam <UserTypeEntity> update smime [id <SmimeID>] [sendas|sendasemail <EmailAddress>] [default]
    gam <UserTypeEntity> delete smime [id <SmimeID>] [sendas|sendasemail <EmailAddress>]
    gam <UserTypeEntity> show smimes [primaryonly]
    gam <UserTypeEntity> print smimes [todrive [<ToDriveAttribute>]] [primaryonly]

4.40.05

Fixed todrive.

Restore gam calendar/calendars commands.
The column labeled id in gam print calendars has been changed to calendarId.

Code clean up.
Documentation updates.

4.40.04

More cleanup of redirect stdout/stderr multiprocess.
Add return code to stdout/stderr Start lines when show_multiprocess_info is true.

4.40.03

Fix error with redirect stdout multiprocess.
Add return code to stdout/stderr End lines when show_multiprocess_info is true.

4.40.02

Improved performance of gam modify/spam messages by using new batchModify API function.

Added message_batch_size to gam.cfg
    message_batch_size
        When deleting or modifying Gmail messages, how many should be processed in each batch
        Default: 1000

Added message_max_results to gam.cfg
    message_max_results
        When retrieving lists of Gmail messages from API, how many should be retrieved in each chunk
        Default: 1000

4.40.01

Housecleaning.
Improve handling member of type CUSTOMER in groups.
Handle errors when updating a users photo.

4.40.00

Added classroom_max_results to gam.cfg
    classroom_max_results
        When retrieving lists of Google Classroom items from API, how many should be retrieved in each chunk
        Default: 0 (Google defined limit)

Added convertcrnl argument to gam print orgs, it causes \n to be converted to \\n in description, otherwise \n is not changed in that field.
gam print orgs|ous [todrive [<ToDriveAttribute>]] [toplevelonly] [from_parent <OrgUnitItem>] [allfields|<OrgUnitFieldName>*|(fields <OrgUnitFieldNameList>)] [convertcrnl]

SKU Google-Apps-Unlimited renamed to Google-Apps-Enterprise.

Added multiprocess subargument to redirect csv/stdout/stderr arguments to allow the multiple processes started by gam csv to write intelligently to a redirected CSV/stdout/stderr file.
You can redirect stdout and stderr to null and stderr can be redirected to stdout.
<Redirect> ::=
        redirect csv <FileName> [multiprocess] [append] [noheader] [charset <Charset>] [columndelimiter <Character>] |
        redirect stdout <FileName> [multiprocess] [append] |
        redirect stdout null |
        redirect stderr <FileName> [multiprocess] [append] |
        redirect stderr stdout |
        redirect stderr null
Examples:
    gam redirect stdout Users.txt multiprocess csv Users.csv gam info user ~primartEmail
The output from each of the gam info user ~User commands will be combined into the single file UserInfo.txt
    gam redirect csv UserDelegates.csv multiprocess csv Users.csv gam user ~User print delegates
The output from each of the gam user ~User print delegates commands will be combined into the single file UserDelegates.csv.

Added show_multiprocess_info to gam.cfg.
    show_multiprocess_info
        Enable/disable showing multiprocess info in redirected stdout/stderr
        Default: False
Example:
Example:
$ gam config show_multiprocess_info false redirect stdout ./Users.txt multiprocess csv Users.csv gam info user ~primaryEmail
$ more Users.txt
User: testuser1@domain.com (1/1)
  Settings:
    First Name: Test
    Last Name: User1
    Full Name: Test User1
...
User: testuser2@domain.com@ (1/1)
  Settings:
    First Name: Test
    Last Name: User2
    Full Name: Test User2
...

$ gam config show_multiprocess_info true redirect stdout ./Users.txt multiprocess csv Users.csv gam info user ~primaryEmail
$ more Users.txt
stdout:      0, Start: 2017-01-26T11:35:00.897773-08:00, Cmd: /Users/admin/gam config show_multiprocess_info true redirect stdout ./Users.txt multiprocess csv Users.csv gam info user ~primaryEmail
stdout:      1, Start: 2017-01-26T11:35:00.902709-08:00, Cmd: gam info user testuser1
User: testuser1@domain.com (1/1)
  Settings:
    First Name: Test
    Last Name: User1
    Full Name: Test User1
...
stdout:      1,   End: 2017-01-26T11:35:02.656837-08:00
stdout:      2, Start: 2017-01-26T11:35:00.910729-08:00, Cmd: gam info user testuser2
User: testuser2@domain.com@ (1/1)
  Settings:
    First Name: Test
    Last Name: User2
    Full Name: Test User2
...
stdout:      2,   End: 2017-01-26T11:35:02.849646-08:00
stdout:      0,   End: 2017-01-26T11:35:02.907141-08:00

The gam printer and gam printers commands have been combined; both forms can handle multiple printerIDs.
    gam print|printers <PrinterIDEntity> add user|manager|owner <UserTypeEntity>|domain:<DomainName>|public
    gam print|printers <PrinterIDEntity> delete <UserTypeEntity>|domain:<DomainName>|public
    gam print|printers <PrinterIDEntity> sync user|manager|owner <UserTypeEntity>|domain:<DomainName>|public

Added new forms of commands to manage multiple users.
    gam <UserTypeEntity> update users <UserAttrubutes> [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
    gam <UserTypeEntity> delete users
    gam <UserEntity> undelete users [org|ou <OrgUnitPath>]
    gam <UserTypeEntity> info users [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas|custom <SchemaNameList>] [userview] <UserFieldName>* [fields <UserFieldNameList>] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)] [formatjson]
The existing forms are:
    gam update users <UserTypeEntity> <UserAttribute>* [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
    gam delete users <UserTypeEntity>
    gam undelete users <UserEntity> [org|ou <OrgUnitPath>]
    gam info users <UserTypeEntity> [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas|custom <SchemaNameList>] [userview] <UserFieldName>* [fields <UserFieldNameList>] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)] [formatjson]

Gam calendar processing has been rewritten to expand its capabilities.
Previous versions could:
Manage a users list of calendars
Manage access to a users primary calendar
Transfer ownership of all of a users calendars to another user
Add and delete events in a users primary calendar
Provide limited event selection: keyword matching only
Replace attendees in a users primary calendar for all events within a datetime range

This version can:
Manage a users list of calendars
Create, modify and remove calendars for a user
Manage access to any calendar a user owns
Transfer ownership of a selection of a users calendars to another user
Add, update, delete and display events in any calendar for which a user has access
Provide expanded event selection: keyword matching, date selection, field matching, attendee matching
Replace attendees for selected events in any calendar for which a user has access

<CalendarSelectProperties> ::=
        (minaccessrole <CalendarACLRole>)|showdeleted|showhidden

<CalendarAddEntity> ::= <EmailAddressList> | resource <ResourceID> | resources <ResourceIDList> | (calendars <CalendarList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>)
<CalendarEntity> ::= allcalendars | primary | <EmailAddressList> | resource <ResourceID> | resources <ResourceIDList> | (calendars <CalendarList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>) | <CalendarSelectProperties>+
<CalendarPrintShowEntity> ::= allcalendars | primary | <CalendarSelectProperties>+

<CalendarAttribute> ::=
        (backgroundcolor <ColorHex>)|
        (colorindex|colorid <CalendarColorIndex>)|
        (foregroundcolor <ColorHex>)|
        (hidden <Boolean>)|
        (notification clear|(email|sms eventcreation|eventchange|eventcancellation|eventresponse|agenda))|
        (reminder clear|(email|sms|pop <Number>)|(<Number> email|sms|pop))|
        (selected <Boolean>)|
        (summary <String>)

Manage a users list of calendars

gam <UserTypeEntity> add calendars <CalendarAddEntity> <CalendarAttribute>*
gam <UserTypeEntity> update calendars <CalendarEntity> <CalendarAttribute>+
gam <UserTypeEntity> delete calendars <CalendarEntity>

gam <UserTypeEntity> info calendars <CalendarEntity>
gam <UserTypeEntity> show calendars <CalendarPrintShowEntity> [permissions]
gam <UserTypeEntity> print calendars <CalendarPrintShowEntity> [todrive [<ToDriveAttribute>]] [permissions]

gam <UserTypeEntity> show calsettings

<CalendarSettings> ::==
        (summary <String>)|(description <String>)|(location <String>)|(timezone <TimeZone>)

Create, modify and remove calendars for a user

gam <UserTypeEntity> create calendar <CalendarSettings>
gam <UserTypeEntity> modify calendars <CalendarEntity> <CalendarSettings>
gam <UserTypeEntity> remove calendars <CalendarEntity>

<CalendarACLRole> ::=
        editor|freebusy|freebusyreader|owner|reader|writer

<CalendarACLScope> ::= [user:]<EmailAddress>|group:<EmailAddress>|domain[:<DomainName>]|default
<CalendarACLScopeList> ::== '<CalendarACLScope>(,<CalendarACLScope>)*'
<CalendarACLScopeEntity>::= <ACLScopeList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>

Manage access to any calendar a user owns

gam <UserTypeEntity> add calendaracls <CalendarEntity> <CalendarACLRole> <CalendarACLScopeEntity>
gam <UserTypeEntity> update calendaracls <CalendarEntity> <CalendarACLRole> <CalendarACLScopeEntity>
gam <UserTypeEntity> delete calendaracls <CalendarEntity> <CalendarACLRole>] <CalendarACLScopeEntity>

gam <UserTypeEntity> info calendaracls <CalendarEntity> <CalendarACLScopeEntity>
gam <UserTypeEntity> show calendaracls <CalendarEntity>
gam <UserTypeEntity> print calendaracls <CalendarEntity> [todrive [<ToDriveAttribute>]]

Transfer ownership of a selection of a users calendars to another user

gam <UserTypeEntity> transfer calendars <UserItem> <CalendarEntity> [keepuser] [retainrole <CalendarACLRole>]

<EventSelectProperties:> ::=
        (endtime|timemax <Time>)|
        (query <QueryCalendar>)|
        (privateextendedproperty <String>)|
        (sharedextendedproperty <Syting>)|
        showdeletedevents|
        showhiddeninvitations|
        singleevents|
        (starttime|timemin <Time>)|
        (updatedmin <Time>)

<EventMatchProperties:> ::=
        (matchfield attendees <EmailAddressList>)|
        (matchfield creatoremail <RegularExpression>)|
        (matchfield creatorname <RegularExpression>)|
        (matchfield description <RegularExpression>)|
        (matchfield location <RegularExpression>)|
        (matchfield organizeremail <RegularExpression>)|
        (matchfield organizername <RegularExpression>)|
        (matchfield summary <RegularExpression>)

<EventEntity> ::=
        (events <EventIdList> | <FileSelector> | <CSVkmdSelector> | <CSVSubkeySelector> | <CSVDataSelector>)|
        (<EventSelectProperties>+ <EventMatchProperties>*)

<EventAddAttribute> ::=
        (anyonecanaddself <Boolean>)|
        (attendee <EmailAddress>)|
        available|
        (colorindex|colorid <EventColorIndex>))|
        (description <String>)|
        (end (allday <Date>)|<Time>)|
        (guestscaninviteothers <Boolean>)|
        guestscantinviteothers|
        (guestscanseeotherguests <Boolean>)|
        guestscantseeothers|
        (location <String>)|
        (noreminders|(reminder email|popup|sms <Number>))|
        notifyattendees|
        (optionalattendee <EmailAddress>)|
        (privateproperty <PropertyKey> <PropertyValue>)|
        (recurrence <RRULE, EXRULE, RDATE and EXDATE line>)|
        (reminder <Number> email|popup|sms))|
        (sendnotifications <Boolean>)|
        (sharedproperty <PropertyKey> <PropertyValue>)|
        (source <String> <URL>)|
        (start (allday <Date>)|<Time>)|
        (status confirmed|tentative|cancelled)|
        (summary <String>)|
        tentative
        (timezone <TimeZone>)|
        (transparency opaque|transparent)|
        (visibility default|public|prvate)

Note!!!
The following attributes are equivalent:
        available = transparency transparent
        guestscantinviteothers = guestscaninviteothers False
        guestscantseeothers = guestscanseeotherguests False
        tentative = status tentative

<EventUpdateAttribute> ::=
        <EventAddAttribute>|
        (clearprivateproperty <PropertyKey>)|
        (clearsharedproperty <PropertyKey>)

Add update and delete events in any calendar for which a user has access

gam <UserTypeEntity> add event <CalendarEntity> [id <String>] <EventAddAttribute>+
gam <UserTypeEntity> update events <CalendarEntity> <EventEntity> <EventUpdateAttribute>+
gam <UserTypeEntity> delete events <CalendarEntity> <EventEntity> [doit] [notifyattendees]
gam <UserTypeEntity> wipe events <CalendarEntity>
gam <UserTypeEntity> move events <CalendarEntity> <EventEntity> to <CalendarItem> [notifyattendees]
gam <UserTypeEntity> update calattendees <CalendarEntity> <EventEntity> [anyorganizer] [csv <FileName>] (replace <EmailAddress> <EmailAddress>)* [doit]

<EventDisplayProperties> ::=
        (alwaysincludeemail)|
        (icaluid <String>)|
        (maxattendees <Integer>)|
        (orderby starttime|updated)|
        (timezone <TimeZone>)

gam <UserTypeEntity> info events <CalendarEntity> <EventEntity>
gam <UserTypeEntity> show events <CalendarPrintShowEntity> ([allevents] <EventSelectProperties>*) <EventDisplayProperties>*
gam <UserTypeEntity> print events <CalendarPrintShowEntity> ([allevents] <EventSelectProperties>*) [todrive [<ToDriveAttribute>]] <EventDisplayProperties>*

gam resource calendar processing has been rewritten.

# Resource Calendars

<ResourceID> ::= <String>
<ResourceIDList> ::= '<ResourceID>(,<ResourceID>)*'
<ResourceEntity> ::= <ResourceIDList> | <FileSelector> | <CSVkmdSelector>

<ResourceFieldName> ::=
        acls|
        description|
        email|
        id|
        name|
        type
<ResourceFieldNameList> ::= '<ResourceFieldName>(,<ResourceFieldName>)*'

gam create resource <ResourceID> <Name> [description <String>] [type <String>]
gam update resource <ResourceID> [name <Name>] [description <String>] [type <String>]
gam delete resource <ResourceID>
gam info resource <ResourceID>

gam update resources <ResourceEntity> [name <Name>] [description <String>] [type <String>]
gam delete resources <ResourceEntity>
gam info resources <ResourceEntity>

gam show resources [allfields|<ResourceFieldName>*|(fields <ResourceFieldNameList>)] [convertcrnl]
gam print resources [todrive [<ToDriveAttribute>]] [allfields|<ResourceFieldName>*|(fields <ResourceFieldNameList>)] [convertcrnl]

gam resource <ResourceID> add calendaracls <CalendarACLRole> <CalendarACLScopeEntity>
gam resource <ResourceID> update calendaracls <CalendarACLRole> <CalendarACLScopeEntity>
gam resource <ResourceID> delete calendaracls <CalendarACLRole>] <CalendarACLScopeEntity>
gam resource <ResourceID> info calendaracls <CalendarACLScopeEntity>

gam resources <ResourceEntity> add calendaracls <CalendarACLRole> <CalendarACLScopeEntity>
gam resources <ResourceEntity> update calendaracls <CalendarACLRole> <CalendarACLScopeEntity>
gam resources <ResourceEntity> delete calendaracls <CalendarACLRole>] <CalendarACLScopeEntity>
gam resources <ResourceEntity> info calendaracls <CalendarACLScopeEntity>

4.39.26

The csv argument has been dropped from gam printer <PrinterIDEntity> showacls. A new command has been added to
output printer ACLs to a CSV file.
    gam printers <PrinterIDEntity> showacls
    gam printers <PrinterIDEntity> printacls [todrive [<ToDriveAttribute>]]

Added fields <ResourceFieldNameList> to gam print resources
    <ResourceFieldName> ::=
        description|
        email|
        id|
        name|
        type
    <ResourceFieldNameList> ::= '<ResourceFieldName>(,<ResourceFieldName>)*'

    gam print resources [todrive [<ToDriveAttribute>]] [allfields|<ResourceFieldName>*|(fields <ResourceFieldNameList>)] [convertcrnl]

Handle bad data from Google in gam report users.

4.39.25

Added buildpath argument to gam create org.
    gam create org|ou <Name> [description <String>] [parent <OrgUnitItem>] [inherit|noinherit|(blockinheritance <Boolean>)] [buildpath]
You can create an org unit in two ways: specify the full path to the org unit or specify the org unit name and parent path.
These are equivalent:
    gam create org /aaa/bbb/ccc/ddd
    gam create ddd parent /aaa/bbb/ccc
The API requires a separate org unit name and parent path, gam makes this separation for you regardless of how you entered the data.
It is an error if the parent path does not exist. In this case, specifying the buildpath argument causes gam to build the parent path.
Suppose /aaa exists and you enter the command: gam create org /aaa/bbb/ccc/ddd buildpath. The initlal API will fail because /aaa/bbb/ccc
does not exist. Gam builds /aaa/bbb, then /aaa/bbb/ccc and finally /aaa/bbb/ccc/ddd.
If a description is specified, it is only applied to the last name in the full path, ddd in this example.

Added fields argument to gam print orgs.
    <OrgUnitFieldName> ::=
        description|
        id|orgunitid|
        inherit|blockinheritance|
        name|
        parentid|parentorgunitid|
        parent|parentorgunitpath|
        path|orgunitpath
    <OrgUnitFieldNameList> ::= '<OrgUnitFieldName>(,<OrgUnitFieldName>)*'

    gam print orgs|ous [todrive [<ToDriveAttribute>]] [toplevelonly] [from_parent <OrgUnitItem>] [allfields|<OrgUnitFieldName>*|(fields <OrgUnitFieldNameList>)]

4.39.24

Added command gam show orgtree to show a tree of organization units. The from_parent argument lets you specify
a particular starting point.
    gam show orgtree [from_parent <OrgUnitItem>]

4.39.23

Update http2lib/cacerts.txt

4.39.22

Apply Jay's fix to correct gam create project problem.

4.39.21

When specifiying multivalued schema field values, empty values can be suppressed by using the multinonempty option.
This is most useful when updating users from a CSV file where users have different numbers of values for a multivalued schema field.
    <SchemaName>.<FieldName> [multivalued|multivalue|value|multinonempty [type work|home|other|(custom <String>)]] <String>)

4.39.20

Handle group member of type customer when processing groups.

4.39.19

Added skipfields <CourseFieldNameList> argument to gam print courses to allow deselection of specific fields to print.
    gam print courses [todrive [<ToDriveAttribute>]] [teacher <UserItem>] [student <UserItem>] [alias|aliases] [delimiter <String>]
        [show all|students|teachers] [fields <CourseFieldNameList>] [skipfields <CourseFieldNameList>]

4.39.18

group <GroupName> should only return users except when updating groups or printer ACLs. Previously, group <GroupName> returned
all members (users and groups) which would cause errors when executing commands like: gam group <GroupName> ...
Previously, this command would print all group members: gam group <GroupName> print
Now, it will only print the users; use this command to get the list of member (user and group) email addresses:  gam print group-members group <GroupName> email

4.39.17

Handle enable API error in gam create project.

4.39.16

Allow newlines in calendar event descriptions.

4.39.15

Start transition of delegate handling from GData to GAPI.
Dropped csv argument from gam show delegates; use gam print delegates to get CSV format.
    gam <UserTypeEntity> show delegates|delegate
    gam <UserTypeEntity> print delegates [todrive [<ToDriveAttribute>]]

4.39.14

Date change in 4.39.13 was off by one day, corrected.

4.39.13

Update gam report admin|calendars|drive|groups|logins|mobile|tokens to print start_time and end_time parameters as dates rather than big integers.

4.39.12

Added fields <CourseFieldNameList> argument to gam print courses to allow selection of specific fields to print.

<CourseFieldName> ::=
        alternatelink|
        coursegroupemail|
        coursematerialsets|
        coursestate|
        creationtime|
        description|
        descriptionheading|
        enrollmentcode|
        guardiansenabled|
        id|
        name|
        ownerid|
        room|
        section|
        teacherfolder|
        teachergroupemail|
        updatetime
<CourseFieldNameList> ::= '<CourseFieldName>(,<CourseFieldName>)*'

    gam print courses [todrive [<ToDriveAttribute>]] [teacher <UserItem>] [student <UserItem>] [alias|aliases] [delimiter <String>] [show all|students|teachers] [fields <CourseFieldNameList>]

4.39.11

Fixed gam create project.

4.39.10

Fixed gam transfer drive to move orphaned files of the source user to the proper folder of the target user.

4.39.09

Added suspended argument to gam update group clear so that only suspended members of a group are removed.
    gam update group <GroupItem> clear [member] [manager] [owner] [suspended]
    gam update groups <GroupEntity> clear [member] [manager] [owner] [suspended]

4.39.08

Added shownoneditable argument to gam print aliases; this will show noneditable aliases in a column labeled NonEditableAlias.

4.39.07

Fixed my coding mistake in gam info user that prevented licences from being printed.

4.39.06

Changed gam print groups output when any of members/memberscount/managers/managerscount/owners/ownerscount are specified.
When members/managers/owners are specified, there will be two columns per role: Members,MembersCount,Managers,ManagersCount,Owners,OwnersCount
When memberscount/managerscount/ownerscount are specified, there will be one column per role: MembersCount,ManagersCount,OwnersCount

Use batch processing to get licenses more quickly in gam info user.

4.39.05

Added directmemberscount to <GroupFieldName>; if this field is specified in gam print groups, it shows the number of entries in a group.

4.39.04

On initial run build drive_dir if it doesn't exist.

Fix error message in gam oauth create regarding no browser to reference no_browser in gam.cfg not nobrowser.txt.

4.39.03

Fix problem where gam update checking was performed on every call.

4.39.02

Handle suspended/no-calendar-access user in calendar commands.

4.39.01

Use patch API rather than update API for gam update customer.

4.39.00

For calendar/calendars add/update/delete acl, the scope can be specified in a new form to make it consistent with other commands.
    <ACLScope> ::= <EmailAddress>|user:<EmailAddress>|group:<EmailAddress>|domain:<DomainName>)|domain|default
    gam calendar <CalendarEntity> add acl <CalendarACLRole> <ACLScope>
    gam calendar <CalendarEntity> update acl <CalendarACLRole> <ACLScope>
    gam calendar <CalendarEntity> del|delete acl [<CalendarACLRole>] <ACLScope>

Updated calendars update/delete/move/info event to allow queries. You specify event queries or event IDs.
    gam calendar <CalendarEntity> update event (q|query|eventquery <QueryCalendar>)+|<EventIDEntity> <EventAttribute>+
    gam calendar <CalendarEntity> delete event (q|query|eventquery <QueryCalendar>)+|<EventIDEntity> [doit] [notifyattendees]
    gam calendar <CalendarEntity> move event (q|query|eventquery <QueryCalendar>)+|<EventIDEntity> to <CalendarItem> [notifyattendees]
    gam calendar <CalendarEntity> info event (q|query|eventquery <QueryCalendar>)+|<EventIDEntity>

Added primary, role <CalendarACLRole>, showdeleted, showhidden and permissions to gam print/show calendars.
    <CalendarACLRole> ::= editor|freebusy|freebusyreader|owner|reader|writer
    gam <UserTypeEntity> show calendars [primary] [role <CalendarACLRole>] [showdeleted] [showhidden] [permissions]
    gam <UserTypeEntity> print calendars [todrive [<ToDriveAttribute>]] [primary] [role <CalendarACLRole>] [showdeleted] [showhidden] [permissions]
By default, information for all visible, non-deleted calendars is shown.
primary limits the selection to the user's primary calendar.
role <CalendarACLRole> limits the selection to those calendars where the user's role is at least <CalendarACLRole>.
showdeleted adds deleted calendars to the selection.
showhidden adds hidden calendars to the selection.
permissions adds permission information for user owned calendars to the output.

Renamed command to batch delete drivefileacls.
    Old: gam <UserTypeEntity> wipe drivefileacls <DriveFileEntity> <PermissionIDEntity>
    New: gam <UserTypeEntity> delete permissions <DriveFileEntity> <PermissionIDEntity>

Eliminated command gam calendar <CalendarEntity> wipe acls

4.38.05

Allow = in gam config. The = is optional but must be surrounded by spaces if included.
    <Config> ::=
        config (<VariableName> [=] <Value)* [save] [verify]

4.38.04

Fixed bug in gam config verify.

4.38.03

Fixed bug in redirect stdout.

4.38.02

Added replace argument to gam update calattendees to allow simple attendee replacements without having to use a CSV file.
    gam <UserTypeEntity> update calattendees [csv <FileName>] (replace <EmailAddress> <EmailAddress>)* [dryrun] [start|starttime|timemin <Time>] [end|endtime|timemax <Time>] [allevents]

4.38.01

Add additional error handling for wipe drivefileacls and add drivefilepermissions.

4.38.00

Added command to batch add drivefileacls.
    <DriveFilePermission> ::= anyone|anyonewithlink|user:<EmailAddress>|group:<EmailAddress>|domain:<DomainName>|domainwithlink:<DomainName>;<DriveFileACLRole>
    <DriveFilePermissionList> ::= '<DriveFilePermission>(,<DriveFilePermission)*'
    <DriveFilePermissionEntity> ::= <DriveFilePermissionList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
    gam <UserTypeEntity> add drivefilepermissions <DriveFileEntity> <DriveFilePermissionEntity> [expiration <Time>] [sendmail] [emailmessage <String>]
Given a CSV file AddPerms.csv with three columns:
Owner,driveFileId,permissions
foo@domain.com,1-1234,"anyone;reader,user:foo@domain.com;writer,group:foo@domain.com;commenter"
goo@domain.com,1-5678,"domain:domain.com;reader"
hoo@domain.com,2-1234,"domainwithlink:domain.com;writer"
All of the permissions for each driveFileId for each owner can be added with a single command:
    gam csvkmd users AddPerms.csv keyfield Owner subkeyfield driveFileId datafield permissions delimiter "," add permissions csvsubkey driveFileId csvdata permissions

Added countsonly and summary arguments to gam report when activities are selected. When countsonly is specified, the columns will be (emailAddress, event names)
showing counts for each event for each email address. When countsonly and summary are both specified there will be two columns output (event, count) showing event names and counts.
Added yesterday to gam report when activities are selected; this sets start and end to the 24 hour period spanning the previous day.
    gam report admin|calendar|calendars|drive|docs|doc|groups|group|logins|login|mobile|tokens|token [todrive [<ToDriveAttribute>]] [maxresults <Number>]
        [([start <Time>] [end <Time>])|yesterday] [(user all|<UserItem>)|(select <UserTypeEntity>)] [event <String>] [filter|filters <String>] [ip <String>] [countsonly] [summary]

4.37.06

Fixed bug in gam show drivefileacls when role was reader and additionalRoles[0] was commenter.
Always show role as commenter rather than role as reader with additionalRoles commenter.


4.37.05

Improve message/thread error handling when ids argument is used.

4.37.04

Expanded csvkmd to take a subkeyfield, this is used to support wipe drivefileacls.
    <CrOSTypeEntity> ::=
                (csvkmd cros <FileName> [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>]
                        keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                        subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
    <UserTypeEntity> ::=
                (csvkmd users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>]
                        keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                        subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
    <CSVkmdSelector> ::=
                csvkmd <FileName> [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>]
                       keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                       subkeyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                       (matchfield <FieldName> <RegularExpression>)*
                       [datafield <FieldName>(:<FieldName)* [delimiter <String>]]

Added command to batch delete drivefileacls.
    gam <UserTypeEntity> wipe drivefileacls <DriveFileEntity> <PermissionIDEntity>
Given a CSV file DeletePerms.csv with three columns:
Owner,driveFileId,permissionIds
foo@domain.com,1-1234,"anyone,32737237,4343434"
foo@domain.com,1-5678,54758584584754
goo@domain.com,2-1234,7847834783
hoo@domain.com,3-5678,"4837448347834,dhjshdjshdjshj,sjahd8wu8"
All of the permissionIds for each driveFileId for each owner can be deleted with a single command:
    gam csvkmd users DeletePerms.csv keyfield Owner subkeyfield driveFileId datafield permissionIds delimiter "," wipe drivefileacls csvsubkey driveFileId csvdata permissionIds

4.37.03

Handle GAPI Bad Gateway error.

4.37.02

Added show all|students|teachers argument to gam print courses. This allows you to get course and participant information in the same CSV file.
    gam print courses [todrive [<ToDriveAttribute>]] [teacher <UserItem>] [student <UserItem>] [alias|aliases] [delimiter <String>] [show all|students|teachers]

Handle additional Google misreporting invalid group in gam print groups settings.

4.37.01

Correct CSV handling for gam redirect csv foo.csv multiprocess loop loop.csv gam ...

4.37.00

Initialize logging with NullHandler.
Point to new Wiki.
Reorganize GamCommands.txt.

4.36.06

Define logging level as CRITICAL to keep APIs silent.
Define Google Product SKU Google-Apps-For-Government (gafg)

4.36.05

Fixed bug in doCSV.

4.36.04

Fix bug in SetGlobalVariables.

4.36.03

Added addparents and removeparents arguments to gam update drivefile to allow adding/removing parents to/from a file.
    <DriveFileUpdateAttribute> ::=
        (localfile <FileName>)|
        (ocr)|(ocrlanguage <Language>)|(restricted|restrict <Boolean>)|(starred|star <Boolean>)|(trashed|trash <Boolean>)|(viewed|view <Boolean>)|
        (lastviewedbyme <Time>)|(modifieddate <Time>)|(description <String>)|(mimetype gdoc|gdocument|gdrawing|gfolder|gdirectory|gform|gfusion|gpresentation|gscript|gsite|gsheet|gspreadsheet)|
        (parentid <DriveFolderID>)|(parentname <FolderName>)|(addparents <DriveFolderIDList>)|(removeparents <DriveFolderIDList>)|writerscantshare
    gam <UserTypeEntity> update drivefile <DriveFileEntity> [copy] [newfilename <DriveFileName>] <DriveFileUpdateAttribute>*

4.36.02

Allow quotes around section name in gam.cfg to fix an initial setup error.

4.36.01

Fix error when passing delimiter to CSV file routines.

4.36.00

Note!!! Syntax changed; the redirect argument has been changed to avoid an ambiguity. Previously, if you wanted to redirect multiple files,
you would say: redirect csv <FileName> ... stdout <FileName> ... stderr <FileName> ...
Now, you must put redirect before each redirected file: redirect csv <FileName> ... redirect stdout <FileName> ... redirect stderr <FileName> ...
<Redirect> ::=
    redirect csv <FileName> [multiprocess] [append] [noheader] [charset <Charset>] [columndelimiter <Character>] |
    redirect stdout <FileName> [append] |
    redirect stderr <FileName> [append]

Identified multi-processing errors, switched back from multi-threading.

Added multiprocess subargument to redirect csv argument to allow the multiple processes started by gam csv to write intelligently to a single CSV file.
    gam redirect csv UserDelegates.csv multiprocess csv Users.csv gam user ~User print delegates
The output from each of the gam user ~User print delegates commands will be combined into the single file UserDelegates.csv.

4.35.01

Improved performance of gam print groups when select <groupEntity> is specified.

4.35.00

Reverted to multi-threading, multi-processing was causing errors.

Added argument columndelimiter <String> to all places where a CSV file can be specified to allow specification of an alternate column delimiter.
    <CrOSTypeEntity> ::=
                (croscsvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <String>])|
                (csvkmd cros <FileName> [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>]
                        keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
    <UserTypeEntity> ::=
                (csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <String>])|
                (csvkmd users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>]
                        keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
    <CSVkmdSelector> ::= csvkmd <FileName> [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>]
                            keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                            (matchfield <FieldName> <RegularExpression>)*
                            [datafield <FieldName>(:<FieldName)* [delimiter <String>]]
    <FileSelector> ::= (file <FileName> [charset <Charset>])|(csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>])
    gam csv <FileName>|- [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>
    gam loop <FileName>|- [charset <Charset>] [columndelimiter <String>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>

Note!!! Syntax changed; delimiter was changed to columndelimiter in the redirect argument.
    <Redirect> ::=
        redirect [csv <FileName> [append] [noheader] [charset <Charset>] [columndelimiter <Character>] [stdout <FileName> [append]] [stderr <FileName> [append]]

4.34.05

Fix error in gam print groups.

In gam info group, sort extended settings.

4.34.04

Call logging.basicConfig to handle logging messages for oauth2client.contrib.multiprocess_file_storage.

4.34.03

Added memberscount, managerscount and ownerscount arguments to gam print groups; they cause the number of members/managers/owners to be shown,
not the list of email addresses. If any of the members, managers or owners arguments are specified and countsonly is specified, only the counts will be shown.
    gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [maxresults <Number>] [allfields|([settings] <GroupFieldName>* [fields <GroupFieldNameList>])] [convertcrnl] [delimiter <String>]
        [members|memberscount] [managers|managerscount] [owners|ownerscount] [countsonly]

4.34.02

Added allfields argument to gam print groups; this selects all of the basic group settings and all of the extended groups settings.
    gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [maxresults <Number>] [convertcrnl] [delimiter <String>] [countsonly]
        [members] [managers] [owners] [allfields|([settings] <GroupFieldName>* [fields <GroupFieldNameList>])]

4.34.01

Additional error checking for group settings operations.

4.34.00

Added csv_input_column_delimiter, csv_output_convert_text_nl, csv_output_column_delimiter and csv_output_field_delimiter to gam.cfg.
    csv_input_column_delimiter
        Column delimiter used when reading CSV files; this must be a single character
        Default: ','
    csv_output_convert_cr_nl
        Convert carriage returns (CR) to "\r" and newlines (NL) to "\n" when writing CSV files
        The commands gam print groups|sites|messages|threads and gam show sites|messages|threads have
        an argument, convertcrnl, that can set this value to true.
        For backwards compatibility the default is False, True is probably the preferred value.
        Default: False
    csv_output_column_delimiter
        Column delimiter used when writing CSV files; this must be a single character
        The redirect csv <FileName> [append] [charset <CharSet>] [delimiter <Character>] argument can override this value.
        Default: ','
    csv_output_field_delimiter
        Field list delimiter used when writing CSV output files; this must be a single character
        With the default value of an empty string:
        Each of the gam print courses|datatransfers|filelist|groups|messages|printers|printjobs|sites|threads|tokens|users commands has a delimiter <String> argument that can override this value.
        Default: ' '

Added show_convert_cr_nl to gam.cfg.
    show_convert_cr_nl
        Convert carriage returns (CR) to "\r" and newlines (NL) to "\n" when showing data
        Convert newlines in text fields to "\n" when showing data
        Default: False

4.33.02
Added noheader argument to gam redirect csv to suppress witing column headers to CSV file.
For redirect csv, the optional arguments must appear in the order shown.
    <Redirect> ::=
        redirect [csv <FileName> [append] [noheader] [charset <Charset>] [delimiter <Character>] [stdout <FileName> [append]] [stderr <FileName> [append]]

4.33.01

Anywhere you can specify todrive, there are additional subarguments following the todrive argument that let you title the file,  direct the uploaded file to a particular location and add a timestamp to the file title.
    <ToDriveAttribute> ::=
        (tdtitle <String>)|(tdparent id:<DriveFolderID>|<DriveFolderName>)|(tdtimestamp <Boolean> [tddaysoffset <Number>] [tdhoursoffset <Number])
The tdtitle argument specifies the title for the uploaded file, if not specified, the Gam default title is used.
The tdparent argument specifies the parent folder for the uploaded file; it must specify an existing Drive folder owned by the user named in oauth2.txt.
The tdtimestamp argument specifies whether a timestamp (of the time the file is uploaded to Google) will be added to the title of the uploaded file.
tdparent and tdtimestamp default to the values specified in gam.cfg.
The tddaysoffset and tdhoursoffset arguments let you specify values that subtract time from the timestamp, possibly as documentation to reflect the end of the time period that the uploaded report covers.
Example, generate a list of users, upload to the 'GAM Reports' folder, add a timestamp to the title.
    gam print users todrive tdparent 'GAM Reports' tdtimestamp true id name
To make these values be the default, add the following two lines to gam.cfg.
    todrive_parent = 'GAM Reports'
    todrive_timestamp = true
To override these values, change them on the command line.
    gam print users todrive tdparent root tdtimestamp false id name

4.33.00

Thanks to Jay, multithreading was changed to multiprocessing for gam batch and gam csv; this should increase performance.

4.32.01

Converted convertfooternl argument to converttextnl in gam print groups, it causes \n to be converted to \\n in customFooterText, defaultMessageDenyNotificationText and description,
otherwise \n is not changed in those fields.
    gam print groups [todrive [<ToDriveAttribute>]] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [maxresults <Number>] [delimiter <String>] [converttextnl] [countsonly]
        [members] [managers] [owners] [settings] <GroupFieldName>* [fields <GroupFieldNameList>]

4.32.00

Added member_max_results variable to gam.cfg. When retrieving lists of Google Group members from API, this variable controls how many should be retrieved in each chunk.
The default value is 200; larger numbers should speed up processing with groups with large numbers of members.

gam print groups has been rewritten to improve performance when members|owners|managers|settings are specified. Previously, the list of groups was retrieved with one API call,
then additional API calls were used per group to get the member and settings data; with N groups, there were 1, 1+N or 1+2N total API calls made based on the arguments given.
Now, the additional API calls are batched (based on batch_size in gam.cfg) to reduce the total number of calls; with N groups, there are 1 or 1+N/batch_size total API calls.
Even if batch_size is one, the members and settings API calls are combined.
Additionally, more checking has been added to handle the case where Google mis-reports that a group does not exist.

4.31.01

Fixed error when formatjson argument was used with gam info group/user.

4.31.00

The Email Settings API, used by versions of Gam prior to 4.18.00, would automatically create a label if a you added a filter that specified a label that didn't exist.
The Gmail API, used by versions of Gam from 4.18.00 on, does not automatically create the label, thus, you don't get the expected result.
This version of Gam creates the label for you to give the expected result.

4.30.09

Reference gam create project and gam check serviceaccount rather than https://github.com/jay0lee/GAM/wiki/CreatingClientSecretsFile.
Handle Google misreporting invalid group in gam print groups settings.

4.30.08

Do not get/set settings for special groups abuse and postmaster.

4.30.07

Handle additional API errors when dealing with groups.

4.30.06

Improve gam print groups settings performance.

4.30.05

Strip carriage returns from signature and vacation message.

4.30.04

Added html argument to gam add sendas/update sendas/signature to control newline (\n) processing when signature is read from a file.
    gam <UserTypeEntity> [add] sendas <EmailAddress> <Name> [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <Tag> <String>)*] [html] [replyto <EmailAddress>] [default] [treatasalias <Boolean>]
    gam <UserTypeEntity> update sendas <EmailAddress> [name <Name>] [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <Tag> <String>)*] [html] [replyto <EmailAddress>] [default] [treatasalias <Boolean>]
    gam <UserTypeEntity> signature|sig <String>|(file <FileName> [charset <Charset>]) (replace <Tag> <String>)* [html] [name <String>] [replyto <EmailAddress>] [default] [primary] [treatasalias <Boolean>]
When html is not specified, newlines are converted to <br/>; this allows simple, multi-line files to be interpreted properly by Google.
When html is specified, newlines are not converted to <br/>; this allows multi-line HTML files to be interpreted properly by Google, no extra blank lines will be included.

4.30.03

Improve Unicode handling when reading files.

4.30.02

Thanks to Jay for the following.
Added gam create project command which is used to create Client and Service Account IDs.
    gam create project [<EmailAddress>]

4.30.01

New columns have been added to CSV files generated by gam print commands; these columns show the number of instances of repeating items.
If a CSV row has the columns: item.0, item.1, ... or item.0.attr1, item.0.attr2, item.1.attr1, item.1.attr2 ...,
the new column will be item showing the number of instances. If a row has no instances of item, the column will be blank.

4.30.00

Thanks to Jay for the following.
Added command to delete calendar events by ID or query from a single calendar.
    gam calendar <CalendarItem> deleteevent (id|eventid <EventID>)* (q|query|eventquery <QueryCalendar>)* [doit] [notifyattendees]
The id argument may be repeated to specify multiple IDs.
A calendar query is a free text search of all of the words in <QueryCalendar>, it is an "and" query.
To perform an "or" query, enter multiple query arguments.
Example, delete all events with "Bob" and "Carol" or "Ted and Alice" in them.
    gam calendar testcal delete event query "Bob Carol" query "Ted Alice" doit
The doit argument is required to actually perform the deletions.

Added notifyattendees argument to gam calendar delete/move event.
    gam calendar <CalendarEntity> delete event <EventIDEntity> [notifyattendees]
    gam calendar <CalendarEntity> move event <EventIDEntity> to <CalendarItem> [notifyattendees]

Added support for newline characters in the unstructured field of a user's address.
$ gam update user testuser address type home unstructured "123 Main Street\nAnytown, CA 12345\nUSA" primary
User: testuser@domain.com, Updated (1/1)
$ gam info user testuser nogroups nolicenses name address
User: testuser@domain.com (1/1)
  Settings:
    First Name: Test
    Last Name: User
    Full Name: Test User
  Addresses:
    type: home
      sourceIsStructured: False
      formatted: 123 Main Street\nAnytown, CA 12345\nUSA

Added optional <EmailAddress> to gam oauth create; if not specified, you will be prompted to enter an email address.
This email address will be used to direct your browser to login at accounts.google.com with the specified address for scope authorization.
The intent is to help prevent using some other currently open session in your browser from doing the scope authorization.
    gam oauth|oauth2 create|request [<EmailAddress>]

Added command to verify Service Account scope authorization. For each Service Account used by GAM, a test is performed to verify that the
scope is authorized. Typically, this command would be executed for a single user.
    gam <UserTypeEntity> check serviceaccount

$ gam user testuser check serviceaccount
User: testuser@domain.com, Check 12 Scopes (1/1)
  Scope: https://mail.google.com/                                    , Checked: PASS (1/12)
  Scope: https://sites.google.com/feeds                              , Checked: PASS (2/12)
  Scope: https://www.google.com/m8/feeds                             , Checked: PASS (3/12)
  Scope: https://www.googleapis.com/auth/activity                    , Checked: PASS (4/12)
  Scope: https://www.googleapis.com/auth/calendar                    , Checked: PASS (5/12)
  Scope: https://www.googleapis.com/auth/drive                       , Checked: PASS (6/12)
  Scope: https://www.googleapis.com/auth/gmail.settings.basic        , Checked: PASS (7/12)
  Scope: https://www.googleapis.com/auth/gmail.settings.sharing      , Checked: PASS (8/12)
  Scope: https://www.googleapis.com/auth/plus.login                  , Checked: PASS (9/12)
  Scope: https://www.googleapis.com/auth/plus.me                     , Checked: PASS (10/12)
  Scope: https://www.googleapis.com/auth/userinfo.email              , Checked: PASS (11/12)
  Scope: https://www.googleapis.com/auth/userinfo.profile            , Checked: PASS (12/12)

All scopes passed!
Service Account Client name <Redacted>.apps.googleusercontent.com is fully authorized.

$ gam user testuser check serviceaccount
User: testuser@domain.com, Check 12 Scopes (1/1)
  Scope: https://mail.google.com/                                    , Checked: PASS (1/12)
  Scope: https://sites.google.com/feeds                              , Checked: FAIL (2/12)
  Scope: https://www.google.com/m8/feeds                             , Checked: PASS (3/12)
  Scope: https://www.googleapis.com/auth/activity                    , Checked: PASS (4/12)
  Scope: https://www.googleapis.com/auth/calendar                    , Checked: FAIL (5/12)
  Scope: https://www.googleapis.com/auth/drive                       , Checked: PASS (6/12)
  Scope: https://www.googleapis.com/auth/gmail.settings.basic        , Checked: PASS (7/12)
  Scope: https://www.googleapis.com/auth/gmail.settings.sharing      , Checked: PASS (8/12)
  Scope: https://www.googleapis.com/auth/plus.login                  , Checked: PASS (9/12)
  Scope: https://www.googleapis.com/auth/plus.me                     , Checked: PASS (10/12)
  Scope: https://www.googleapis.com/auth/userinfo.email              , Checked: PASS (11/12)
  Scope: https://www.googleapis.com/auth/userinfo.profile            , Checked: PASS (12/12)

ERROR: Some scopes failed! Please go to:

https://admin.google.com/domain.com/AdminHome?#OGX:ManageOauthClients

and grant Service Account Client name:

<Redacted>.apps.googleusercontent.com

Access to scopes:

https://mail.google.com/,
https://sites.google.com/feeds,
https://www.google.com/m8/feeds,
https://www.googleapis.com/auth/activity,
https://www.googleapis.com/auth/calendar,
https://www.googleapis.com/auth/drive,
https://www.googleapis.com/auth/gmail.settings.basic,
https://www.googleapis.com/auth/gmail.settings.sharing,
https://www.googleapis.com/auth/plus.login,
https://www.googleapis.com/auth/plus.me,
https://www.googleapis.com/auth/userinfo.email,
https://www.googleapis.com/auth/userinfo.profile

4.29.06

Added todrive_parent and todrive_timestamp variables to gam.cfg.
todrive_parent specifies the parent folder for CSV files when todrive is specified; can be id:<DriveFolderID> or <DriveFolderName>; default is root.
It must specify an existing Drive folder owned by the user named in oauth2.txt.
todrive_timestamp enables/disables adding a timestamp to the title of CSV files when todrive is specified; default is false.

Note!!! Syntax changed.
Anywhere you can specify todrive, there are additional subarguments following the todrive argument that let you direct the uploaded file to a particular location and add a timestamp to the file title.
    <ToDriveAttribute> ::=
        (tdparent id:<DriveFolderID>|<DriveFolderName>)|(tdtimestamp <Boolean> [tddaysoffset <Number>] [tdhoursoffset <Number])
The tdparent argument specifies the parent folder for the uploaded file; it must specify an existing Drive folder owned by the user named in oauth2.txt.
The tdtimestamp argument specifies whether a timestamp (of the time the file is uploaded to Google) will be added to the title of the uploaded file.
tdparent and tdtimestamp default to the values specified in gam.cfg.
The tddaysoffset and tdhoursoffset arguments let you specify values that subtract time from the timestamp, possibly as documentation to reflect the end of the time period that the uploaded report covers.
Example, generate a list of users, upload to the 'GAM Reports' folder, add a timestamp to the title.
    gam print users todrive tdparent 'GAM Reports' tdtimestamp true id name
To make these values be the default, add the following two lines to gam.cfg.
    todrive_parent = 'GAM Reports'
    todrive_timestamp = true
To override these values, change them on the command line.
    gam print users todrive tdparent root tdtimestamp false id name

4.29.05

Added simple argument to gam version for use by scripts.
      gam version [check] [simple]

4.29.04

Add ability to specify an alternate CSV field delimiter in redirect csv.
For redirect csv, the optional arguments must appear in the order shown.
    <Redirect> ::=
        redirect [csv <FileName> [append] [charset <Charset>] [delimiter <Character>] [stdout <FileName> [append]] [stderr <FileName> [append]]

4.29.03

Fixed bug in archive messages.

4.29.02

Allow empty values in user attribute fields.

Added todrive_conversion variable to gam.cfg. When a command specifies todrive, Gam attempts to convert the CSV file to a Google Sheet when uploading the file.
When todrive_conversion is False, no conversion will be performed.

4.29.01

Allow empty values in Contact fields. The blank value will be accepted and the entry will be cleared.

4.29.00

Note!!! oauth2.txt has been reorganized to circumvent a Google limitation and you must reauthorize your Client ID.
If you have customized the list of authorized scopes in a prior version, do 'gam oauth create' in that version, note the settings and then enter e to exit.
After installing this version, you must immediately perform a 'gam oauth create' and enter the settings noted above.
If you haven't customized the list of authorized scopes in a prior version, just do 'gam oauth create' in this version and proceed.
This version and prior versions can share the new oauth2.txt file.
After you've determined that you won't be using a prior version any longer, you can issue the following command to delete the authorizations for the previous version of gam.
    gam oauth delete previous

Added command to archive messages to a group.
    gam <UserTypeEntity> archive messages <GroupItem> (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_archive <Number>])|(ids <MessageIDEntity>)
To use this command you must add the following scope to the list of authorized scopes for your Client ID:
    https://www.googleapis.com/auth/apps.groups.migration

Thanks to Mattias Bystedt for the following enhancement.
Anywhere you can specify todrive, there are additional subarguments following the todrive argument that let you direct the uploaded file to a particular location and add a timestamp to the file title.
    <ToDriveAttribute> ::=
        (tdparentid <DriveFolderID>)|(tdparentname <DriveFolderName>)|(tdtimestamp [tddaysoffset <Number>] [tdhoursoffset <Number])
The tdparentid/tdparentname arguments specify the parent folder for the uploaded file; they must specify an existing Drive folder owned by the user named in oauth2.txt.
The tdtimestamp argument adds a timestamp (of the time the file is uploaded to Google) to the title of the uploaded file. The tddaysoffset and tdhoursoffset let you specify values that
subtract time from the timestamp, possibly as documentation to reflect the end of the time period that the uploaded report covers.
If these arguments are not specified, the functionaality is as before, the file is uploaded to your root folder with no tiemstamp added to the title.
Example, generate a list of users, upload to the 'GAM Reports' folder, add a timestamp to the title.
    gam print users todrive tdparentname 'GAM Reports' tdtimestamp id name

4.28.01

Correct initialization of scopes list in gam oauth create.

4.28.00

The internal processing of claim/transfer ownership, show filetree and print/show filelist with a select has been rewritten to improve performance.
Previously, the code used an order N-squared process to identify a folder and its descendents; this got unwieldly with large N, say 100000.
The new method uses an order 2N process; print/show filelist without a select is unchanged, it was an order N process.

Added showownedby argument to print/show filelist to allow specification of file ownership.
Added orphans option to select argument in print/show filelist to allow identifying those files that are not on a path from the root folder.
This often occurs with files/folders that are shared with you.
    gam <UserTypeEntity> print|show filelist [todrive] [anyowner|(showownedby any|me|others)] [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [select <DriveFileEntity>|orphans] [depth <Number>]
        [filepath] [allfields|<DriveFieldName>*] (orderby <DriveOrderByFieldName> [ascending|descending])*
By default, print/show filelist starts with a query of "'me' in owners".
If you specify query "xxx", "and xxx" is appended to the current query; you can repeat the query argument to build up a longer query.
If you specify fullquery "xxx", the query is set to "xxx" eliminating the initial "'me' in owners".
If you specify showownedby any or anyowner, all files accessible by the user are listed.
If you specify showownedby me, all files owned by the user are listed; this is the default.
If you specify showownedby others, only files not owned by the user are listed.
The depth <Number> argument controls whether files or folders within a selected folder are listed.
If <Number> equals -1 (the default), all files and folders in the selected folder and below are listed.
If <Number> is 0, files or folders within a selected folder are listed, no descendents are listed.
If <Number> is greater than 0, the files and folders within the selected folder and those files and folders <Number> levels below the selected folder are listed.

When the select argument is not used, the list of files that match the query are listed.
Example, list all files/folders owned by the user:
    gam user testuser print filelist
Example, list all files/folders owned by the user that begin with the word 'Test':
    gam user testuser print filelist query "title contains 'Test'"
Example, list all files/folders owned by any user that are starred and have been modified since a given date.
    gam user testuser print filelist full query "starred = true and modifiedDate >= '2016-10-15T00:00:00Z'"

The select argument specifies a starting point for output; all files that match the query and are descendents of the starting folder are listed.

Example, get a list of files/folders without a parent, owned by anyone, do not show their descendents:
    gam user testuser print filelist select orphans showownedby any depth 0
Example, get a list of files/folders and their descendents, owned by the user,  in the folder 'Top Folder' owned by the user:
    gam user testuser print filelist select drivefilename 'Top Folder' showownedby me

Added showownedby argument to show filetree to allow specification of file ownership.
Added orphans option to select argument to show filetree to allow identifying those files that are not on a path from the root folder.
This often occurs with files/folders that are shared with you.
    gam <UserTypeEntity> show filetree [anyowner|(showownedby any|me|others)] [select <DriveFileEntity>|orphans] [depth <Number>] (orderby <DriveOrderByFieldName> [ascending|descending])*
By default, show filetree displays all files owned by the user.
If you specify showownedby any or anyowner, all files accessible by the user are displayed.
If you specify showownedby me, all files owned by the user are displayed; this is the default.
If you specify showownedby others, all files not owned by the user are displayed.
The depth <Number> argument controls whether files or folders within a selected folder are displayed.
If <Number> equals -1 (the default), all files and folders in the selected folder and below are displayed.
If <Number> is 0, files or folders within a selected folder are displayed, no descendents are displayed.
If <Number> is greater than 0, the files and folders within the selected folder and those files and folders <Number> levels below the selected folder are displayed.

When the select argument is not used, the root folder is selected.
The select argument specifies an alternate starting point for output.
Example, display the tree of files/folders owned by the user:
    gam user testuser show filetree
Example, display the tree of files/folders owned by anyone to a depth of 2:
    gam user testuser show filetree showownedby any depth 2

Emample, display the tree of files/folders without a parent, owned by anyone, and their descendents:
    gam user testuser show filetree select orphans showownedby any
Example, display the tree of  files/folders, owned by the user, in a folder owned by another user:
    gam user testuser show filetree select anydrivefilename 'Other User Folder' showownedby me

Added preview, filepath and todrive arguments to claim/transfer ownership.
preview specifies that a CSV file showing the ownership changes be produced without actually performing the changes.
filepath is used with preview to show the file path for files.
    gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem> [includetrashed] (orderby <DriveOrderByFieldName> [ascending|descending])* [preview] [filepath] todrive]
    gam <UserTypeEntity> claim ownership <DriveFileEntity> [skipids <DriveFileEntity>] [skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>] [includetrashed] [writerscantshare] [preview] [filepath] todrive]
For transfer ownership, the headers of the CSV file are: OldOwner,NewOwner,type,id,title
For claim ownership, the headers of the CSV file are: NewOwner,OldOwner,type,id,title
If filepath is specified, a paths header is added that show the total number of paths to the file; a header path.<N> is added for each path.

4.27.04

Fixed gam print tokens to show clientId.

4.27.03

Handle newlines in CrOS notes field.

4.27.02

Added depth <Number> argument to show filetree
    gam <UserTypeEntity> show filetree [anyowner] [select <DriveFileEntity>] (orderby <DriveOrderByFieldName> [ascending|descending])* [depth <Number>]
If <Number> equals -1 (the default), all files and folders below the selected folder are listed. The root folder is selected by default.
If <Number> is 0, files or folders within a selected folder are listed.
If <Number> is greater than 0, the files and folders within the selected folder and those files and folders depth-1 levels below the selected folder are listed.

Added anydrivefilename argument to allow specification of drive file names for files you don't own but can access, i.e., files shared with you.
    <DriveFileIDEntity> ::= (<DriveFileItem>)|(id <DriveFileItem>)|(id:<DriveFileItem>)|(ids <DriveFileList>)|(ids:<DriveFileList>)
    <DriveFileNameEntity> ::= (drivefilename <DriveFileName>)|(drivefilename:<DriveFileName>)|(anydrivefilename <DriveFileName>)|(anydrivefilename:<DriveFileName>)
    <DriveFileQueryEntity> ::= (query <QueryDriveFile>)|(query:<QueryDriveFile>)
    <DriveFileEntity> ::= <DriveFileIDEntity>|<DriveFileNameEntity>|<DriveFileQueryEntity>|root|<FileSelector>|<ArgsSelector>|<CSVkmdSelector>|<CSVDataSelector>)

4.27.01

Cleaned up processing of guardian invitation cancellations.

4.27.00
Note!!! Functionality change.
Changed command gam show filetree to show only files owned by the user by default; this makes it consistent with gam show filelist.
To get the prior behavior, add the anyowner argument.
    gam <UserTypeEntity> show filetree [anyowner] [select <DriveFileEntity>] (orderby <DriveOrderByFieldName> [ascending|descending])*

Added a new method of selecting a list of users to <UserTypeEntity>.
    group_users <GroupList> [members] [managers] [owners] [primarydomain] [domains <DomainNameList>] [recursive] end
From the list of groups in <GroupList>, users with the specified roles are selected. If no roles are specified, all users are selected.
If recursive is specified, users within nested groups are included. If primarydomain or domains <DomainNameList> are specified, only users from those domains are selected.
The end argument terminates the group_users selection.
To verify the selection, do: gam group_users <GroupList> [members] [managers] [owners] [primarydomain] [domains <DomainNameList>] [recursive] print
Example: gam group_users sales,marketing members recursive primarydomain print
Example: gam info users group_users sales,marketing members recursive primarydomain nogroups nolicenses noaliases name ou

Added a new column to the CSV file produced by print|show driveactivity. Currently, there is a column labeled eventTimeMillis which gives the time of the event
in milliseconds since the start of the current epoch. The new column is eventTime which show eventTimeMillis in the format yyyy-mm-ddThh:mm:ssZ.

Added timezone variable to gam.cfg. Google provides most times in UTC, this variable can be used to convert those times to local time.
The possible values are: utc, local and +|-hh:mm. The default value is utc.
timezone = utc - Time values are not converted.
timezone = local - Time values are converted to local time.
timezone = +|-hh:mm - Time values are converted to the specified offset from UTC.

Added invitations argument to gam delete guardian so that only a pending invitation for a guardian is cancelled.
    gam delete guardian|guardians <GuardianItem> <StudentItem> [invitations]

Added a command to cancel guardian invitations by invitation ID.
    gam cancel guardianinvitation|guardianinvitations <GuardianInvitationID> <StudentItem>

Added arguments to gam update user to enable clearing entire schemas or schema fields.
    gam update user <UserItem> <UserAttribute>+ [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
See 4.23.03 for note about updating multi-valued schema fields.

Note!!! Functionality change.
Starting in Gam 4.18.00, gam signature and gam show signature were operating on the primary signature of a user, regardless of the user name passed on the command line.
Now, the commands work on the signature of the user specified on the command line. To get the previous behavior, user the primary argument.
    gam <UserTypeEntity> signature|sig <String>|(file <FileName> [charset <Charset>]) (replace <Tag> <String>)* [name <String>] [replyto <EmailAddress>] [default] [primary] [treatasalias <Boolean>]
    gam <UserTypeEntity> show signature|sig [format] [primary]

4.26.01

In order to use the gam info/print/show gal commands you must update your list of authorized scopes; you want to change the scope: https://www.google.com/m8/feeds/contacts to https://www.google.com/m8/feeds
for your OAuth2 Client and Service Accounts. (You are removing /contacts.)

4.26.00

Thanks to Jay for the following change.
Added arguments to gam update cros to perform device actions. See: https://developers.google.com/admin-sdk/directory/v1/reference/chromeosdevices/action
You can either update CrOS device attributes or perform a CrOS device action; if you specify both, only the device action will be performed.
    gam update cros <CrOSList> (<CrOSAttribute>+)|(action deprovision_same_model_replace|deprovision_different_model_replace|deprovision_retiring_device|disable|reenable [acknowledge_device_touch_requirement])
As a precatuion, none of the deprovisioning actions are performed unless you also specify the acknowledge_device_touch_requirement argument.

Implemented commands to show the global address list.
    gam <UserTypeEntity> info gal <ContactEntity> [basic|full] [fields <ContactFieldNameList>]
    gam <UserTypeEntity> show gal [query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
        [basic|full] [orderby <ContactOrderByFieldName> [ascending|descending]] [fields <ContactFieldNameList>]
    gam <UserTypeEntity> print gal [todrive] [query <QueryContact>] [emailmatchpattern <RegularExpression>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
        [basic|full] [orderby <ContactOrderByFieldName> [ascending|descending]] [fields <ContactFieldNameList>]

4.25.04

Improve performance of gam print filelist select.

4.25.03

Eliminated depth column in gam print filelist select. Changed depth to default to -1.

4.25.02

Use collections.deque() to reduce memory usage on some gam print operations.

4.25.01

Added convertfooternl argument to gam print groups, it causes \n to be converted to \\n in customFooterText, otherwise \n is not changed.
Added countsonly argument to gam print groups, it causes the number of members/owners/managers to be shown, not the list of email addresses.
    gam print groups [todrive] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [maxresults <Number>] [delimiter <String>] [convertfooternl] [countsonly]
        [members] [owners] [managers] [settings] <GroupFieldName>* [fields <GroupFieldNameList>]

4.25.00

Note!!! Syntax change.
Changed arguments to gam show filetree to allow selection of starting folder and specification of output ordering.
    gam <UserTypeEntity> show filetree [select <DriveFileEntity>] [orderby <DriveOrderByFieldName> [ascending|descending]]*
If select <DriveFileEntity> is omitted, the filetree output starts with the root folder.

Added select argument to print filelist to allow selection of a starting folder for the file list rather than the root folder.
Added anyowner argument to allowing listing of all files in users' drive rather than just those files owned by user.
    gam <UserTypeEntity> print|show filelist [anyowner] [todrive] ([query <QueryDriveFile>] [fullquery <QueryDriveFile>])|([select <DriveFileEntity>] [depth <Number>])
        [filepath] [allfields|<DriveFieldName>*] (orderby <DriveOrderByFieldName> [ascending|descending])*
If none of query, fullquery and select are specified, all of the users' files and folders starting at the root folder are listed.
If query or fullquery is specified, all of the users' files and folders matching the query are listed.
If select is specified, each file or folder selected by <DriveFileEntity> is listed.
The depth <Number> argument controls whether files or folders within a selected folder are listed when the select argument is specified.
If <Number> equals -1 (the default), all files and folders below the selected folder are listed.
If <Number> is 0, no files or folders within a selected folder are listed.
If <Number> is greater than 0, the files and folders within the selected folder and those files and folders depth-1 levels below the selected folder are listed.
When anyowner or fullquery are specified, the Owner column should be interpreted as the User column as some files shown may not owned by the user.

4.24.05

Update 4.24.04 was too complicated; if a drive file has no parents, it will have no paths; there is no need for "orphaned".
In gam print filelist, the headers will be "paths" with a value indicating the number of paths to the file; the paths have headers "path.0", "path.1", ...
If a file has no parents, "paths" will be 0 and there will be no values for "path.0", "path.1", ...

4.24.04

Whenever a file path is shown, there is also an indication as to whether the path is "orphaned", i.e., the file path does not start at the root of Drive.
In gam print filelist, for every header "path.#", there will also be a header "orphaned.#".

4.24.03

The commands gam show fileinfo/filepath and print filelist now show all file paths for a file or folder; previously, only one file path was shown.
The headers for gam print filelist have been changed. Previously, there was a header "path" with a value showing one possible path to a file.
Now, there is a header "paths" with a value indicating the number of paths to the file; the paths have headers "path.0", "path.1", ...
    gam <UserTypeEntity> show fileinfo <DriveFileEntity> [filepath] [allfields|<DriveFieldName>*]
    gam <UserTypeEntity> print|show filelist [todrive] [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [filepath] [allfields|<DriveFieldName>*] (orderby <DriveOrderByFieldName> [ascending|descending])*
    gam <UserTypeEntity> show filepath <DriveFileEntity>

4.24.02

Added formatjson argument to info group/groups to cause output to be in JSON format.
    gam info group <GroupItem> [nousers] [noaliases] [groups] <GroupFieldName>* [fields <GroupFieldNameList>] [formatjson]
    gam info groups <GroupEntity> [nousers] [noaliases] [groups] <GroupFieldName>* [fields <GroupFieldNameList>] [formatjson]

4.24.01

Added formatjson argument to info user/users to cause output to be in JSON format.
    gam info user <UserItem> [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas <SchemaNameList>] [userview] [fields <UserFieldNameList>] [products|product <ProductIDList>] [skus|sku <SKUIDList>] [formatjson]
    gam info users <UserTypeEntity> [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas <SchemaNameList>] [userview] [fields <UserFieldNameList>] [products|product <ProductIDList>] [skus|sku <SKUIDList>] [formatjson]

4.24.00

Gam forward and print/show forward now use Gmail API.

4.23.06

Handle multipart/mixed and multipart/related messages in print/show messages.

4.23.05

Handle carriage returns/linefeeds in message bodies.
In gam print messages/threads, convertbodynl causes \n to be converted to \\n, \r to be converted to \\r, otherwise \n and \r are not changed.
    gam <UserTypeEntity> print messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [headers <String>] [showlabels] [showbody] [convertbodynl] [showsize] [showsnippet] [todrive]

4.23.04

Added showbody argument to print/show messages/threads to allow display of plain message body.
    gam <UserTypeEntity> show messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [headers <String>] [showlabels] [showbody] [showsize] [showsnippet]
    gam <UserTypeEntity> print messages|threads (((query <QueryGmail>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>)
        [headers <String>] [showlabels] [showbody]  [showsize] [showsnippet] [todrive]

4.23.03

Added support for specifying type in multi-valued schemas. Custom schema fields can be single-valued or multi-valued;
Gam has always supported both but has not supported the type characteristic within a multi-valued schema field.
In gam create/update user, schema fields are now specified as:
    <SchemaName>.<FieldName> [multivalued [type work|home|other|(custom <CustomType>)]] <String>
Examples:
TestSchema.SVField <String> - value is <String>
TestSchema.MVField <String> - type is work (default), value is <String>
TestSchema.MVField type home <String> - type is home, value is <String>
TestSchema.MVField type custom <CustomType> <String> - type is custom, customType is <CustomType>, value is <String>
Compatibility note: In the unlikely case that you are currently setting a multi-valued schema field with the value "type",
i.e., TestSchema.MVField type, you will have to change this to TestSchema.MVField type work type.

If you have external programs that produce multi-column files of data, but witout headers, you have to add a
header row to the file before Gam can read the file as a CSV file. Now, you can use the file as is and specify the
headers in Gam. There are several places where the headers can be specified:
    croscsvfile <FileName>(:<FieldName>)+ [charset <Charset>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <String>]
    csvfile <FileName>(:<FieldName>)+ [charset <Charset>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* [delimiter <String>]
    csvkmd cros|users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>] [fields <FieldNameList>]
               keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
           (matchfield <FieldName> <RegularExpression>)*
           [datafield <FieldName>(:<FieldName)* [delimiter <String>]]
    <CSVkmdSelector> ::= csvkmd <FileName> [charset <Charset>] [fields <FieldNameList>]
                                keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
                                (matchfield <FieldName> <RegularExpression>)*
                                [datafield <FieldName>(:<FieldName)* [delimiter <String>]]
    gam csv <FileName>|- [charset <Charset>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>
    gam loop <FileName>|- [charset <Charset>] [fields <FieldNameList>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>

4.23.02

Use Directory API to update customer language.

4.23.01

Improve handling of inappropriate email addresses in GAPI Service calls.

4.23.00

Allow mapping of keyfield value in csvkmd selectors.
    <CSVkmdSelector> ::= csvkmd <FileName> [charset <Charset>]
        keyfield <FieldName> [keypattern <RegularExpression>] [keyvalue <String>] [delimiter <String>]
        (matchfield <FieldName> <RegularExpression>)*
        [datafield <FieldName>(:<FieldName)* [delimiter <String>]]

You want to update the membership of a collection of parent groups at your school, the data is coming from a database in a fixed format.
Example 1, CSV File GroupP1P2.csv, exactly the data you want, keypattern and keyvalue are not required
Group,P1Email,P2Email
2017-parents@domain.com,g1member11@domain.com,g1member12@domain.com
2017-parents@domain.com,g1member21@domain.com,g1member22@domain.com
2018-parents@domain.com,g2member11@domain.com,g2member11@domain.com
2018-parents@domain.com,g2member21@domain.com,g2member22@domain.com
...
For each row, the value from the Group column is used as the group name.
Verify data selection: gam list csvkmd GroupP1P2.csv keyfield Group datafield P1Email:P2Email data csvdata P1Email:P2Email
Execute: gam update groups csvkmd GroupP1P2.csv keyfield Group datafield P1Email:P2Email sync member csvdata P1Email:P2Email

Example 2, CSV File GradYearP1P2.csv, you have to convert GradYear to group name GradYear-parents@domain.com, keyvalue is required
GradYear,P1Email,P2Email
2017,g1member11@domain.com,g1member12@domain.com
2017,g1member21@domain.com,g1member22@domain.com
2018,g2member11@domain.com,g2member11@domain.com
2018,g2member21@domain.com,g2member22@domain.com
...
For each row, the value from the GradYear column replaces the keyField name in the keyvalue argument and that value is used as the group name.
Verify data selection: gam list csvkmd GradYearP1P2.csv keyfield GradYear keyvalue GradYear-parents@domain.com datafield P1Email:P2Email data csvdata P1Email:P2Email
Execute: gam update groups csvkmd GradYearP1P2.csv keyfield GradYear keyvalue GradYear-parents@domain.com datafield P1Email:P2Email sync member csvdata P1Email:P2Email

Example 3, CSV File GradYearP1P2.csv, you have to convert GradYear to group name 'LastTwoDigitsOfGradYear-parents@domain.com', keypattern and keyvalue are required.
GradYear,P1Email,P2Email
2017,g1member11@domain.com,g1member12@domain.com
2017,g1member21@domain.com,g1member22@domain.com
2018,g2member11@domain.com,g2member11@domain.com
2018,g2member21@domain.com,g2member22@domain.com
...
For each row, the value from the GradYear column is matched against the keypattern, the matched segments are substituted into the keyvalue argument and that value is used as the group name.
Verify data selection: gam list csvkmd GradYearP1P2.csv keyfield GradYear keypattern '20(..)' keyvalue '\1-parents@domain.com' datafield P1Email:P2Email data csvdata P1Email:P2Email
Execute: gam update groups csvkmd GradYearP1P2.csv keyfield GradYear keypattern '20(..)' keyvalue '\1-parents@domain.com' datafield P1Email:P2Email sync member csvdata P1Email:P2Email

4.22.03

Allow underscore as a valid character in site names. Thanks to Mattias Bystedt for reporting this.

4.22.02

Fix error in gam print group-members.

4.22.01

Handle cache_discovery_only when discovery is read from file.

4.22.00

Added cache_discovery_only variable to gam.cfg.
If no_cache = True, no GAM API calls are cached.
If no_cache = False and cache_discovery_only = False, all GAM API calls are cached.
If no_cache = False and cache_discovery_only = True, only GAM discovery API calls are cached.
The last combination caches GAM discovery API calls that usually return the same value
without consuming large amounts of disc space as when all GAM API calls are cached.

4.21.02

Retry Sites API calls on Internal Server Error

4.21.01

Added gam show sites command.
    gam [<UserTypeEntity>] show sites [domain|domains <DomainNameEntity>] [includeallsites] [withmappings] [role|roles all|<SiteACLRoleList>] [maxresults <Number>]

4.21.01

Expanded gam print sites to take a <DomandNameEntity> rather than just a <DomainName>. This allows printing site information for several domains with one command.
    gam [<UserTypeEntity>] print sites [todrive] [domain <DomainNameEntity>] [includeallsites] [withmappings] [roles all|<SiteACLRoleList>] [maxresults <Number>] [convertsummarynl]
Examples:
     gam print sites domain domain1.com,domain2.com
     gam redirect csv ./domains.csv print domains | gam print sites domain csvfile ./domains.csv:domainName

4.20.13

Fix uninitialized variable bug in doLoop.

4.20.12

Handle linefeeds in site summaries.
In gam print sites, convertsummarynl causes \n to be converted to \\n, otherwise \n is not changed.
In gam create/update sites, \\n is  converted to \n in summary <String>.
    gam [<UserTypeEntity>] print sites [todrive] [domain <DomainName>] [includeallsites] [withmappings] [roles all|<SiteACLRoleList>] [maxresults <Number>] [convertsummarynl]

4.20.11

Add includeallsites to gam print sites to expand list of sites printed for a user.
    gam [<UserTypeEntity>] print sites [todrive] [domain <DomainName>] [includeallsites] [withmappings] [roles all|<SiteACLRoleList>] [maxresults <Number>]

4.20.10

Handle incomplete author information in gam print siteactivity.

4.20.09

Added userfields to gam print group-members to allow output of additional user fields.
    gam print group-members|groups-members [todrive] ([domain <DomainName>] [member <UserItem>])|[group <GroupItem>]|[select <GroupEntity>]
        [membernames] <MembersFieldName>* [fields <MembersFieldNameList>] [userfields <UserFieldNameList>] [recursive [noduplicates]]

4.20.08

Expand gam calendar show events and add gam calendar print events.
    gam calendar <CalendarEntity> show events [alwaysincludeemail] [showdeleted] [showhiddeninvitations] [singleevents]
        [icaluid <String>] (privateextendedproperty <String>)* (sharedextendedproperty <String>)* [q|query <String>] [maxattendees <Number>]
        [starttime|timemin <Time>] [endtime|timemax <Time>] [updatedmin <Time>] [orderby starttime|updated]
    gam calendar <CalendarEntity> print events [todrive] [alwaysincludeemail] [showdeleted] [showhiddeninvitations] [singleevents]
        [icaluid <String>] (privateextendedproperty <String>)* (sharedextendedproperty <String>)* [q|query <String>] [maxattendees <Number>]
        [starttime|timemin <Time>] [endtime|timemax <Time>] [updatedmin <Time>] [orderby starttime|updated]

Handle untranslatable Unicode characters.

4.20.05

Implement command to claim Google Drive file ownership. Credit to Mattias Bystedt for the original code.
See: https://github.com/lerklompen/GAM/releases/tag/v3.66-writerscantshare
    gam <UserTypeEntity> claim ownership <DriveFileEntity> [skipids <DriveFileEntity>] [skipusers <UserTypeEntity>] [subdomains <DomainNameEntity>] [includetrashed] [writerscantshare]

4.20.04

Big fix.

4.20.03

Implement command to transfer Google Drive file ownership. Credit to Mattias Bystedt for the original code.
See: https://github.com/lerklompen/GAM/releases/tag/v3.66-writerscantshare
    gam <UserTypeEntity> transfer ownership <DriveFileEntity> <UserItem> [includetrashed] (orderby <DriveOrderByFieldName> [ascending|descending])*

4.20.02

Signatures and vacation messages were converting newlines to <br/> inappropriately, this has been corrected.

4.20.01

Selectors/commands that use the matchfield argument have been extended to allow multiple instances of matchfield.
To select a row from a CSV file, all matchfields must be present in the row and all <RegularExpression>s must match.
    <CrOSTypeEntity> ::=
                (croscsvfile <FileName>(:<FieldName>)+ [charset <Charset>] (matchfield <FieldName> <RegularExpression>)* [delimiter <String>])|
                (csvkmd cros <FileName> [charset <Charset>]
                        keyfield <FieldName> [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
    <UserTypeEntity> ::=
                (csvfile <FileName>(:<FieldName>)+ [charset <Charset>] (matchfield <FieldName> <RegularExpression>)* [delimiter <String>])|
                (csvkmd users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>]
                        keyfield <FieldName> [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
    <CSVkmdSelector> ::= csvkmd <FileName> [charset <Charset>] keyfield <FieldName> [delimiter <String>] (matchfield <FieldName> <RegularExpression>)* [datafield <FieldName>(:<FieldName)* [delimiter <String>]]

    gam csv <FileName>|- [charset <Charset>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>
    gam loop <FileName>|- [charset <Charset>] (matchfield <FieldName> <RegularExpression>)* gam <GAMArgumentList>

The csvkmd datafield <FieldName> argument has been expanded to datafield <FieldName>(:<FieldName>)*.
This allows you to gather data from several columns; the columns do not have to be contiguous.
    <FieldName>(:<FieldName>*) must be the same in csvkmd and csvcros/csvdata.
    <CrOSTypeEntity> ::=
                (csvkmd cros <FileName> [charset <Charset>]
                        keyfield <FieldName> [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
                (csvcros <FieldName>(:<FieldName>*))
    <UserTypeEntity> ::=
                (csvkmd users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>]
                        keyfield <FieldName> [delimiter <String>]
                        (matchfield <FieldName> <RegularExpression>)*
                        [datafield <FieldName>(:<FieldName)* [delimiter <String>]])|
                (csvdata <FieldName>(:<FieldName>*))
    <CSVkmdSelector> ::= csvkmd <FileName> [charset <Charset>] keyfield <FieldName> [delimiter <String>] (matchfield <FieldName> <RegularExpression>)* [datafield <FieldName>(:<FieldName)* [delimiter <String>]]

Given the file GroupFourUsers.csv:
Group,UserA,UserB,UserC,UserD
group1@bar.com,user1a@bar.com,user1b@bar.com,user1c@bar.com,user1d@bar.com
group2@bar.com,user2a@bar.com,user2b@bar.com,user2c@bar.com,user2d@bar.com
...
gam update groups csvkmd GroupFourUsers.csv keyfield Group datafield UserA:UserB:UserC:UserD sync members csvdata UserA:UserB:UserC:UserD

4.20.00

The data selector csvfile <FileName>:<FieldName> has been expanded to <FileName>(:<FieldName>)+.
This allows you to gather data from several columns; the columns do not have to be contiguous.

Given the file FourUsers.csv:
UserA,UserB,UserC,UserD
user1a@bar.com,user1b@bar.com,user1c@bar.com,user1d@bar.com
user2a@bar.com,user2b@bar.com,user2c@bar.com,user2d@bar.com
...
gam update group group@bar.com sync members csvfile FourUsers.csv:UserA:UserB:UserC:UserD

4.19.06

Expanded the options for parameter substitution in gam csv, RE pattern substitution is now available.
An argument containing instances of ~~xxx~!~pattern~!~replacement~~ has ~~...~~ replaced by re.sub(pattern, replacement, value of field xxx from the CSV file)
An argument containing instances of ~~xxx~~ has xxx replaced by the value of field xxx from the CSV file
An argument containing exactly ~xxx is replaced by the value of field xxx from the CSV file
For example, ~~primaryEmail~!~^(.+)@(.+)$~!~\1 AT \2~~ would replace foo@bar.com (from the primaryEmail column) with foo AT bar.com

4.19.05

Added products <ProductIDList> argument to gam info user <User> so that licenses for desired products can be shown.
You can specify products or skus but not both.
    gam info user [<UserItem>] [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas <SchemaNameList>] [userview] <UserFieldName>* [fields <UserFieldNameList>] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)]


4.19.04

When specifying a flat file or CSV file as the source of a list of items, you can specify a delimiter so that multiple values can be
obtained from a single row of a flat file or a single column of a CSV file.
file <FileName> [charset <CharSet>] [delimiter <String>]
csvfile <FileName>:<FieldName> [charset <CharSet>] [delimiter <String>]
Suppose you have a program that queries a database to get the email addresses for all families at your school; there is one file per grade,
one row per family and multiple email addresses per row separated by spaces. For example, here is SecondGrade.txt
momfamily1@domain.com dadfamily1@domain.com
momfamily2@domain.com dadfamily2@domain.com
momfamily3@domain.com
...
The specification: file SecondGrade.txt delimiter ' '
would produce the list:
momfamily1@domain.com
dadfamily1@domain.com
momfamily2@domain.com
dadfamily2@domain.com
momfamily3@domain.com
...

4.19.00

At Jay Lee's suggestion, gam update schema was updated to function in a manner expected by users.
The existing schema is read, any <SchemaFieldDefinitions> that have the same field name as an existing field will update that field.
Any <SchemaFieldDefinitions> that don't exist in the current schema will be added.
You can delete fields; it is an error to delete a field that doesn't exist.
It is an error to delete all of the fields in a schema; delete the schema if it is no longer required.
The previous model that required that the entire field list be supplied on an update still works.
    gam update schema <SchemaName> <SchemaFieldDefinition>* (deletefield <FieldName>)*
    gam update schemas <SchemaEntity> <SchemaFieldDefinition>* (deletefield <FieldName>)*

Thanks to Jay Lee, classroom student guardians are now supported.
    gam create guardian|guardianinvite|inviteguardian <EmailAddress> <UserItem>
    gam delete guardian|guardians <GuardianID <UserItem>
    gam show guardian|guardians [invitedguardian <GuardianID>] [student <UserItem>] [invitations] [states <GuardianStateList>] [<UserTypeEntity>]
    gam print guardian|guardians [todrive] [invitedguardian <GuardianID>] [student <UserItem>] [invitations] [states <GuardianStateList>] [<UserTypeEntity>]

4.18.08

Added removeexpiration <Boolean> argument to gam update drivefileacl to allow removal of ACL expiration date.
    gam <UserTypeEntity> update drivefileacl <DriveFileEntity> <PermissionID>
        (role <DriveFileACLRole>) [withlink|(allowfilediscovery <Boolean>)] [removeexpiration <Boolean>] [transferownership <Boolean>] [showtitles]

Changed the CSV file headers for gam print delegates.
Old: User, delegateName, delegateAddress, delegationStatus
New: Delegator, Delegate, Delegate Email, Delegate ID, Status

4.18.06

Added noshow argument to gam get photo to suppress displaying of photo data
    gam <UserTypeEntity> get photo [drivedir|(targetfolder <FilePath>)] [noshow]

4.18.05

The idfirst argument has been dropped from all print commands as its effect is now the default. Eliminate it from any scripts.

The command print is now a synonym for show for driveactivity, drivesettings, filelist.

The column headings for gam print org are now consistent regardless of what fields are chosen to display.
The headings are: Path, ID, Name, Description, Parent, ParentID, InheritanceBlocked

4.18.03

Added command to print Gmail Profiles to CSV file, dropped all arguments from gam show gmailprofile.
    gam <UserTypeEntity> print gmailprofile [todrive]
    gam <UserTypeEntity> show gmailprofile

Added command to print Goggle+ Profiles to CSV file, dropped all arguments from gam show gplusprofile.
    gam <UserTypeEntity> print gplusprofile [todrive]
    gam <UserTypeEntity> show gplusprofile

Added command to print user schemas to CSV file, renamed command to display formatted user schemas to gam show schemas.
    gam print schema|schemas [todrive]
    gam show schema|schemas

Added command to print user access tokens to CSV file.
    gam <UserTypeEntity> print tokens|token|3lo|oauth [todrive] [clientid <ClientID>]

Added command to move a Google drive file to the trash.
    gam <UserTypeEntity> trash drivefile <DriveFileEntity>
This is equivalent to: gam <UserTypeEntity> delete drivefile <DriveFileEntity> trash

Added command to remove a Google drive file from the trash.
    gam <UserTypeEntity> untrash drivefile <DriveFileEntity>
This is equivalent to: gam <UserTypeEntity> delete drivefile <DriveFileEntity> untrash

Added commands to process Gmail threads in the same manner as messages.
Added and, or arguments to message processing commands. These arguments allow you to combine queries and matchlabels; the default conjunction is and.
Added quick and notquick arguments to message processing commands.
By default, gam delete/modify/spam/trash/untrash messages fetches all matching messages from Google and then processes only max_to_process of them.
To speed up fetching, specify quick and only max_to_process of the matching messages will be fetched. You must still specify doit to perform the operation.
By default, gam print/show messages fetch only max_to_process matching messages from Google and then processes them.
To see how many messages actually match, specify notquick and all matching messages will be fetched; only max_to_process of them will be processed.

    gam <UserTypeEntity> delete messages|threads (((query <Query>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_delete|max_to_process <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> modify messages|threads (((query <Query>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_modify|max_to_process <Number>])|(ids <MessageIDEntity>) (addlabel <LabelName>)* (removelabel <LabelName>)*
    gam <UserTypeEntity> spam messages|threads (((query <Query>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_spam|max_to_process <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> trash messages|threads (((query <Query>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_trash|max_to_process <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> untrash messages|threads (((query <Query>) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_untrash|max_to_process <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> show messages|threads (((query <Query>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_show|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>) [headers <String>] [showlabels] [showsize] [showsnippet]
    gam <UserTypeEntity> print messages|threads (((query <Query>) (matchlabel <LabelName>) [or|and])* [quick|notquick] [max_to_print|max_to_process <Number>] [includespamtrash])|(ids <MessageIDEntity>) [headers <String>] [showlabels] [showsize] [showsnippet] [todrive]

All commands that process messages and threads now use the value of email_batch_size from gam.cfg to create batches to speed up processing.

Added select argument to gam print cros to allow selection of source of ChromeOS devices.
Add optional <UserTypeEntity> to gam print users and <CroSTypeEntity> to gam print cros.
    gam [<CrOSTypeEntity>] print cros [todrive] [query <QueryCrOS>]|[select <CrOSTypeEntity>]
        [orderby <CrOSOrderByFieldName> [ascending|descending]] [nolists] [listlimit <Number>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]
    gam [<UserTypeEntity>] print users [todrive] ([domain <DomainName>] [query <QueryUser>] [deleted_only|only_deleted])|[select <UserTypeEntity>]
        [delimiter <String>] [groups] [license|licenses|licence|licences] [emailpart|emailparts|username]
        [orderby <UserOrderByFieldName> [ascending|descending]] [userview]
        [basic|full|allfields | <UserFieldName>* | fields <UserFieldNameList>]

Added arguments to gam info cros to allow specification of desired output fields.
    gam info cros <CrosDeviceEntity> [nolists] [listlimit <Number>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]
    gam info croses <CrOSEntity> [nolists] [listlimit <Number>]
        [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>]

Added drivedir and targetfolder <FilePath> arguments to gam printjob fetch and gam get photo to
allow specification of the destination folder for the file retrieved from Google. The default
location for these commands is the current working directory, drivedir specifies the value of drive_dir from gam.cfg and
targetfolder <FilePath> specifies a user-chosen path.
    gam printjob|printjobs <PrinterID>|any fetch
        [olderthan|newerthan <PrintJobAge>] [query <QueryPrintJob>]
        [status <PrintJobStatus>]
        [orderby <PrintJobOrderByFieldName> [ascending|descending]]
        [owner|user <EmailAddress>]
        [limit <Number>] [drivedir|(targetfolder <FilePath>)]
    gam <UserTypeEntity> get photo [drivedir|(targetfolder <FilePath>)]

4.18.02

Set exit/return code when no items are found to process in a command.
For example, if you want to test for the existance of a Google drive folder:
gam <UserTypeEntity> show fileinfo drivefilename 'Top Folder' and mimeType ='application/vnd.google-apps.folder'" id
The exit/return code is 0 if the folder exists, 60 if it doesn't.

4.18.01

Added variable email_batch_size to gam.cfg, the default is 100 and the range is 1 to 100.
gam print/show messages/threads use this variable to batch retrieval of items from Gmail; it speeds up processing by a factor of ten.

4.18.0

Improve Gmail filter processing.
    gam <UserTypeEntity> [add] filter [from <EmailAddress>] [to <EmailAddress>] [subject <String>] [haswords|query <List>] [nowords|negatedquery <List>] [musthaveattachment|hasattachment] [excludechats] [size larger|smaller <ByteCount>]
        [label <LabelID>] [important|notimportant] [star] [trash] [markread] [archive] [neverspam] [forward <EmailAddress>]
    gam <UserTypeEntity> delete filters <FilterIDEntity>
    gam <UserTypeEntity> show filters
    gam <UserTypeEntity> info filters <FilterIDEntity>
    gam <UserTypeEntity> print filters [todrive]

Add commands to process Gmail forwarding addresses.
    gam <UserTypeEntity> add forwardingaddress|forwardingaddresses <EmailAddressEntity>
    gam <UserTypeEntity> delete forwardingaddress|forwardingaddresses <EmailAddressEntity>
    gam <UserTypeEntity> show forwardingaddress|forwardingaddresses
    gam <UserTypeEntity> info forwardingaddress|forwardingaddresses <EmailAddressEntity>
    gam <UserTypeEntity> print forwardingaddress|forwardingaddresses [todrive]

Improve Gmail forward processing.
    gam <UserTypeEntity> forward <FalseValues>
    gam <UserTypeEntity> forward <TrueValues> keep|leaveininbox|archive|delete|trash|markread <EmailAddress>
    gam <UserTypeEntity> show forward
    gam <UserTypeEntity> print forward [todrive]

Improve Gmail sendas processing.
    gam <UserTypeEntity> [add] sendas <EmailAddress> <Name> [replyto <EmailAddress>] [default] [treatasalias <Boolean>] [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <REPattern> <String>)*]
    gam <UserTypeEntity> update sendas <EmailAddress> [name <Name>] [replyto <EmailAddress>] [default] [treatasalias <Boolean>] [signature|sig <String>|(file <FileName> [charset <CharSet>]) (replace <REPattern> <String>)*]
    gam <UserTypeEntity> delete sendas <EmailAddressEntity>
    gam <UserTypeEntity> show sendas [format]
    gam <UserTypeEntity> info sendas <EmailAddressEntity> [format]
    gam <UserTypeEntity> print sendas [todrive]

Improve Gmail signature processing.
    gam <UserTypeEntity> signature|sig <String>|(file <FileName> [charset <Charset>]) (replace <Tag> <String>)* [name <String>] [replyto <EmailAddress>]
    gam <UserTypeEntity> show signature|sig [format]

Use Gmail API for POP/IMAP/Vacation processing.
    gam <UserTypeEntity> imap|imap4 <Boolean> [noautoexpunge] [expungebehavior archive|deleteforever|trash] [maxfoldersize 0|1000|2000|5000|10000]
    gam <UserTypeEntity> pop|pop3 <Boolean> [for allmail|newmail|mailfromnowon|fromnowown] [action keep|leaveininbox|archive|delete|trash|markread]
    gam <UserTypeEntity> vacation <FalseValues>
    gam <UserTypeEntity> vacation <TrueValues> subject <String> (message <String>)|(file <FileName> [charset <CharSet>]) (replace <Tag> <String>)* [html]
        [contactsonly] [domainonly] [startdate <Date>] [enddate <Date>]
    gam <UserTypeEntity> show vacation [format]

The output of the command gam [<UserTypeEntity>] print contacts has been modified.
The first three column headings are User|Domain, ContactID, Name; the remaining column headings are sorted.
The column names for address, email, externalid, event, im, jot, organization, phone, relation, userdefinedfield and website have changed.
Using email as an example, if a user has two work email addresses and a home email address, the columns/values would have been:
Home Email,Home Email Primary,Work Email,Work Email Primary,Work Email 2,Work Email 2 Primary
home@domain.com,false,work1@domain.com,true,work2@domain.com,false
The new column headings are:
Emails.0.count,Emails.1.address,Emails.1.rank,Emails.1.type,Emails.2.address,Emails.2.rank,Emails.2.type,Emails.3.address,Emails.3.rank,Emails.3.type
3,home@domain.com,notprimary,home,work1@domain.com,primary,work,work2@domain.com,notprimary,work

The new headings should make processing the CSV file easier and allows gam csv to directly use the data from the CSV file.

Added command gam show contacts, it performs optional queries or shows all contacts.
    gam show contacts [query <Query>] [updated_min yyyy-mm-dd]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]])
    gam <UserTypeEntity> show contacts [query <Query>] [contactgroup <ContactGroupItem>] [updated_min yyyy-mm-dd]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]

Modified command gam info contacts to operate only on contacts identified by their IDs.
    gam info contacts <ContactEntity> [basic|full] [showgroups]
    gam <UserTypeEntity> info contacts <ContactEntity> [basic|full] [showgroups]
If you have scripts that use the query or contactgroups arguments with gam info contacts, change info to show.

Added showgroups argument to gam info/print/show contacts to display output of contact group information.

Added emailmatchpattern <REPattern> and [emailmatchtype work|home|other|<String>] arguments to gam delete/print/show contacts
to allow matching on contact email addresses. emailmatchtype is only used when emailmatchpattern is specified.
Added fields argument to gam info/print/show contacts to allow selection of fields to display.
    gam delete contacts <ContactEntity>|([query <Query>] [emailmatchpattern <REPattern>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
    gam info contacts <ContactEntity> [basic|full] [showgroups] [fields <ContactFieldNameList>]
    gam show contacts [query <Query>] [emailmatchpattern <REPattern>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]] [fields <ContactFieldNameList>]
    gam print contacts [todrive] [query <Query>] [emailmatchpattern <REPattern>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]] [fields <ContactFieldNameList>]

    gam <UserTypeEntity> delete contacts <ContactEntity>|([query <Query>] [contactgroup <ContactGroupItem>] [emailmatchpattern <REPattern>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
    gam <UserTypeEntity> info contacts <ContactEntity> [basic|full] [showgroups] [fields <ContactFieldNameList>]
    gam <UserTypeEntity> show contacts [query <Query>] [contactgroup <ContactGroupItem>] [emailmatchpattern <REPattern>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]] [fields <ContactFieldNameList>]
    gam <UserTypeEntity> print contacts [todrive] [query <Query>] [contactgroup <ContactGroupItem>] [emailmatchpattern <REPattern>] [emailmatchtype work|home|other|<String>] [updated_min yyyy-mm-dd]
        [basic|full] [showgroups] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]] [fields <ContactFieldNameList>]

Added command to show all of a user's contact groups.
    gam <UserTypeEntity> show contactgroups [updated_min yyyy-mm-dd]
        [basic|full] [showdeleted] [orderby <ContactOrderByFieldName> [ascending|descending]]

Added command to print calendars to CSV file, dropped all arguments from gam show calendars.
    gam <UserTypeEntity> print calendars [todrive]
    gam <UserTypeEntity> show calendars

4.17.B

Add alternative command to add delegates and command to print delegates.
    gam <UserTypeEntity> add delegate|delegates <UserEntity>
    gam <UserTypeEntity> print delegates [todrive]

4.17.7

Added Message-Id to default list of message headers in print/show messages.
Added showsize argument to gam print/show messages to have message size output/

4.17.1

Handle errors when contact commands are applied to aliases.

4.17.0

Added commands to print messages/threads.
    gam <UserTypeEntity> print message|messages (query <Query> (matchlabel <LabelName>)* [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>) [headers <String>] [showlabels] [todrive]
    gam <UserTypeEntity> print thread|threads (query <Query> (matchlabel <LabelName>)* [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>) [headers <String>] [showlabels] [todrive]

Added command to empty drive drive trash.
    gam <UserTypeEntity> empty drivetrash

4.16.6

Credit to Steve Main for suggesting the following enhancement.
Added argument to gam <UserTypeEntity> signature and gam <UserTypeEntity> vacation to allow pattern substitution in the signature and vacation message.
    gam <UserTypeEntity> signature <String>|(file <FileName> [charset <Charset>]) (replace <Tag> <String>)*
    gam <UserTypeEntity> vacation <TrueValues> subject <String> (message <String>)|(file <FileName> [charset <CharSet>]) [contactsonly] [domainonly]
        [startdate <Date>] [enddate <Date>] (replace <Tag> <String>)*
Every instance of {Tag} in the signature/message will be replaced by <String>. Instances of the form {RT}...{Tag}...{/RT} will be eliminated
if there was no <Tag> specified that matches Tag or if a <Tag> matching Tag was specified but the matching <String> is empty.
This is especially useful with CSV files.
gam csv Users.csv gam user '~User' signature file SignatureTemplate.txt replace 'User' '~User' replace 'Title' '~Title'

4.16.5

Added argument to gam xxx messages/threads to allow id lists to be specified. In this case doit and max_to_xxx are not required.
    gam <UserTypeEntity> delete message|messages (query <Query> (matchlabel <LabelName>)* [doit] [max_to_delete <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> modify message|messages (query <Query> (matchlabel <LabelName>)* [doit] [max_to_modify <Number>])|(ids <MessageIDEntity>) (addlabel <LabelName>)* (removelabel <LabelName>)*
    gam <UserTypeEntity> spam message|messages (query <Query> (matchlabel <LabelName>)* [doit] [max_to_spam <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> trash message|messages (query <Query> (matchlabel <LabelName>)* [doit] [max_to_trash <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> untrash message|messages (query <Query> (matchlabel <LabelName>)* [doit] [max_to_untrash <Number>])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> show message|messages (query <Query> (matchlabel <LabelName>)* [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)
    gam <UserTypeEntity> show thread|threads (query <Query> (matchlabel <LabelName>)* [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>)

4.16.4

Added commands to show messages/threads.
    gam <UserTypeEntity> show message|messages (query <Query> (matchlabel <LabelName>)* [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>) [headers <String>] [showlabels]
    gam <UserTypeEntity> show thread|threads (query <Query> (matchlabel <LabelName>)* [max_to_show <Number>] [includespamtrash])|(ids <MessageIDEntity>) [headers <String>] [showlabels]

4.16.0

Implement user Contact Groups: see GamContacts.txt

Implement Sites: see GamSites.txt

The output of the command gam print contacts has been modified; the column heading User has been changed to Domain.
The output of the command gam <UserTypeEntity> print contacts has not changed.

4.15.0

Added domain <DomainName> and member <UserItem> arguments to gam print group-members to allow selecting subsets of groups.
    gam print group-members|groups-members [todrive] ([domain <DomainName>] [member <UserItem>])|[group <GroupItem>]|[select <GroupEntity>] [membernames] [fields <MembersFieldNameList>] [recursive [noduplicates]]
These new arguments are the same as for gam print groups.

Add arguments to gam show fileinfo to allow field selection.
    gam <UserTypeEntity> show fileinfo <DriveFileEntity> [filepath] [allfields|<DriveFieldNames>*]

Allow selection of CrOS devices by Organizational Unit.
    gam cros_ous <OrgUnitList> ...
    gam cros_ous_and_children <OrgUnitList> ..
The first form selects only the CrOS devices directly in the Org Units; the second form selects CrOS devices from the Org Units and all child Org Units.
Google does not support this selection directly in the API; gam has to download all CrOS devices and then perform the selection locally;
this could be time consumimg with very largs lists of CrOS devices.

Any place you can specify a Google Drive folder id, you can enter root to select the root folder.
    gam <UserTypeEntity> show fileinfo root

Add arguments to gam show filetree to allow selection of starting folder and specification of output ordering.
    gam <UserTypeEntity> show filetree [<DriveFileEntity>] [orderby <DriveOrderByFieldName> [ascending|descending]]*
If <DriveFileEntity> is omitted, the filetree output starts with the root folder.

Add fullquery argument to gam print|show filelist to allow arbitrary queries. The query <Query> argument always includes "'me' in owners" which limits the scope.
Add filepath argument to gam print|show filelist to show the file path of Google Drive files.
Add arguments to gam print|show filelist to allow specification of output ordering.
Getting the file path for many files is expensive, use sparingly.
    gam <UserTypeEntity> print|show filelist [todrive] [query <QueryDriveFile>] [fullquery <QueryDriveFile>] [filepath] [allfields|<DriveFieldName>*] (orderby <DriveOrderByFieldName> [ascending|descending])*

Processing of the arguments orderby <DriveOrderByFieldName> and ascending|descending has been slightly restricted. Previously, these areguments
could appear in any order and they could be separated by other arguments; now, they must appear as: orderby <OrderByFieldName> [ascending|descending]
gam show filelist/filetree allow specification of multiple orderby fields; all other commands allow specification of a single orderby field.

The commands gam get drivefile, gam copy drivefile and gam update drivefile have been slightly restricted. Previously, these commands
allowed the <DriveFileEntity> to be specified anywhere in the list of arguments; now, <DriveFileEntity> must appear as the first argument after
the argument drivefile. This makes these commands consistent with gam delete drivefile and gam undelete drivefile.

Earlier updates

Added revision argument to gam <UserTypeEntity> get drivefile to allow downloading specific version of a file.
    gam <UserTypeEntity> get drivefile <DriveFileEntity> [format <FileFormatList>] [targetfolder <FilePath>] [revision <Number>]
Submitted by Seth Stein

Added command to show revisions of a file.
    gam <UserTypeEntity> show filerevisions <DriveFileEntity>
Submitted by Seth Stein

Warning messages are now written to stderr.
To capture all stdout and stderr ouput from a command in a single file, do: gam command > file 2>&1

Update gam <UserTypeEntity> delete groups to allow specification of a list of groups from which the users are to be deleted.
    gam <UserTypeEntity> delete|del group|groups [<GroupEntity>]

Add command to allow adding users to multiple groups.
    gam <UserTypeEntity> add group|groups [owner|manager|member] <GroupEntity>

Added skus <SKUIDList> argument to gam info user <User> so that licenses for desired SKUs can be shown.
    gam info user [<UserItem>] [noaliases] [nogroups] [nolicenses] [noschemas] [schemas <SchemaNameList>] [userview] [fields <UserFieldNamesList>] [skus|sku <SKUIDList>]

Removed language, name, admin_secondary_email, mx_verify, user_migrations, outbound_gateway, email_route from gam update instance
language, name and admin_secondary_email are present in gam update customer
    gam update customer [primary <DomainName>] [adminsecondaryemail|alternateemail <EmailAddress>] [language <LanguageCode] [phone|phonenumber <String>]
        [contact|contactname <String>] [name|organizationname <String>]
        [address1|addressline1 <String>]  [address2|addressline2 <String>]  [address3|addressline3 <String>]
        [locality <String>] [region <String>] [postalcode <String>] [country|countrycode <String>]

Add membernames argument to gam print group-members to include member name (in addition to member email) in output. Add fields argument to allow full specification of fields.
    gam print group-members|groups-members [todrive] [membernames] [fields <MembersFieldNameList>] [recursive [noduplicates]] [group <GroupItem>]|[select <GroupEntity>]

Add select argument to gam print users to allow selection of source of users.
    gam print users [todrive] ([domain <DomainName>] [query <Query>] [deleted_only|only_deleted])|[select <UserTypeEntity>]
        [delimiter <String>] [groups] [license|licenses] [emailpart|emailparts|username]
        [orderby familyname|lastname|givenname|firstname|email] [ascending|descending] [userview]
        [allfields | <UserFieldNames>* | fields <UserFieldNamesList>]

Add select argument to gam print groups/group-members to allow selection of groups.
    gam print groups [todrive] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [maxresults <Number>] [delimiter <String>]
        [members] [owners] [managers] <GroupFieldNames>* [settings] [fields <GroupFieldNamesList>|<GroupSettingsFieldNamesList>]
    gam print group-members|groups-members [todrive] [recursive [noduplicates]] [group <GroupItem>]|[select <GroupEntity>]

Add select argument to gam report to allow selection of users. Add maxresults and nodatechange arguments.
    gam report users|user [todrive] [nodatechange] [maxresults <Number>]
        [date <Date>] [(user all|<UserItem>)|(select <UserTypeEntity>)] [filter|filters <String>] [fields|parameters <String>]
    gam report customers|customer|domain [todrive] [nodatechange]
        [date <Date>] [fields|parameters <String>]
    gam report admin|calendar|calendars|drive|docs|doc|groups|group|logins|login|mobile|tokens|token [todrive] [maxresults <Number>]
        [start <Time>] [end <Time>] [(user all|<UserItem>)|(select <UserTypeEntity>)] [event <String>] [filter|filters <String>] [ip <String>]
If nodatechange is specified, <Date> will not be moved back to the last acceptable date.
The maxResults argument, range 1-1000,  controls how many results are obtained in each packet from Google; it does not limit the total number of results.

Added charset argument to gam signature/vacation to allow specification of character set of file argument.
    gam <UserTypeEntity> signature|sig <String>|(file <FileName> [charset <Charset>]
    gam <UserTypeEntity> vacation <Boolean> [subject <String>] [message <String>]|[file <FileName> [charset <Charset>]] [contactsonly] [domainonly] [startdate <Date>] [enddate <Date>]

Added clear option to reminder and notification arguments of add/update calendar
    reminder clear|(email|sms|pop <Number>)
    notification clear|(email|sms eventcreation|eventchange|eventcancellation|eventresponse|agenda)

Jay added command to modify message labels.
    gam <UserTypeEntity> modify message|messages query <Query> (addlabel <LabelName>)* (removelabel <LabelName>)* [doit] [max_to_modify <Number>]

Added matchlabel argument to gam delete/modify/spam/trash/untrash messages as an additional way of selecting messages.
    gam <UserTypeEntity> delete message|messages query <Query> (matchlabel <LabelName>)* [doit] [max_to_delete <Number>]
    gam <UserTypeEntity> modify message|messages query <Query> (matchlabel <LabelName>)* (addlabel <LabelName>)* (removelabel <LabelName>)* [doit] [max_to_modify <Number>]
    gam <UserTypeEntity> spam message|messages query <Query> (matchlabel <LabelName>)* [doit] [max_to_modify <Number>]
    gam <UserTypeEntity> trash message|messages query <Query> (matchlabel <LabelName>)* [doit] [max_to_trash <Number>]
    gam <UserTypeEntity> untrash message|messages query <Query> (matchlabel <LabelName>)* [doit] [max_to_untrash <Number>]
A message must have all of the specified matchlabels to be selected.

Add fields argument to gam info user to allow selection of fields.
    gam info user [<User>] [noaliases] [nogroups] [nolicenses] [noschemas] [schemas <SchemaNameList>] [userview] [fields <UserFieldNamesList>]

Add fields argument to gam print users to allow expanded selection of fields.
    gam print users [todrive] ([domain <DomainName>] [query <Query>] [deleted_only|only_deleted])|[select <UserTypeEntity>]
        [delimiter <String>] [groups] [license|licenses] [emailpart|emailparts|username]
        [orderby familyname|lastname|givenname|firstname|email] [ascending|descending] [userview]
        [allfields | <UserFieldNames>* | fields <UserFieldNamesList>]

Add fields argument to gam info group to allow selection of fields.
    gam info group <Group> [nousers] [noaliases] [groups] [fields <GroupFieldNamesList>|<GroupSettingsFieldNamesList>]

Add fields argument to gam print groups to allow expanded selection of fields.
    gam print groups [todrive] ([domain <DomainName>] [member <UserItem>])|[select <GroupEntity>]
        [maxresults <Number>] [delimiter <String>]
        [members] [owners] [managers] <GroupFieldNames>* [settings] [fields <GroupFieldNamesList>|<GroupSettingsFieldNamesList>]

Add fields argument to gam info cros to allow selection of fields.
    gam info cros <CrOSDeviceID> [fields <CrOSFieldNamesList>]

Add fields argument to gam print cros to allow selection of fields.
    gam print cros [todrive] [query <Query>] [basic|full] [nolists|recentusers|timeranges] [listlimit <Number>]
        [orderby lastsync|location|notes|serialnumber|status|supportenddate|user] [ascending|descending] [fields <CrOSFieldNamesList>]

Add show argument to gam print course-participants to select what members to display; the default is all.
    gam print course-participants ... [show all|students|teachers]

Add untrash argument to gam delete drivefile to remove file from trash.
    gam <UserTypeEntity> delete drivefile <DriveFileEntity> [purge|untrash]

Add arguments to gam info group to suppress aliases listing and include groups of which this group is a member.
    gam info group <Group> ... [noaliases] [groups]

Add listlimit argument to gam print cros to limit number of timeranges and recentusers entries
    gam print cros ... [listlimit <Number>]

Added command to untrash messages
    gam <UserTypeEntity> untrash messages query <Query> [doit] [max_to_untrash <Number>]

Add a command to show the file path of a Google Drive file.
    gam <UserTypeEntity> show filepath <DriveFileEntity>

Add filepath argument to gam show fileinfo to show the file path of a Google Drive file.
    gam <UserTypeEntity> show fileinfo <DriveFileEntity> [filepath] [allfields|<DriveFieldName>*]

Modify gam update group <GroupItem> add/sync to allow suspended users to be excluded from being added to the group.
    gam update group <GroupItem> add [owner|manager|member] [notsuspended] <UserTypeEntity>
    gam update group <GroupItem> sync [owner|manager|member] [notsuspended] <UserTypeEntity>
This option is effective for the following values of <UserTypeEntity>:
    all users | ou|org <OrgUnitPath | ou_and_children|ou_and_child <OrgUnitPath> | query <Query>

Modify gam course <CourseID> add/sync to disallow suspended users from being added to the course.
    gam course <CourseID> add teachers|students <UserTypeEntity>
    gam course <CourseID> sync teachers|students <UserTypeEntity>
This option is effective for the following values of <UserTypeEntity>:
    all users | ou|org <OrgUnitPath | ou_and_children|ou_and_child <OrgUnitPath> | query <Query>

Modify gam <UserTypeEntity> show calendars command to allow output to CSV file.
    gam <UserTypeEntity> show calendars [csv] [todrive]

Implement Pull request #10 to allow copying of Drive folders
    gam <UserTypeEntity> copy drivefile <DriveFileEntity> [newfilename <DriveFileName>] [recursive] [parentid <DriveFolderID>] [parentname <FolderName>]

Implement a command for redirecting stdout, stderr and CSV files.
    gam [redirect csv {{Section}}|<FileName> [append] [charset <CharSet>]] [redirect stdout {{Section}}|<FileName> [append]] [rerirect stderr {{Section}}|<FileName> [append]] ...
The redirect arguments must appear before any other gam arguments.
If <FileName> is relative, it will be stored in ~/Downloads.

Add recursive argument to gam print group-members to show users from sub-groups rather than the sub-group name itself.
Two new columns indicate the sub-group that a user comes from and the depth of the sub-group.
The noduplicates argument ensures that a user only appears once in the list.

Process a csv file without subprocesses. The syntax is exactly the same as gam csv, but, rather than starting
a subprocess for each line, gam executes the command directly. There is no subprocess creation overhead, cleaner output,
but it will not execute as fast on large csv files as there is no parallelism.
    gam loop <Filename>|- gam ...

Improve support for languages with accented characters.
The following commands have been extended to allow specification of the character set used in the file.
    gam batch <Filename>|- [charset <Charset>]
    gam csv <Filename>|- [charset <Charset>] gam ...
    gam loop <Filename>|- [charset <Charset>] gam ...
<Charset> defaults to ascii; other typical values are: utf-8, utf-16, latin-1.

Extend gam csv/loop to select rows from a csv file by matching a field value.
    gam csv <Filename>|- [charset <Charset>] [matchfield <FieldName> <RegularExpression>] gam ...
    gam loop <Filename>|- [charset <Charset>] [matchfield <FieldName> <RegularExpression>] gam ...
<FieldName> does not have a leading ~ and must be a column heading in <FileName>.
For documentation on <RegularExpression> see https://docs.python.org/2/library/re.html
    gam csv DeptGroups.csv matchfield Department Sales gam print group-members group ~Group
DeptGroups.csv:
Department,Group
Sales,sales-ny@bar.com
Sales,sales-nj@bar.com
Marketing,mktg-ny@bar.com
Marketing,mktg-nj@bar.com

Add a command to support updating a list of ChromeOS devices.
Currently:
    gam update cros <DeviceID>|query:<Query> <CrOSAttribute>
    gam all cros update <CrOSAttribute>
Proposed:
    gam cros <DeviceIDList> update <CrOSAttribute>

Implement pull request #93 to be able to mark messages as spam.
    gam <UserTypeEntity> spam message|messages query <Query> [doit] [max_to_move <Number>]
<Number> defaults to 1.

Support user calendar creation/modification/deletion/information.
    <CalendarSettings> ::==
        (summary <String>)|(description <String>)|(location <String>)|(timezone <TimeZone>)
    gam <UserTypeEntity> create calendar|calendars <CalendarSettings>
    gam <UserTypeEntity> modify calendar <CalendarItem>|primary <CalendarSettings>
    gam <UserTypeEntity> remove calendar <CalendarItem>
    gam <UserTypeEntity> modify calendars <CalendarEntity>|primary <CalendarSettings>
    gam <UserTypeEntity> remove calendars <CalendarEntity>
    gam <UserTypeEntity> info calendars <CalendarEntity>|primary
Summary <string> is required when creating a calendar.
primary refers to the user's primary calendar, it is replaced with the user's email address.

The format argument in gam get drivefile is extended to offer more choices of file types and can be a list.
The possible formats are: csv|html|txt|tsv|jpeg|jpg|png|svg|pdf|rtf|pptx|xlsx|docx|odt|ods|openoffice|ms|microsoft|micro$oft
ms, microsoft and micro$oft are  shorthand for docx,pptx,xlsx
openoffice is shorthand for odt,ods
    gam get drivefile drivefilename <DriveFileEntity> format docx,rtf,txt,odt,pdf
This will get file XXX as long as it is in some text document format. If a file is available in multiple formats, the first
available format in the list is chosen.

Add a command to remove drive files from the trash.
    gam <UserTypeEntity> untrash drivefile <DriveFileEntity>

Extend gam update group to explicitly allow clearing members from a group.
    gam update group <GroupItem> clear [owner] [manager] [member]

Extend the gam course add and gam course remove commands to use the same participant selections as gam course sync.
    gam course <CourseID> add teachers|students <UserTypeEntity>
    gam course <CourseID> delete teachers|students <UserTypeEntity>
    gam course <CourseID> sync teachers|students <UserTypeEntity>
<UserTypeEntity> ::=
        <EmailAddress>|
        (all users)|
        (user <EmailAddress>)|
        (users <EmailAddressList>)|
        (group <EmailAddress)|
        (ou <OrgUnitPath)|
        (ou_and_children <OrgUnitPath)|
        (courseparticipants <CourseID>)|
        (students <CourseID>)|
        (teachers <CourseID>)|
        (file <FileName> [charset <Charset>])|
        (csvfile <FileName>:<FieldName> [charset <Charset>])|
        (query <Query>)|
        (groups <GroupList)|
        (ous|orgs <OrgUnitList)|
        (ous_and_children|ous_and_child <OrgUnitList)|
        (courseparticipants <CourseIDList>)|
        (students <CourseIDList>)|
        (teachers <CourseIDList>)|
        (args users|groups|ous|ous_and_children|courseparticipants|students|teachers <Marker> <UserItem>* <Marker>)|
        (datafile users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>])|
        (csvkmd users|groups|ous|ous_and_children|courseparticipants|students|teachers <FileName> [charset <Charset>]
                keyfield <FieldName> [delimiter <String>]
                [matchfield <FieldName> <RegularExpression>]
                [datafield <FieldName> [delimiter <String>]])|
        (csvdata <FieldName>)

Allow user properties that are arrays, e.g., phone, organization, address, to be cleared.
Gam can currently set these arrays but has no way of removing all of the entries.
    gam update user <UserID> <Property> clear|none
<Property> is phone, organization, im, address, ...
    gam update user foo@bar.com phone none

Support user properties website and note.
In gam create user and gam update user add website argument.
    website home_page|blog|profile|work|home|other|ftp|reservations|app_install_page|<String> <Value>
    gam update user foo@bar.com website work www.bar.com
If <String> is specified instead of one of the pre-defined values, it will be marked custom.

    note text_plain|text_html file <FileName>
    note text_plain|text_html <String>
    gam update user foo@bar.com note text_plain "Works weekend shift"

Allow gam batch to read lines from stdin by specifying - instead of a file name.
    cat foo.bat | gam batch -
This makes gam batch have the same file options as gam csv; for those heavy duty scripting users.

Two new mutually exclusive arguments are defined for gam print mobile to set the amount of data retrieved.
    bam print mobile basic|full

A new argument (delimiter <String>) is defined in gam print users.
It is used when the groups argument is specified, <String> rather than a single space will separate the entries in the groups list.
    gam print users delimiter ',' groups

A new argument (delimiter <String>) is defined in gam print courses.
It is used when the aliases argument is specified, <String> rather than a single space will separate the entries in the aliases list.
    gam print courses delimiter ',' aliases

Extend gam version to force an update check.
    gam version check

Support event notification property in calendars.
In gam <UserTypeEntity> add calendar and gam <UserTypeEntity> update calendar, add notification argument; it may be repeated.
   notification email|sms event_creation|event_change|event_cancellation|event_response|agenda
   gam user foo@bar.com update calendar bar.com_xxx@group.calendar.google.com notification email event_creation notification sms event_change

Add an argument to gam <UserTypeEntity> show signature to format the signature.
   gam <UserTypeEntity> show signature|sig [format]

Add argument to gam print printjobs and gam printjob fetch to control number of retrieved print jobs.
   gam print printjobs ... limit <Number>
   gam printjob <PrinterId> fetch ... limit <Number>
limit specifies the maximum number of print jobs to retrieve; defaults to 25, set limit to 0 to retrieve all print jobs.

Clean up argument parsing, give user location of error in command line.
Currently:
    ./gam.py update user testuser1 address type foo formatted '123 main street' primary
    ERROR: wrong type should be custom, home, other or work. Got foo
Proposed:
    ./gam.py update user testuser1 address type foo formatted '123 main street' primary

    Command: ./gam.py update user testuser1 address type >>>foo<<< formatted '123 main street' primary
    ERROR: Invalid argument: expected <custom|home|other|work>
    Help: Documentation is at https://github.com/jay0lee/GAM/wiki
This change involves creating functions like getBoolean, getChoice, getInteger, that standardize argument
processing. Additionally, common processing of large argument lists is combined into a function.
For example, doCreateuser and doUpdateUser call getuserAttributes rather than repeating the argument processing.

Make reminder argument consistent in add/update calendar and calendar addevent.
    (reminder email|popup|sms <Number>)|(reminder <Number> email|popup|sms)

Make the file selection arguments for all drivefile and drivefileacl commands consistent.
    <DriveFileEntity> ::= ([id] <DriveFileItem>)|(ids <DriveFileList>|<FileSelector>|<ArgsSelector>|<CSVkmdSelector>|<CSVDataSelector>)|(drivefilename[:| ]<DriveFileName>)|(query[:| ]<QueryDriveFile>)|root

Corrected gam create resource so that type argument is properly recognized.

Add name and type specification argument for gam print resources.
    gam print resources [todrive] [allfields] [id] [name] [description] [email] [type]

Make the gam whatis command work better. Add an argument to suppress all output beyond the statement
indicating the type of the email address.
    gam whatis <EmailAddress> [noinfo]
If noinfo is specified, doGetUserInfo, doGetGroupInfo, doGetAliasInfo are not called.
If noinfo is not specified, the arguments in the doGetxxxInfo functions are processed starting at the correct point.
Additionally, each of the doGetxxxInfo functions silently ignore non-relevant arguments.
    gam whatis foo@bar.com nousers nogroups
If foo@bar.com is a user, nogroups takes effect and nousers is ignored.
If foo@bar.com is a group, nousers takes effect and nogroups is ignored.
If foo@bar.com is an alias, all arguments are ignored.

All "Getting ...", "Retrieving ...", "Got ..." messages are now written to stderr.
Most already were but the following commands wrote to stdout:
    gam <UserTypeEntity> show gmailprofile
    gam <UserTypeEntity> deprov
    gam <UserTypeEntity> delete label
    gam <UserTypeEntity> transfer drive
    gam <UserTypeEntity> add drivefile
    gam <UserTypeEntity> update drivefile
    gam <UserTypeEntity> delete drivefile
    gam <UserTypeEntity> get drivefile

Add additional commands to manage calendar events.
    gam calendar <CalendarEntity> add event <EventAttribute>
    gam calendar <CalendarEntity> update event <EventIDEntity> <EventAttribute>
    gam calendar <CalendarEntity> delete event <EventIDEntity>
    gam calendar <CalendarEntity> move event <EventIDEntity> to <CalendarItem>
    gam calendar <CalendarEntity> info event <EventIDEntity>
    gam calendar <CalendarEntity> show events
    gam calendar <CalendarEntity> wipe events

Add additional command to manage calendar ACLs.
    gam calendar <CalendarEntity> add acl <CalendarACLRole> ([user] <EmailAddress>)|(group <EmailAddress>)|(domain [<DomainName>])|default
    gam calendar <CalendarEntity> update acl <CalendarACLRole> ([user] <EmailAddress>)|(group <EmailAddress>)|(domain [<DomainName>])|default
    gam calendar <CalendarEntity> del|delete acl ([user] <EmailAddress>)|(group <EmailAddress>)|(domain [<DomainName>])|default
    gam calendar <CalendarEntity> add acls <CalendarACLRole> <CalendarACLEntity>
    gam calendar <CalendarEntity> update acls <CalendarACLRole> <CalendarACLEntity>
    gam calendar <CalendarEntity> del|delete acls [<CalendarACLRole>] <CalendarACLEntity>
    gam calendar <CalendarEntity> info acl|acls <CalendarACLEntity>
    gam calendar <CalendarEntity> show acls

Reorganize gam so that it is importable on Mac OS/Linux.
This isn't elegant but it's a start; you can say:
    #!/usr/bin/env python
    import os, sys, shlex
    from gam import ProcessGAMCommand
    # Set appropriate values
    os.environ['GAMCFGDIR'] = '/Users/admin/GAM'
    GAM_STDOUT = '/tmp/gamstdout.out'
    # Choose how to produce args list
    rc = ProcessGAMCommand(shlex.split('/Users/admin/GAM/gam.py redirect stdout {0} info user admin'.format(GAM_STDOUT)))
    #rc = ProcessGAMCommand(['/Users/admin/GAM/gam.py',
    #                        'redirect', 'stdout', GAM_STDOUT,
    #                        'info', 'user', 'admin'])
    print 'GAM returned {0}'.format(rc)
    with open(GAM_STDOUT, 'rU') as f:
        for line in f:
            sys.stdout.write(line)
