Updated <SchemaNameList> to allow schema fields

This commit is contained in:
Ross Scroggs
2024-05-29 10:49:31 -07:00
parent db95cbcfa4
commit 5a335fb57b
9 changed files with 153 additions and 92 deletions

View File

@@ -457,6 +457,7 @@
<ResellerID> ::= <String> <ResellerID> ::= <String>
<ResourceID> ::= <String> <ResourceID> ::= <String>
<SchemaName> ::= <String> <SchemaName> ::= <String>
<SchemaNameField> ::= <SchemaName>.<FieldName>
<Section> ::= <String> <Section> ::= <String>
<SendAsContent> ::= <SendAsContent> ::=
(sig|signature|htmlsig <String>)| (sig|signature|htmlsig <String>)|
@@ -513,6 +514,7 @@
<Title> ::= <String> <Title> ::= <String>
<ToDriveAttribute> ::= <ToDriveAttribute> ::=
(tdaddsheet [<Boolean>])| (tdaddsheet [<Boolean>])|
(tdalert <EmailAddress>)*|
(tdbackupsheet (id:<Number>)|<String>)| (tdbackupsheet (id:<Number>)|<String>)|
(tdcellnumberformat text|number)| (tdcellnumberformat text|number)|
(tdcellwrap clip|overflow|wrap)| (tdcellwrap clip|overflow|wrap)|
@@ -520,17 +522,20 @@
(tdcopysheet (id:<Number>)|<String>)| (tdcopysheet (id:<Number>)|<String>)|
(tddescription <String>)| (tddescription <String>)|
(tdfileid <DriveFileID>)| (tdfileid <DriveFileID>)|
(tdfrom <EmailAddress>)|
(tdlocalcopy [<Boolean>])| (tdlocalcopy [<Boolean>])|
(tdlocale <Locale>)| (tdlocale <Locale>)|
(tdnobrowser [<Boolean>])| (tdnobrowser [<Boolean>])|
(tdnoemail [<Boolean>])| (tdnoemail [<Boolean>])|
(tdnoescapechar [<Boolean>])| (tdnoescapechar [<Boolean>])|
(tdnotify [<Boolean>])|
(tdparent (id:<DriveFolderID>)|<DriveFolderName>)| (tdparent (id:<DriveFolderID>)|<DriveFolderName>)|
(tdretaintitle [<Boolean>])| (tdretaintitle [<Boolean>])|
(tdshare <EmailAddress> commenter|reader|writer)*| (tdshare <EmailAddress> commenter|reader|writer)*|
(tdsheet (id:<Number>)|<String>)| (tdsheet (id:<Number>)|<String>)|
(tdsheettimestamp [<Boolean>] [tdsheettimeformat <String>]) (tdsheettimestamp [<Boolean>] [tdsheettimeformat <String>])
(tdsheettitle <String>)| (tdsheettitle <String>)|
(tdsubject <String>)|
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])| ([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])|
(tdtimestamp [<Boolean>] [tdtimeformat <String>] (tdtimestamp [<Boolean>] [tdtimeformat <String>]
[tddaysoffset <Number>] [tdhoursoffset <Number>])| [tddaysoffset <Number>] [tdhoursoffset <Number>])|

View File

@@ -10,6 +10,12 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation See [Downloads](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads) for Windows or other options, including manual installation
### 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 ### 6.76.07
Fixed bug where control-C was not recognized when GAM had processed all rows in a CSV file Fixed bug where control-C was not recognized when GAM had processed all rows in a CSV file

View File

@@ -335,7 +335,7 @@ writes the credentials into the file oauth2.txt.
admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt admin@server:/Users/admin/bin/gamadv-xtd3$ rm -f /Users/admin/GAMConfig/oauth2.txt
admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version admin@server:/Users/admin/bin/gamadv-xtd3$ ./gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAMADV-XTD3 6.76.07 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.76.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.3 64-bit final Python 3.12.3 64-bit final
MacOS Sonoma 14.4.1 x86_64 MacOS Sonoma 14.4.1 x86_64
@@ -1009,7 +1009,7 @@ writes the credentials into the file oauth2.txt.
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
C:\GAMADV-XTD3>gam version C:\GAMADV-XTD3>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAMADV-XTD3 6.76.07 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.76.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.3 64-bit final Python 3.12.3 64-bit final
Windows-10-10.0.17134 AMD64 Windows-10-10.0.17134 AMD64

View File

@@ -85,7 +85,7 @@
<QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*" <QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*"
<QueryUserList> ::= "<QueryUser>(,<QueryUser>)*" <QueryUserList> ::= "<QueryUser>(,<QueryUser>)*"
<ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*" <ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*"
<SchemaNameList> ::= "<SchemaName>(,<SchemaName>)*" <SchemaNameList> ::= "<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"
<SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*" <SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*"
<ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*" <ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*"
<SiteACLScopeList> ::= "<SiteACLScope>(,<SiteACLScope>)*" <SiteACLScopeList> ::= "<SiteACLScope>(,<SiteACLScope>)*"

View File

@@ -110,6 +110,11 @@ queries "`"orgUnitPath=\'/Students/Lower\ School/2027\'`",`"orgUnitPath=\'/Stude
<QueryUser> ::= <String> <QueryUser> ::= <String>
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-users See: https://developers.google.com/admin-sdk/directory/v1/guides/search-users
<FieldName> ::= <String>
<SchemaName> ::= <String>
<SchemaNameField> ::= <SchemaName>.<FieldName>
<SchemaNameList> ::= "<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"
<StorageBucketName> ::= <String> <StorageBucketName> ::= <String>
<StorageObjectName> ::= <String> <StorageObjectName> ::= <String>
<StorageBucketObjectName> ::= <StorageBucketObjectName> ::=
@@ -488,7 +493,7 @@ clearschema <SchemaName>
``` ```
Clear a specific field in a schema: Clear a specific field in a schema:
``` ```
clearschema <SchemaName>.<FieldName> clearschema <SchemaNameField>
``` ```
## Create a user ## Create a user
@@ -614,7 +619,7 @@ gam update user <UserItem> [ignorenullpassword] <UserAttribute>*
[updateoufromgroup <FileName> [charset <Charset>] [updateoufromgroup <FileName> [charset <Charset>]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]] [fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [clearschema <SchemaName>|<SchemaNameField>]
[createifnotfound] [notfoundpassword random|<Password>] [createifnotfound] [notfoundpassword random|<Password>]
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)* (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
[alias|aliases <EmailAddressList>] [alias|aliases <EmailAddressList>]
@@ -635,7 +640,7 @@ gam update users <UserTypeEntity> [ignorenullpassword] <UserAttribute>*
[updateoufromgroup <FileName> [charset <Charset>] [updateoufromgroup <FileName> [charset <Charset>]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]] [fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [clearschema <SchemaName>|<SchemaNameField>]
[createifnotfound] [notfoundpassword random|<Password>] [createifnotfound] [notfoundpassword random|<Password>]
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)* (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
[alias|aliases <EmailAddressList>] [alias|aliases <EmailAddressList>]
@@ -656,7 +661,7 @@ gam <UserTypeEntity> update users [ignorenullpassword] <UserAttribute>*
[updateoufromgroup <FileName> [charset <Charset>] [updateoufromgroup <FileName> [charset <Charset>]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]] [fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [clearschema <SchemaName>|<SchemaNameField>]
[createifnotfound] [notfoundpassword random|<Password>] [createifnotfound] [notfoundpassword random|<Password>]
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)* (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
[alias|aliases <EmailAddressList>] [alias|aliases <EmailAddressList>]
@@ -954,7 +959,7 @@ Starting in version `5.23.01`, the variable `quick_info_user` was added to `gam.
These existing options enable the display of additional information. These existing options enable the display of additional information.
* `(products|product <ProductIDList>)|(skus|sku <SKUIDList>)` - Display license information for a selected list of products/SKUs. * `(products|product <ProductIDList>)|(skus|sku <SKUIDList>)` - Display license information for a selected list of products/SKUs.
* `schemas|custom|customschemas <SchemaNameList>` - Display the specified custom schemas * `schemas|custom|customschemas <SchemaNameList>` - Display all fields or selected fields of the specified custom schemas
By default, Gam displays fields that only an adminstrator can view. By default, Gam displays fields that only an adminstrator can view.
* `userview` - Only display fields that other users in the domain can view. * `userview` - Only display fields that other users in the domain can view.
@@ -1064,8 +1069,8 @@ By default, Gam displays only the primary email address for each user.
* `allfields|basic` - Display all non custom schema fields for each user. * `allfields|basic` - Display all non custom schema fields for each user.
* `full` - Display all fields including all custom schema fields for each user. * `full` - Display all fields including all custom schema fields for each user.
* `<UserFieldName>* [fields <UserFieldNameList>]` - Only display selected fields. * `<UserFieldName>* [fields <UserFieldNameList>]` - Only display selected fields.
* `schemas|custom all` - Get custom schema information for all schemas. * `schemas|custom all` - Display custom schema information for all schemas.
* `schemas|custom <SchemaNameList>` - Get custom schema information for a selected list of schemas. * `schemas|custom <SchemaNameList>` - Display all fields or selected fields of the specified custom schemas
By default, when aliases are displayed, all aliases are displayed. Use `aliasmatchpattern <RegularExpression>` By default, when aliases are displayed, all aliases are displayed. Use `aliasmatchpattern <RegularExpression>`
to limit the display of aliases to those that match `<RegularExpression>`. to limit the display of aliases to those that match `<RegularExpression>`.

View File

@@ -3,7 +3,7 @@
Print the current version of Gam with details Print the current version of Gam with details
``` ```
gam version gam version
GAMADV-XTD3 6.76.07 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.76.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.3 64-bit final Python 3.12.3 64-bit final
MacOS Sonoma 14.4.1 x86_64 MacOS Sonoma 14.4.1 x86_64
@@ -15,7 +15,7 @@ Time: 2023-06-02T21:10:00-07:00
Print the current version of Gam with details and time offset information Print the current version of Gam with details and time offset information
``` ```
gam version timeoffset gam version timeoffset
GAMADV-XTD3 6.76.07 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.76.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.3 64-bit final Python 3.12.3 64-bit final
MacOS Sonoma 14.4.1 x86_64 MacOS Sonoma 14.4.1 x86_64
@@ -27,7 +27,7 @@ Your system time differs from www.googleapis.com by less than 1 second
Print the current version of Gam with extended details and SSL information Print the current version of Gam with extended details and SSL information
``` ```
gam version extended gam version extended
GAMADV-XTD3 6.76.07 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource GAMADV-XTD3 6.76.08 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.3 64-bit final Python 3.12.3 64-bit final
MacOS Sonoma 14.4.1 x86_64 MacOS Sonoma 14.4.1 x86_64
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gamadv-xtd3 Path: /Users/Admin/bin/gamadv-xtd3
Version Check: Version Check:
Current: 5.35.08 Current: 5.35.08
Latest: 6.76.07 Latest: 6.76.08
echo $? echo $?
1 1
``` ```
@@ -72,7 +72,7 @@ echo $?
Print the current version number without details Print the current version number without details
``` ```
gam version simple gam version simple
6.76.07 6.76.08
``` ```
In Linux/MacOS you can do: In Linux/MacOS you can do:
``` ```
@@ -82,7 +82,7 @@ echo $VER
Print the current version of Gam and address of this Wiki Print the current version of Gam and address of this Wiki
``` ```
gam help gam help
GAM 6.76.07 - https://github.com/taers232c/GAMADV-XTD3 GAM 6.76.08 - https://github.com/taers232c/GAMADV-XTD3
Ross Scroggs <ross.scroggs@gmail.com> Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.3 64-bit final Python 3.12.3 64-bit final
MacOS Sonoma 14.4.1 x86_64 MacOS Sonoma 14.4.1 x86_64

View File

@@ -546,6 +546,7 @@ If an item contains spaces, it should be surrounded by ".
<ResellerID> ::= <String> <ResellerID> ::= <String>
<ResourceID> ::= <String> <ResourceID> ::= <String>
<SchemaName> ::= <String> <SchemaName> ::= <String>
<SchemaNameField> ::= <SchemaName>.<FieldName>
<Section> ::= <String> <Section> ::= <String>
<SendAsContent> ::= <SendAsContent> ::=
(sig|signature|htmlsig <String>)| (sig|signature|htmlsig <String>)|
@@ -626,7 +627,7 @@ If an item contains spaces, it should be surrounded by ".
(tdsubject <String>)| (tdsubject <String>)|
([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])| ([tdsheetdaysoffset <Number>] [tdsheethoursoffset <Number>])|
(tdtimestamp [<Boolean>] [tdtimeformat <String>] (tdtimestamp [<Boolean>] [tdtimeformat <String>]
([tddaysoffset <Number>] [tdhoursoffset <Number>])| [tddaysoffset <Number>] [tdhoursoffset <Number>])|
(tdtimezone <TimeZone>)| (tdtimezone <TimeZone>)|
(tdtitle <String>)| (tdtitle <String>)|
(tdupdatesheet [<Boolean>])| (tdupdatesheet [<Boolean>])|
@@ -725,7 +726,7 @@ If an item contains spaces, it should be surrounded by ".
<QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*" <QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*"
<QueryUserList> ::= "<QueryUser>(,<QueryUser>)*" <QueryUserList> ::= "<QueryUser>(,<QueryUser>)*"
<ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*" <ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*"
<SchemaNameList> ::= "<SchemaName>(,<SchemaName>)*" <SchemaNameList> ::= "<SchemaName>|<SchemaFieldName>(,<SchemaName>|<SchemaFieldName>)*"
<SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*" <SerialNumberList> ::= "<SerialNumber>(,<SerialNumber>)*"
<ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*" <ServiceAccountKeyList> ::= "<ServiceAccountKey>(,<ServiceAccountKey>)*"
<SiteACLScopeList> ::= "<SiteACLScope>(,<SiteACLScope>)*" <SiteACLScopeList> ::= "<SiteACLScope>(,<SiteACLScope>)*"
@@ -4991,7 +4992,7 @@ gam <UserTypeEntity> show teamdriveacls
(field:<UserReplacementField>)| (field:<UserReplacementField>)|
(field:<UserReplacementFieldSubfield>)| (field:<UserReplacementFieldSubfield>)|
(field:<UserReplacementFieldSubfieldMatchSubfield>)| (field:<UserReplacementFieldSubfieldMatchSubfield>)|
(schema:<SchemaName>.<FieldName>)| (schema:<SchemaNameField>)|
<String> <String>
# Vault/Takeout # Vault/Takeout
@@ -5256,7 +5257,7 @@ gam download storagefile <StorageBucketObjectName>
(recoveryemail <EmailAddress>)| (recoveryemail <EmailAddress>)|
(recoveryphone <string>)| (recoveryphone <string>)|
(suspend|suspended <Boolean>)| (suspend|suspended <Boolean>)|
(<SchemaName>.<FieldName> [scalarnonempty| (<SchemaNameField> [scalarnonempty|
[multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]]] [multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]]]
<String>) <String>)
@@ -5347,7 +5348,7 @@ gam update user <UserItem> [ignorenullpassword] <UserAttribute>*
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]] [fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
[immutableous <OrgUnitEntity>]| [immutableous <OrgUnitEntity>]|
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [clearschema <SchemaName> | <SchemaNameField>]
[createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>] [createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)* (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
[alias|aliases <EmailAddressList>] [alias|aliases <EmailAddressList>]
@@ -5382,7 +5383,7 @@ gam update users <UserTypeEntity> [ignorenullpassword] <UserAttribute>*
[updateoufromgroup <FileName> [charset <CharSet>] [updateoufromgroup <FileName> [charset <CharSet>]
[columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>] [columndelimiter <Character>] [noescapechar <Boolean>] [quotechar <Character>]
[fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]] [fields <FieldNameList>] [keyfield <FieldName>] [datafield <FieldName>]]
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [clearschema <SchemaName>|<SchemaNameField>]
[createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>] [createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)* (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
[alias|aliases <EmailAddressList>] [alias|aliases <EmailAddressList>]
@@ -5415,7 +5416,7 @@ gam <UserTypeEntity> update users [ignorenullpassword] <UserAttribute>*
[verifynotinvitable] [noactionifalias] [verifynotinvitable] [noactionifalias]
[updateprimaryemail <RegularExpression> <EmailReplacement>] [updateprimaryemail <RegularExpression> <EmailReplacement>]
[updateoufromgroup <CSVFileInput> [keyfield <FieldName>] [datafield <FieldName>]] [updateoufromgroup <CSVFileInput> [keyfield <FieldName>] [datafield <FieldName>]]
[clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] [clearschema <SchemaName> | <SchemaNameField>]
[createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>] [createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
(groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)* (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
[alias|aliases <EmailAddressList>] [alias|aliases <EmailAddressList>]

View File

@@ -2,6 +2,12 @@
Merged GAM-Team version Merged GAM-Team version
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 6.76.07
Fixed bug where control-C was not recognized when GAM had processed all rows in a CSV file Fixed bug where control-C was not recognized when GAM had processed all rows in a CSV file

View File

@@ -41917,7 +41917,7 @@ def verifyUserPrimaryEmail(cd, user, createIfNotFound, i, count):
# [updateprimaryemail <RegularExpression> <EmailReplacement>] # [updateprimaryemail <RegularExpression> <EmailReplacement>]
# [updateoufromgroup <CSVFileInput> [keyfield <FieldName>] [datafield <FieldName>]] # [updateoufromgroup <CSVFileInput> [keyfield <FieldName>] [datafield <FieldName>]]
# [immutableous <OrgUnitEntity>]| # [immutableous <OrgUnitEntity>]|
# [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] # [clearschema <SchemaName>|<SchemaNameField>]
# [createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>] # [createifnotfound] [notfoundpassword (random [<Integer>])|blocklogin|<Password>]
# (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)* # (groups [<GroupRole>] [[delivery] <DeliverySetting>] <GroupEntity>)*
# [alias|aliases <EmailAddressList>] # [alias|aliases <EmailAddressList>]
@@ -42523,6 +42523,44 @@ def _formatLanguagesList(propertyValue, delimiter):
languages.append(lang) languages.append(lang)
return delimiter.join(languages) return delimiter.join(languages)
def _initSchemaParms(projection):
return {'projection': projection, 'customFieldMask': None, 'selectedSchemaFields': {}}
def _getSchemaNameList(schemaParms):
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',')
if customFieldMask.lower() == 'all':
schemaParms['projection'] = 'full'
schemaParms['customFieldMask'] = None
schemaParms['selectedSchemaFields'] = {}
else:
schemaParms['projection'] = 'custom'
customFieldMaskList = []
for schemaField in customFieldMask.split(','):
if schemaField.find('.') == -1:
customFieldMaskList.append(schemaField)
else:
schemaName, fieldName = schemaField.split('.', 1)
customFieldMaskList.append(schemaName)
schemaParms['selectedSchemaFields'] .setdefault(schemaName, set())
schemaParms['selectedSchemaFields'][schemaName].add(fieldName)
schemaParms['customFieldMask'] = ','.join(customFieldMaskList)
def _filterSchemaFields(userEntity, schemaParms):
schemas = userEntity.pop('customSchemas', None)
if schemas is None:
return
customSchemas = {}
for schema in sorted(schemas):
if schema in schemaParms['selectedSchemaFields']:
for field, value in sorted(iter(schemas[schema].items())):
if field not in schemaParms['selectedSchemaFields'][schema]:
continue
customSchemas.setdefault(schema, {})
customSchemas[schema][field] = value
else:
customSchemas[schema] = schemas[schema]
userEntity['customSchemas'] = customSchemas
def infoUsers(entityList): def infoUsers(entityList):
def printUserCIGroupMap(parent, group_name_mappings, seen_group_count, edges, direction): def printUserCIGroupMap(parent, group_name_mappings, seen_group_count, edges, direction):
for a_parent, a_child in edges: for a_parent, a_child in edges:
@@ -42558,8 +42596,7 @@ def infoUsers(entityList):
getAliases = getBuildingNames = getCIGroupsTree = getGroups = getLicenses = getSchemas = not GC.Values[GC.QUICK_INFO_USER] getAliases = getBuildingNames = getCIGroupsTree = getGroups = getLicenses = getSchemas = not GC.Values[GC.QUICK_INFO_USER]
getGroupsTree = False getGroupsTree = False
FJQC = FormatJSONQuoteChar() FJQC = FormatJSONQuoteChar()
projection = 'full' schemaParms = _initSchemaParms('full')
customFieldMask = None
viewType = 'admin_view' viewType = 'admin_view'
fieldsList = [] fieldsList = []
groups = [] groups = []
@@ -42582,19 +42619,13 @@ def infoUsers(entityList):
getLicenses = myarg in {'licenses', 'licences'} getLicenses = myarg in {'licenses', 'licences'}
elif myarg == 'noschemas': elif myarg == 'noschemas':
getSchemas = False getSchemas = False
projection = 'basic' schemaParms = _initSchemaParms('basic')
elif myarg == 'allschemas': elif myarg == 'allschemas':
getSchemas = True getSchemas = True
projection = 'full' schemaParms = _initSchemaParms('full')
elif myarg in {'custom', 'schemas', 'customschemas'}: elif myarg in {'custom', 'schemas', 'customschemas'}:
getSchemas = True getSchemas = True
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',') _getSchemaNameList(schemaParms)
if customFieldMask.lower() == 'all':
customFieldMask = None
projection = 'full'
else:
projection = 'custom'
fieldsList.append('customSchemas')
elif myarg in {'products', 'product'}: elif myarg in {'products', 'product'}:
skus = SKU.convertProductListToSKUList(getGoogleProductList()) skus = SKU.convertProductListToSKUList(getGoogleProductList())
elif myarg in {'sku', 'skus'}: elif myarg in {'sku', 'skus'}:
@@ -42611,6 +42642,8 @@ def infoUsers(entityList):
FJQC.GetFormatJSON(myarg) FJQC.GetFormatJSON(myarg)
if fieldsList: if fieldsList:
fieldsList.append('primaryEmail') fieldsList.append('primaryEmail')
if getSchemas:
fieldsList.append('customSchemas')
if getAliases: if getAliases:
fieldsList.extend(['aliases', 'nonEditableAliases']) fieldsList.extend(['aliases', 'nonEditableAliases'])
fields = getFieldsFromFieldsList(fieldsList) fields = getFieldsFromFieldsList(fieldsList)
@@ -42627,7 +42660,8 @@ def infoUsers(entityList):
try: try:
user = callGAPI(cd.users(), 'get', user = callGAPI(cd.users(), 'get',
throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND], throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND],
userKey=userEmail, projection=projection, customFieldMask=customFieldMask, viewType=viewType, fields=fields) userKey=userEmail, projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
viewType=viewType, fields=fields)
groups = [] groups = []
memberships = [] memberships = []
if getGroups or getGroupsTree: if getGroups or getGroupsTree:
@@ -42859,6 +42893,10 @@ def infoUsers(entityList):
typeKey = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_TYPE_KEYWORD] typeKey = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_TYPE_KEYWORD]
typeCustomValue = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_TYPE_CUSTOM_VALUE] typeCustomValue = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_TYPE_CUSTOM_VALUE]
customTypeKey = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_CUSTOMTYPE_KEYWORD] customTypeKey = userProperty[UProp.TYPE_KEYWORDS][UProp.PTKW_ATTR_CUSTOMTYPE_KEYWORD]
if schemaParms['selectedSchemaFields']:
_filterSchemaFields(user, schemaParms)
propertyValue = user[up]
if propertyValue:
printKeyValueList([UProp.PROPERTIES[up][UProp.TITLE], None]) printKeyValueList([UProp.PROPERTIES[up][UProp.TITLE], None])
Ind.Increment() Ind.Increment()
for schema in sorted(propertyValue): for schema in sorted(propertyValue):
@@ -42942,8 +42980,8 @@ def infoUsers(entityList):
GAPI.badRequest, GAPI.backendError, GAPI.systemError) as e: GAPI.badRequest, GAPI.backendError, GAPI.systemError) as e:
entityActionFailedWarning([Ent.USER, userEmail], str(e), i, count) entityActionFailedWarning([Ent.USER, userEmail], str(e), i, count)
except (GAPI.invalidInput, GAPI.invalidMember) as e: except (GAPI.invalidInput, GAPI.invalidMember) as e:
if customFieldMask: if schemaParms['customFieldMask']:
entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(customFieldMask), i, count) entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(schemaParms['customFieldMask']), i, count)
else: else:
entityActionFailedWarning([Ent.USER, userEmail], str(e), i, count) entityActionFailedWarning([Ent.USER, userEmail], str(e), i, count)
@@ -43058,6 +43096,8 @@ def doPrintUsers(entityList=None):
phoneNumber = phone.get('value', '') phoneNumber = phone.get('value', '')
if phoneNumber.startswith('+'): if phoneNumber.startswith('+'):
phone['value'] = "'"+phoneNumber phone['value'] = "'"+phoneNumber
if schemaParms['selectedSchemaFields']:
_filterSchemaFields(userEntity, schemaParms)
if printOptions['getGroupFeed']: if printOptions['getGroupFeed']:
printGettingAllEntityItemsForWhom(Ent.GROUP_MEMBERSHIP, userEmail, i, count) printGettingAllEntityItemsForWhom(Ent.GROUP_MEMBERSHIP, userEmail, i, count)
try: try:
@@ -43128,8 +43168,8 @@ def doPrintUsers(entityList=None):
entityUnknownWarning(Ent.USER, ri[RI_ITEM], int(ri[RI_J]), int(ri[RI_JCOUNT])) entityUnknownWarning(Ent.USER, ri[RI_ITEM], int(ri[RI_J]), int(ri[RI_JCOUNT]))
else: else:
_writeUserEntity({'primaryEmail': ri[RI_ITEM], showValidColumn: False}) _writeUserEntity({'primaryEmail': ri[RI_ITEM], showValidColumn: False})
elif (reason == GAPI.INVALID_INPUT) and customFieldMask: elif (reason == GAPI.INVALID_INPUT) and schemaParms['customFieldMask']:
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(customFieldMask), int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(schemaParms['customFieldMask']), int(ri[RI_J]), int(ri[RI_JCOUNT]))
elif reason not in GAPI.DEFAULT_RETRY_REASONS: elif reason not in GAPI.DEFAULT_RETRY_REASONS:
errMsg = getHTTPError(_PRINT_USER_REASON_TO_MESSAGE_MAP, http_status, reason, message) errMsg = getHTTPError(_PRINT_USER_REASON_TO_MESSAGE_MAP, http_status, reason, message)
printKeyValueList([ERROR, errMsg]) printKeyValueList([ERROR, errMsg])
@@ -43138,7 +43178,8 @@ def doPrintUsers(entityList=None):
try: try:
user = callGAPI(cd.users(), 'get', user = callGAPI(cd.users(), 'get',
throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.RATE_LIMIT_EXCEEDED], throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.RATE_LIMIT_EXCEEDED],
userKey=ri[RI_ITEM], projection=projection, customFieldMask=customFieldMask, viewType=viewType, fields=fields) userKey=ri[RI_ITEM], projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
viewType=viewType, fields=fields)
_printUser(user, int(ri[RI_J]), int(ri[RI_JCOUNT])) _printUser(user, int(ri[RI_J]), int(ri[RI_JCOUNT]))
except (GAPI.userNotFound, GAPI.resourceNotFound): except (GAPI.userNotFound, GAPI.resourceNotFound):
if not showValidColumn: if not showValidColumn:
@@ -43149,8 +43190,8 @@ def doPrintUsers(entityList=None):
GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.rateLimitExceeded) as e: GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.rateLimitExceeded) as e:
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
except GAPI.invalidInput as e: except GAPI.invalidInput as e:
if customFieldMask: if schemaParms['customFieldMask']:
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(customFieldMask), int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], invalidUserSchema(schemaParms['customFieldMask']), int(ri[RI_J]), int(ri[RI_JCOUNT]))
else: else:
entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT])) entityActionFailedWarning([Ent.USER, ri[RI_ITEM]], str(e), int(ri[RI_J]), int(ri[RI_JCOUNT]))
@@ -43174,9 +43215,8 @@ def doPrintUsers(entityList=None):
lic = None lic = None
skus = None skus = None
maxResults = GC.Values[GC.USER_MAX_RESULTS] maxResults = GC.Values[GC.USER_MAX_RESULTS]
projection = 'basic' schemaParms = _initSchemaParms('basic')
projectionSet = False projectionSet = False
customFieldMask = None
oneLicensePerRow = quotePlusPhoneNumbers = showDeleted = False oneLicensePerRow = quotePlusPhoneNumbers = showDeleted = False
aliasMatchPattern = isSuspended = orgUnitPath = orgUnitPathLower = orderBy = sortOrder = None aliasMatchPattern = isSuspended = orgUnitPath = orgUnitPathLower = orderBy = sortOrder = None
viewType = 'admin_view' viewType = 'admin_view'
@@ -43203,27 +43243,22 @@ def doPrintUsers(entityList=None):
orderBy, sortOrder = getOrderBySortOrder(USERS_ORDERBY_CHOICE_MAP) orderBy, sortOrder = getOrderBySortOrder(USERS_ORDERBY_CHOICE_MAP)
elif myarg == 'userview': elif myarg == 'userview':
viewType = 'domain_public' viewType = 'domain_public'
elif myarg in {'allfields', 'basic'}:
schemaParms = _initSchemaParms('basic')
projectionSet = printOptions['sortHeaders'] = True
fieldsList = []
elif myarg == 'full':
if schemaParms['projection'] != 'custom':
schemaParms = _initSchemaParms(myarg)
projectionSet = printOptions['sortHeaders'] = True
fieldsList = []
elif myarg in {'custom', 'schemas', 'customschemas'}: elif myarg in {'custom', 'schemas', 'customschemas'}:
if not fieldsList:
fieldsList = ['primaryEmail']
fieldsList.append('customSchemas')
customFieldMask = getString(Cmd.OB_SCHEMA_NAME_LIST).replace(' ', ',')
if customFieldMask.lower() == 'all':
customFieldMask = None
projection = 'full'
else:
projection = 'custom'
projectionSet = True projectionSet = True
_getSchemaNameList(schemaParms)
if fieldsList:
fieldsList.append('customSchemas')
elif myarg == 'delimiter': elif myarg == 'delimiter':
delimiter = getCharacter() delimiter = getCharacter()
elif myarg in PROJECTION_CHOICE_MAP:
projection = myarg
projectionSet = printOptions['sortHeaders'] = True
fieldsList = []
elif myarg == 'allfields':
projection = 'basic'
projectionSet = printOptions['sortHeaders'] = True
fieldsList = []
elif myarg == 'sortheaders': elif myarg == 'sortheaders':
printOptions['sortHeaders'] = getBoolean() printOptions['sortHeaders'] = getBoolean()
elif myarg == 'scalarsfirst': elif myarg == 'scalarsfirst':
@@ -43326,7 +43361,8 @@ def doPrintUsers(entityList=None):
GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN], GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
query=query, fields=fields, query=query, fields=fields,
showDeleted=showDeleted, orderBy=orderBy, sortOrder=sortOrder, viewType=viewType, showDeleted=showDeleted, orderBy=orderBy, sortOrder=sortOrder, viewType=viewType,
projection=projection, customFieldMask=customFieldMask, maxResults=maxResults, **kwargs) projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
maxResults=maxResults, **kwargs)
for users in feed: for users in feed:
if showItemCountOnly: if showItemCountOnly:
itemCount += len(users) itemCount += len(users)
@@ -43351,12 +43387,12 @@ def doPrintUsers(entityList=None):
entityActionFailedWarning([Ent.USER, None, Ent.DOMAIN, kwargs['domain']], Msg.NOT_FOUND) entityActionFailedWarning([Ent.USER, None, Ent.DOMAIN, kwargs['domain']], Msg.NOT_FOUND)
continue continue
except (GAPI.invalidOrgunit, GAPI.invalidInput) as e: except (GAPI.invalidOrgunit, GAPI.invalidInput) as e:
if query and not customFieldMask: if query and not schemaParms['customFieldMask']:
entityActionFailedWarning([Ent.USER, None], invalidQuery(query)) entityActionFailedWarning([Ent.USER, None], invalidQuery(query))
elif customFieldMask and not query: elif schemaParms['customFieldMask'] and not query:
entityActionFailedWarning([Ent.USER, None], invalidUserSchema(customFieldMask)) entityActionFailedWarning([Ent.USER, None], invalidUserSchema(schemaParms['customFieldMask']))
elif query and customFieldMask: elif query and schemaParms['customFieldMask']:
entityActionFailedWarning([Ent.USER, None], f'{invalidQuery(query)} or {invalidUserSchema(customFieldMask)}') entityActionFailedWarning([Ent.USER, None], f'{invalidQuery(query)} or {invalidUserSchema(schemaParms['customFieldMask'])}')
else: else:
entityActionFailedWarning([Ent.USER, None], str(e)) entityActionFailedWarning([Ent.USER, None], str(e))
continue continue
@@ -43377,7 +43413,9 @@ def doPrintUsers(entityList=None):
jcount = len(entityList) jcount = len(entityList)
fields = getFieldsFromFieldsList(fieldsList) fields = getFieldsFromFieldsList(fieldsList)
if GC.Values[GC.BATCH_SIZE] > 1 and jcount > 1: if GC.Values[GC.BATCH_SIZE] > 1 and jcount > 1:
svcargs = dict([('userKey', None), ('fields', fields), ('projection', projection), ('customFieldMask', customFieldMask), ('viewType', viewType)]+GM.Globals[GM.EXTRA_ARGS_LIST]) svcargs = dict([('userKey', None), ('fields', fields),
('projection', schemaParms['projection']), ('customFieldMask', schemaParms['customFieldMask']),
('viewType', viewType)]+GM.Globals[GM.EXTRA_ARGS_LIST])
method = getattr(cd.users(), 'get') method = getattr(cd.users(), 'get')
dbatch = cd.new_batch_http_request(callback=_callbackPrintUser) dbatch = cd.new_batch_http_request(callback=_callbackPrintUser)
bcount = 0 bcount = 0
@@ -43402,7 +43440,8 @@ def doPrintUsers(entityList=None):
try: try:
user = callGAPI(cd.users(), 'get', user = callGAPI(cd.users(), 'get',
throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.RATE_LIMIT_EXCEEDED], throwReasons=GAPI.USER_GET_THROW_REASONS+[GAPI.INVALID_INPUT, GAPI.RESOURCE_NOT_FOUND, GAPI.RATE_LIMIT_EXCEEDED],
userKey=userEmail, projection=projection, customFieldMask=customFieldMask, viewType=viewType, fields=fields) userKey=userEmail, projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
viewType=viewType, fields=fields)
_printUser(user, j, jcount) _printUser(user, j, jcount)
except (GAPI.userNotFound, GAPI.resourceNotFound): except (GAPI.userNotFound, GAPI.resourceNotFound):
if not showValidColumn: if not showValidColumn:
@@ -43413,8 +43452,8 @@ def doPrintUsers(entityList=None):
GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.rateLimitExceeded) as e: GAPI.badRequest, GAPI.backendError, GAPI.systemError, GAPI.rateLimitExceeded) as e:
entityActionFailedWarning([Ent.USER, userEmail], str(e), j, jcount) entityActionFailedWarning([Ent.USER, userEmail], str(e), j, jcount)
except GAPI.invalidInput as e: except GAPI.invalidInput as e:
if customFieldMask: if schemaParms['customFieldMask']:
entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(customFieldMask), j, jcount) entityActionFailedWarning([Ent.USER, userEmail], invalidUserSchema(schemaParms['customFieldMask']), j, jcount)
else: else:
entityActionFailedWarning([Ent.USER, userEmail], str(e), j, jcount) entityActionFailedWarning([Ent.USER, userEmail], str(e), j, jcount)
# The only field specified was primaryEmail, just list the users/count the domains # The only field specified was primaryEmail, just list the users/count the domains
@@ -53951,10 +53990,9 @@ def printFileList(users):
showParent = getBoolean() showParent = getBoolean()
elif myarg == 'nodataheaders': elif myarg == 'nodataheaders':
nodataFields = getString(Cmd.OB_FIELD_NAME_LIST).replace('_', '').replace(',', ' ').split() nodataFields = getString(Cmd.OB_FIELD_NAME_LIST).replace('_', '').replace(',', ' ').split()
elif myarg == 'filepath': elif myarg in {'filepath', 'fullpath'}:
filepath = True filepath = True
elif myarg == 'fullpath': fullpath = myarg == 'fullpath'
filepath = fullpath = True
elif myarg == 'folderpathonly': elif myarg == 'folderpathonly':
folderPathOnly = getBoolean() folderPathOnly = getBoolean()
elif myarg == 'pathdelimiter': elif myarg == 'pathdelimiter':