Multiple updates (#1273)

* Multiple updates

Add member to print cigroups|cigroup-members to select groups to display
Drop Google-Coordinate product ID
Update print|show driveactivity to Drive Activity API v2
Check for more parents than 1 in create|update drivefile
Update documentation
Allow times_to_check_status with gam getcommand cros
Display deviceId and commandId when issuing/getting commands

* Fix orgunit references in vault

* Rename member to enterprisemember in print cigroups|cigroup-members

Give error message indication the Enterprise license is required

* Add lastKnownNetwork to CrOS fields

* Soft fail when deleting user photo

* Fix bug in PR #1273
This commit is contained in:
Ross Scroggs
2020-12-05 18:54:26 -08:00
committed by GitHub
parent 6a879927a7
commit 8ce18960fe
7 changed files with 328 additions and 185 deletions

View File

@ -73,17 +73,9 @@ If an item contains spaces, it should be surrounded by ".
<ProductID> ::= <ProductID> ::=
Google-Apps| Google-Apps|
Google-Chrome-Device-Management| Google-Chrome-Device-Management|
Google-Coordinate|
Google-Drive-storage| Google-Drive-storage|
Google-Vault| Google-Vault|
101001|101005|101031 101001|101005|101031|101033|101034
<ProductID> ::=
Google-Apps|
Google-Chrome-Device-Management|
Google-Coordinate|
Google-Drive-storage|
Google-Vault|
101001|101005|101006|101031|101033|101034
<SKUID> ::= <SKUID> ::=
cloudidentity|identity|1010010001| cloudidentity|identity|1010010001|
cloudidentitypremium|identitypremium|1010050001| cloudidentitypremium|identitypremium|1010050001|
@ -103,7 +95,6 @@ If an item contains spaces, it should be surrounded by ".
gsbau|businessarchived|gsuitebusinessarchived| gsbau|businessarchived|gsuitebusinessarchived|
gseau|enterprisearchived|gsuiteenterprisearchived| gseau|enterprisearchived|gsuiteenterprisearchived|
chrome|cdm|googlechromedevicemanagement|Google-Chrome-Device-Management| chrome|cdm|googlechromedevicemanagement|Google-Chrome-Device-Management|
coordinate|googlecoordinate|Google-Coordinate|
wsess|workspaceesentials|gsuiteessentials|essentials|d4e|driveenterprise|drive4enterprise|1010060001| wsess|workspaceesentials|gsuiteessentials|essentials|d4e|driveenterprise|drive4enterprise|1010060001|
wsentess|workspaceenterpriseessentials|1010060003| wsentess|workspaceenterpriseessentials|1010060003|
drive20gb|20gb|googledrivestorage20gb|Google-Drive-storage-20GB| drive20gb|20gb|googledrivestorage20gb|Google-Drive-storage-20GB|
@ -209,10 +200,6 @@ If an item contains spaces, it should be surrounded by ".
<ParameterValue> ::= <String> <ParameterValue> ::= <String>
<Password> ::= <String> <Password> ::= <String>
<PermissionID> ::= id:<String>|<EmailAddress>|anyone|anyonewithlink <PermissionID> ::= id:<String>|<EmailAddress>|anyone|anyonewithlink
<PrinterID> ::= <String>
<PrintJobAge> ::= <Number>[m|h|d]
<PrintJobID> ::= <String>
<PrintJobStatus> ::= done|error|held|in_progress|queued|submitted
<PropertyKey> ::= <String> <PropertyKey> ::= <String>
<PropertyValue> ::= <String> <PropertyValue> ::= <String>
<QueryCalendar> ::= <String> <QueryCalendar> ::= <String>
@ -222,7 +209,6 @@ If an item contains spaces, it should be surrounded by ".
<QueryGmail> ::= <String> See: https://support.google.com/mail/answer/7190 <QueryGmail> ::= <String> See: https://support.google.com/mail/answer/7190
<QueryGroup> ::= <String> See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups <QueryGroup> ::= <String> See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups
<QueryMobile> ::= <String> See: https://support.google.com/a/answer/7549103 <QueryMobile> ::= <String> See: https://support.google.com/a/answer/7549103
<QueryPrinter> ::= <String> See: https://developers.google.com/cloud-print/docs/appInterfaces#search
<QueryPrintJob> ::= <String> See: https://developers.google.com/cloud-print/docs/appInterfaces#parameters_3 <QueryPrintJob> ::= <String> See: https://developers.google.com/cloud-print/docs/appInterfaces#parameters_3
<QueryUser> ::= <String> See: https://developers.google.com/admin-sdk/directory/v1/guides/search-users <QueryUser> ::= <String> See: https://developers.google.com/admin-sdk/directory/v1/guides/search-users
<QueryVaultCorpus> ::= <String> See: https://developers.google.com/vault/reference/rest/v1/matters.holds#CorpusQuery <QueryVaultCorpus> ::= <String> See: https://developers.google.com/vault/reference/rest/v1/matters.holds#CorpusQuery
@ -594,12 +580,10 @@ Items, separated by spaces, with spaces, commas or single quotes in the items th
<MembersFieldNameList> ::= "<MembersFieldName>(,<MembersFieldName>)*" <MembersFieldNameList> ::= "<MembersFieldName>(,<MembersFieldName>)*"
<MobileList> ::= "<MobileId>(,<MobileId>)*" <MobileList> ::= "<MobileId>(,<MobileId>)*"
<OrgUnitList> ::= "<OrgUnitPath>(,<OrgUnitPath>)*" <OrgUnitList> ::= "<OrgUnitPath>(,<OrgUnitPath>)*"
<PrinterIDList> ::= "<PrinterID>(,<PrinterID>)*"
<ProductIDList> ::= "(<ProductID>|SKUID>)(,<ProductID>|SKUID>)*" <ProductIDList> ::= "(<ProductID>|SKUID>)(,<ProductID>|SKUID>)*"
<PrintJobIDList> ::= "<PrintJobID>(,<PrintJobID>)*" <PrintJobIDList> ::= "<PrintJobID>(,<PrintJobID>)*"
<QueryCrOSList> ::= "<QueryCrOS>(,<QueryCrOS>)*" <QueryCrOSList> ::= "<QueryCrOS>(,<QueryCrOS>)*"
<QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*" <QueryMobileList> ::= "<QueryMobile>(,<QueryMobile>)*"
<QueryPrinterList> ::= "<QueryPrinter>(,<QueryPrinter>)*"
<QueryUserList> ::= "<QueryUser>(,<QueryUser>)*" <QueryUserList> ::= "<QueryUser>(,<QueryUser>)*"
<ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*" <ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*"
<SKUIDList> ="<SKUID>(,<SKUID>)*" <SKUIDList> ="<SKUID>(,<SKUID>)*"
@ -653,7 +637,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
## Item attributes ## Item attributes
<BuildingAttributes> ::= <BuildingAttribute> ::=
(description <String>)| (description <String>)|
(floors <FloorNameList>)| (floors <FloorNameList>)|
(id <String>)| (id <String>)|
@ -661,7 +645,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
(longitude <Float>)| (longitude <Float>)|
(name <String>) (name <String>)
<CalendarAttributes> ::= <CalendarAttribute> ::=
(selected <Boolean>)|(hidden <Boolean>)|(summary <String>)|(colorindex|colorid <CalendarColorIndex>)|(backgroundcolor <ColorValue>)|(foregroundcolor <ColorValue>)| (selected <Boolean>)|(hidden <Boolean>)|(summary <String>)|(colorindex|colorid <CalendarColorIndex>)|(backgroundcolor <ColorValue>)|(foregroundcolor <ColorValue>)|
(reminder clear|(email|sms|pop <Number>))| (reminder clear|(email|sms|pop <Number>))|
(notification clear|(email|sms eventcreation|eventchange|eventcancellation|eventresponse|agenda)) (notification clear|(email|sms eventcreation|eventchange|eventcancellation|eventresponse|agenda))
@ -669,7 +653,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
<CalendarSettings> ::= <CalendarSettings> ::=
(summary <String>)|(description <String>)|(location <String>)|(timezone <TimeZone>) (summary <String>)|(description <String>)|(location <String>)|(timezone <TimeZone>)
<CourseAttributes> ::= <CourseAttribute> ::=
(description <String>)| (description <String>)|
(heading <String>)| (heading <String>)|
(name <String>)| (name <String>)|
@ -678,14 +662,18 @@ Specify a collection of Users by directly specifying them or by specifiying item
(state|status <CourseState>)| (state|status <CourseState>)|
(owner|ownerid|teacher <UserItem>) (owner|ownerid|teacher <UserItem>)
<CrOSAttributes> ::= <CrOSAttribute> ::=
(asset|assetid|tag <String>)| (asset|assetid|tag <String>)|
(location <String>)| (location <String>)|
(notes <String>)| (notes <String>)|
(org|ou <OrgUnitPath>)| (org|ou <OrgUnitPath>)|
(user <Name>) (user <Name>)
<DriveFileAddAttributes> ::= <CIGroupAttribute> ::=
(description <String>)|
(name <String>)
<DriveFileAddAttribute> ::=
(localfile <FileName>)| (localfile <FileName>)|
(convert)|(ocr)|(ocrlanguage <Language>)| (convert)|(ocr)|(ocrlanguage <Language>)|
(restricted|restrict)|(starred|star)|(trashed|trash)|(viewed|view)| (restricted|restrict)|(starred|star)|(trashed|trash)|(viewed|view)|
@ -695,7 +683,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
(lastviewedbyme <Time>)|(modifieddate|modifiedtime <Time>)|(description <String>)|(mimetype <MimeType>)| (lastviewedbyme <Time>)|(modifieddate|modifiedtime <Time>)|(description <String>)|(mimetype <MimeType>)|
(parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|writerscantshare| (parentid <DriveFolderID>)|(parentname <DriveFolderName>)|(anyownerparentname <DriveFolderName>)|writerscantshare|
(shortcut <DriveFileID>) (shortcut <DriveFileID>)
<DriveFileUpdateAttributes> ::= <DriveFileUpdateAttribute> ::=
(localfile <FileName>)| (localfile <FileName>)|
(convert)|(ocr)|(ocrlanguage <Language>)| (convert)|(ocr)|(ocrlanguage <Language>)|
(restricted|restrict <Boolean>)|(starred|star <Boolean>)|(trashed|trash <Boolean>)|(viewed|view <Boolean>)| (restricted|restrict <Boolean>)|(starred|star <Boolean>)|(trashed|trash <Boolean>)|(viewed|view <Boolean>)|
@ -773,13 +761,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
<MobileAction> ::= <MobileAction> ::=
admin_remote_wipe|wipe|admin_account_wipe|accountwipe|wipeaccount|approve|block|cancel_remote_wipe_then_activate|cancel_remote_wipe_then_block admin_remote_wipe|wipe|admin_account_wipe|accountwipe|wipeaccount|approve|block|cancel_remote_wipe_then_activate|cancel_remote_wipe_then_block
<PrinterAttributes> ::= (currentquota <Number>)|(dailyquota <Number>)| <ResourceAttribute> ::=
(defaultdisplayname <String>)|(description <String>)|(displayname <String>)|(firmware <String>)|(gcpversion <String>)|
(istosaccepted <Boolean>)|(manufacturer <String>)|(model <String>)|(name <String>)|(ownerid <EmailAddress>)|(proxy <String>)|(public <Boolean>)|
(quotaenabled <Boolean>)|(status <Number>)|(type <String>)|(uuid <String>)|
(setupurl <URL>)|(supporturl <URL>)|(updateurl <URL>)
<ResourceAttributes> ::=
(buildingid <BuildingID>)| (buildingid <BuildingID>)|
(capacity <Number>)| (capacity <Number>)|
(category other|room|conference_room|category_unknown)| (category other|room|conference_room|category_unknown)|
@ -813,7 +795,7 @@ Specify a collection of Users by directly specifying them or by specifiying item
(recoveryphone <string>)| (recoveryphone <string>)|
(suspended <Boolean>)| (suspended <Boolean>)|
(<SchemaName>.<FieldName> [multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]] <String>) (<SchemaName>.<FieldName> [multivalued|multivalue|value|multinonempty [type home|other|work|(custom <String>)]] <String>)
<UserMultiAttributes> ::= <UserMultiAttribute> ::=
(address clear|(type home|other|work|(custom <String>) [unstructured|formatted <String>] [pobox <String>] [extendedaddress <String>] [streetaddress <String>] (address clear|(type home|other|work|(custom <String>) [unstructured|formatted <String>] [pobox <String>] [extendedaddress <String>] [streetaddress <String>]
[locality <String>] [region <String>] [postalcode <String>] [country <String>] [countrycode <String>] notprimary|primary))| [locality <String>] [region <String>] [postalcode <String>] [country <String>] [countrycode <String>] notprimary|primary))|
(otheremail clear|(home|other|work|<String> <String>))| (otheremail clear|(home|other|work|<String> <String>))|
@ -872,7 +854,7 @@ gam <UserTypeEntity> check serviceaccount [scope|scopes <APIScopeURLList>]
gam whatis <EmailItem> gam whatis <EmailItem>
<ResoldCustomerAttributes> ::= <ResoldCustomerAttribute> ::=
(email|alternateemail <EmailAddress>)| (email|alternateemail <EmailAddress>)|
(contact|contactname <String>)| (contact|contactname <String>)|
(phone|phonenumber <String>)| (phone|phonenumber <String>)|
@ -885,7 +867,7 @@ gam whatis <EmailItem>
(zipcode|postal|postalcode <String>)| (zipcode|postal|postalcode <String>)|
(country|countrycode <String>) (country|countrycode <String>)
gam create resoldcustomer <CustomerDomain> (customer_auth_token <String>) <ResoldCustomerAttributes>+ gam create resoldcustomer <CustomerDomain> (customer_auth_token <String>) <ResoldCustomerAttribute>+
gam update resoldcustomer <CustomerID> [customer_auth_token <String>] <ResoldCustomerAttribues>+ gam update resoldcustomer <CustomerID> [customer_auth_token <String>] <ResoldCustomerAttribues>+
gam info resoldcustomer <CustomerID> gam info resoldcustomer <CustomerID>
@ -976,7 +958,7 @@ gam delete domainalias|aliasdomain <DomainAlias>
gam info domainalias|aliasdomain <DomainAlias> gam info domainalias|aliasdomain <DomainAlias>
gam print domainaliases|aliasdomains [todrive] gam print domainaliases|aliasdomains [todrive]
<CustomerAttributes> ::= <CustomerAttribute> ::=
(primary <DomainName>)| (primary <DomainName>)|
(adminsecondaryemail|alternateemail <EmailAddress>)| (adminsecondaryemail|alternateemail <EmailAddress>)|
(contact|contactname <String>)| (contact|contactname <String>)|
@ -991,7 +973,7 @@ gam print domainaliases|aliasdomains [todrive]
(zipcode|postal|postalcode <String>)| (zipcode|postal|postalcode <String>)|
(country|countrycode <String>) (country|countrycode <String>)
gam update customer <CustomerAttributes>* gam update customer <CustomerAttribute>*
gam info customer gam info customer
@ -1034,7 +1016,7 @@ The following attributes are equivalent:
sendnotifications false - sendupdates none sendnotifications false - sendupdates none
sendnotifications true - sendupdates all sendnotifications true - sendupdates all
<EventAttributes> ::= <EventAttribute> ::=
anyonecanaddself| anyonecanaddself|
(attendee <EmailAddress>)| (attendee <EmailAddress>)|
available| available|
@ -1060,8 +1042,8 @@ The following attributes are equivalent:
(timezone <Timezone>)| (timezone <Timezone>)|
(visibility default|public|prvate) (visibility default|public|prvate)
<EventUpdateAttributes> ::= <EventUpdateAttribute> ::=
<EventAttributes>| <EventAttribute>|
(removeattendee <EmailAddress>)| (removeattendee <EmailAddress>)|
(replacedescription <RegularExpression> <String>) (replacedescription <RegularExpression> <String>)
@ -1076,10 +1058,10 @@ The following attributes are equivalent:
<EventDisplayProperty> ::= <EventDisplayProperty> ::=
(timezone <TimeZone>) (timezone <TimeZone>)
gam calendar <CalendarItem> addevent [id <String>] <EventAttributes>+ [<EventNotificationAttribute>] gam calendar <CalendarItem> addevent [id <String>] <EventAttribute>+ [<EventNotificationAttribute>]
gam calendar <CalendarItem> deleteevent id|eventid <EventID> [doit] [<EventNotificationAttribute>] gam calendar <CalendarItem> deleteevent id|eventid <EventID> [doit] [<EventNotificationAttribute>]
gam calendar <CalendarItem> moveevent id|eventid <EventID> [doit] [<EventNotificationAttribute>] gam calendar <CalendarItem> moveevent id|eventid <EventID> [doit] [<EventNotificationAttribute>]
gam calendar <CalendarItem> updateevent <EventID> <EventUpdateAttributes>+ [<EventNotificationAttribute>] gam calendar <CalendarItem> updateevent <EventID> <EventUpdateAttribute>+ [<EventNotificationAttribute>]
gam calendar <CalendarItem> wipe gam calendar <CalendarItem> wipe
gam calendar <CalendarItem> printevents <EventSelectProperty>* <EventDisplayProperty>* [todrive] gam calendar <CalendarItem> printevents <EventSelectProperty>* <EventDisplayProperty>* [todrive]
@ -1099,7 +1081,19 @@ gam calendar <CalendarItem> modify <CalendarSettings>+
disable| disable|
reenable reenable
gam update cros <CrOSEntity> (<CrOSAttributes>+)|(action <CrOSAction> [acknowledge_device_touch_requirement]) gam update cros <CrOSEntity> action <CrOSAction> [acknowledge_device_touch_requirement]
<CrOSCommand>
wipe_users|
remote_powerwash|
reboot|
set_volume <0-100>|
take_a_screenshot
gam issuecommand cros <CrOSEntity> command <CrOSCommand> [times_to_check_status <0-1000+>] [doit]
gam getcommand cros <CrOSEntity> commandid <CommandID> [times_to_check_status <0-1000+>]
gam update cros <CrOSEntity> <CrOSAttribute>+
gam info cros <CrOSEntity> [nolists] [listlimit <Number>] [start <Date>] [end <Date>] gam info cros <CrOSEntity> [nolists] [listlimit <Number>] [start <Date>] [end <Date>]
[basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [downloadfile latest|<Time>] [targetfolder <FilePath>] [basic|full|allfields] <CrOSFieldName>* [fields <CrOSFieldNameList>] [downloadfile latest|<Time>] [targetfolder <FilePath>]
@ -1181,8 +1175,29 @@ gam info mobile <MobileID>
gam print mobile [todrive] [(query <QueryMobile>)|(queries <QueryMobileList>)] [basic|full] [orderby <MobileOrderByFieldName> [ascending|descending]] gam print mobile [todrive] [(query <QueryMobile>)|(queries <QueryMobileList>)] [basic|full] [orderby <MobileOrderByFieldName> [ascending|descending]]
fields <MobileFieldNameList>] [delimiter <Character>] [appslimit <Number>] [listlimit <Number>] fields <MobileFieldNameList>] [delimiter <Character>] [appslimit <Number>] [listlimit <Number>]
gam create group <EmailAddress> <GroupAttributes>* gam create cigroup <EmailAddress> <CIGroupAttribute>*
gam update group <GroupItem> [email <EmailAddress>] <GroupAttributes>* [makeowner] [alias|aliases <AliasList>] [dynamic <QueryDynamicGroup>]
gam update cigroup <GroupItem> [email <EmailAddress>] <CIGroupAttribute>* [security]
gam update cigroup <GroupItem> add [owner|manager|member] [notsuspended|suspended] [expiretime <Time>] <UserTypeEntity>
gam update cigroup <GroupItem> delete|remove [owner|manager|member] [notsuspended|suspended] <UserTypeEntity>
gam update cigroup <GroupItem> sync [owner|manager|member] [notsuspended|suspended] [expiretime <Time>] <UserTypeEntity>
gam update cigroup <GroupItem> update [owner|manager|member] [notsuspended|suspended] [expiretime <Time>] <UserTypeEntity>
gam update cigroup <GroupItem> clear [member] [manager] [owner] [notsuspended|suspended]
gam delete cigroup <GroupItem>
gam info cigroup <GroupItem> [nousers] [nojoindate] [showupdatedate]
gam print cigroups [todrive]
[enterprisemember <UserItem>]
[members|memberscount] [managers|managerscount] [owners|ownerscount]
[delimiter <Character>] [sortheaders]
gam info cimember <UserItem> <GroupItem>
gam print cigroup-members|cigroups-members [todrive]
[(enterprisemember <UserItem>)|(cigroup <GroupItem>)]
[roles <GroupRoleList>]
gam create group <EmailAddress> <GroupAttribute>*
gam update group <GroupItem> [email <EmailAddress>] <GroupAttribute>*
gam update group <GroupItem> add [owner|manager|member] [notsuspended|suspended] [allmail|daily|digest|none|nomail] <UserTypeEntity> gam update group <GroupItem> add [owner|manager|member] [notsuspended|suspended] [allmail|daily|digest|none|nomail] <UserTypeEntity>
gam update group <GroupItem> delete|remove [owner|manager|member] <UserTypeEntity> gam update group <GroupItem> delete|remove [owner|manager|member] <UserTypeEntity>
gam update group <GroupItem> sync [owner|manager|member] [notsuspended|suspended] [allmail|daily|digest|none|nomail] <UserTypeEntity> gam update group <GroupItem> sync [owner|manager|member] [notsuspended|suspended] [allmail|daily|digest|none|nomail] <UserTypeEntity>
@ -1205,8 +1220,8 @@ gam print group-members|groups-members [todrive]
gam print licenses [todrive] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)|allskus|gsuite] [countsonly] gam print licenses [todrive] [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)|allskus|gsuite] [countsonly]
gam show license|licenses|licence|licences [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)|allskus|gsuite] gam show license|licenses|licence|licences [(products|product <ProductIDList>)|(skus|sku <SKUIDList>)|allskus|gsuite]
gam create building <Name> <BuildingAttributes>* gam create building <Name> <BuildingAttribute>*
gam update building <BuildIngID> <BuildingAttributes>* gam update building <BuildIngID> <BuildingAttribute>*
gam delete building <BuildingID> gam delete building <BuildingID>
gam info building <BuildingID> gam info building <BuildingID>
gam print buildings [todrive] gam print buildings [todrive]
@ -1216,8 +1231,8 @@ gam update feature <Name> name <Name>
gam delete feature <Name> gam delete feature <Name>
gam print features [todrive] gam print features [todrive]
gam create resource <ResourceID> <Name> <ResourceAttributes>* gam create resource <ResourceID> <Name> <ResourceAttribute>*
gam update resource <ResourceID> <ResourceAttributes>* gam update resource <ResourceID> <ResourceAttribute>*
gam delete resource <ResourceID> gam delete resource <ResourceID>
gam info resource <ResourceID> gam info resource <ResourceID>
gam print resources [todrive] [allfields] <ResourceFieldName>* [query <String>] gam print resources [todrive] [allfields] <ResourceFieldName>* [query <String>]
@ -1229,8 +1244,8 @@ gam info schema <SchemaName>
gam show schema|schemas gam show schema|schemas
gam print schema|schemas gam print schema|schemas
gam create user <EmailAddress> <UserAttributes>* gam create user <EmailAddress> <UserAttribute>*
gam update user <UserItem> <UserAttributes>* [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>] gam update user <UserItem> <UserAttribute>* [clearschema <SchemaName>] [clearschema <SchemaName>.<FieldName>]
gam delete user <UserItem> gam delete user <UserItem>
gam undelete user <UserItem> [org|ou <OrgUnitPath>] gam undelete user <UserItem> [org|ou <OrgUnitPath>]
gam info user [<UserItem>] [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas|custom <SchemaNameList>] [userview] [skus|sku <SKUIDList>] gam info user [<UserItem>] [noaliases] [nogroups] [nolicenses|nolicences] [noschemas] [schemas|custom <SchemaNameList>] [userview] [skus|sku <SKUIDList>]
@ -1251,8 +1266,8 @@ gam create verify|verification <DomainName>
gam update verify|verification <DomainName> cname|txt|text|site|file gam update verify|verification <DomainName> cname|txt|text|site|file
gam info verify|verification gam info verify|verification
gam create course [id|alias <CourseAlias>] <CourseAttributes>* gam create course [id|alias <CourseAlias>] <CourseAttribute>*
gam update course <CourseID> <CourseAttributes>+ gam update course <CourseID> <CourseAttribute>+
gam delete course <CourseID> gam delete course <CourseID>
gam info course <CourseID> gam info course <CourseID>
gam print courses [todrive] [teacher <UserItem>] [student <UserItem>] [states <CourseStateList>] gam print courses [todrive] [teacher <UserItem>] [student <UserItem>] [states <CourseStateList>]
@ -1272,32 +1287,6 @@ gam show guardian|guardians [invitedguardian <EmailAddress>] [student <StudentIt
gam print guardian|guardians [todrive] [invitedguardian <EmailAddress>] [student <StudentItem>] [invitations [states <GuardianStateList>]] [<UserTypeEntity>] gam print guardian|guardians [todrive] [invitedguardian <EmailAddress>] [student <StudentItem>] [invitations [states <GuardianStateList>]] [<UserTypeEntity>]
gam cancel guardianinvitation|guardianinvitations <GuardianInvitationID> <StudentItem> gam cancel guardianinvitation|guardianinvitations <GuardianInvitationID> <StudentItem>
gam update printer <PrinterID> <PrinterAttributes>+
gam delete printer <PrinterID>
gam info printer <PrinterID> [everything]
gam print printers [todrive] [(query <QueryPrinter>)|(queries <QueryPrinterList>)] [type <String>] [status <String>] [extrafields <String>]
gam printer <PrinterID> add user|manager|owner <EmailAddress>|[domain:]<DomainName>|public [notify]
gam printer <PrinterID> delete <EmailAddress>|[domain:]<DomainName>|public
gam printer <PrinterID> showacl
gam printjob <PrintJobID> cancel
gam printjob <PrintJobID> delete
gam printjob <PrintJobID> resubmit <PrinterID>
gam printjob <PrinterID>|any fetch
[olderthan|newerthan <PrintJobAge>] [query <QueryPrintJob>]
[status <PrintJobStatus>]
[orderby <PrintJobOrderByFieldName> [ascending|descending]]
[owner|user <EmailAddress>]
[limit <Number>] [drivedir|(targetfolder <FilePath>)]
gam printjob <PrinterID> submit <FileName>|<URL> [name|title <String>] (tag <String>)*
gam print printjobs [todrive] [printer|printerid <PrinterID>]
[olderthan|newerthan <PrintJobAge>] [query <QueryPrintJob>]
[status <PrintJobStatus>]
[orderby <PrintJobOrderByFieldName> [ascending|descending]]
[owner|user <EmailAddress>]
[limit <Number>]
gam create vaultexport|export matter <MatterItem> [name <name>] corpus <drive|mail|groups|hangouts_chat> gam create vaultexport|export matter <MatterItem> [name <name>] corpus <drive|mail|groups|hangouts_chat>
(accounts <EmailAddressList>) | (orgunit|ou <OrgUnitPath>) | (teamdrives <TeamDriveList>) | (rooms <ChatRoomList>) | everyone (accounts <EmailAddressList>) | (orgunit|ou <OrgUnitPath>) | (teamdrives <TeamDriveList>) | (rooms <ChatRoomList>) | everyone
[scope <all_data|held_data|unprocessed_data>] [scope <all_data|held_data|unprocessed_data>]
@ -1340,8 +1329,8 @@ gam <UserTypeEntity> update backupcodes|backupcode|verificationcodes
gam <UserTypeEntity> delete|del backupcodes|backupcode|verificationcodes gam <UserTypeEntity> delete|del backupcodes|backupcode|verificationcodes
gam <UserTypeEntity> show backupcodes|backupcode|verificationcodes gam <UserTypeEntity> show backupcodes|backupcode|verificationcodes
gam <UserTypeEntity> add calendar <CalendarItem> <CalendarAttributes>* gam <UserTypeEntity> add calendar <CalendarItem> <CalendarAttribute>*
gam <UserTypeEntity> update calendar <CalendarItem>|primary <CalendarAttributes>+ gam <UserTypeEntity> update calendar <CalendarItem>|primary <CalendarAttribute>+
gam <UserTypeEntity> delete|del calendar <CalendarItem> gam <UserTypeEntity> delete|del calendar <CalendarItem>
gam <UserTypeEntity> show calendars gam <UserTypeEntity> show calendars
gam <UserTypeEntity> info calendar <CalendarItem>|primary gam <UserTypeEntity> info calendar <CalendarItem>|primary
@ -1360,8 +1349,8 @@ gam <UserTypeEntity> show fileinfo <DriveFileID> [allfields|<DriveFieldName>*]
gam <UserTypeEntity> show filerevisions <DriveFileID> gam <UserTypeEntity> show filerevisions <DriveFileID>
gam <UserTypeEntity> show filetree [anyowner] (orderby <DriveOrderByFieldName> [ascending|descending])* gam <UserTypeEntity> show filetree [anyowner] (orderby <DriveOrderByFieldName> [ascending|descending])*
gam <UserTypeEntity> create|add drivefile [drivefilename <DriveFileName>] <DriveFileAddAttributes>* [csv] [todrive] [returnidonly] gam <UserTypeEntity> create|add drivefile [drivefilename <DriveFileName>] <DriveFileAddAttribute>* [csv] [todrive] [returnidonly]
gam <UserTypeEntity> update drivefile (id <DriveFileID)|(drivefilename <DriveFileName>)|(query <QueryDriveFile) [copy] [newfilename <DriveFileName>] <DriveFileUpdateAttributes>* gam <UserTypeEntity> update drivefile (id <DriveFileID)|(drivefilename <DriveFileName>)|(query <QueryDriveFile) [copy] [newfilename <DriveFileName>] <DriveFileUpdateAttribute>*
gam <UserTypeEntity> get drivefile (id <DriveFileID>)|(drivefilename <DriveFileName>)|(query <QueryDriveFile>) gam <UserTypeEntity> get drivefile (id <DriveFileID>)|(drivefilename <DriveFileName>)|(query <QueryDriveFile>)
[revision <Number>] [(format <FileFormatList>)|(csvsheet <String>)] [revision <Number>] [(format <FileFormatList>)|(csvsheet <String>)]
[targetfolder <FilePath>] [targetname -|<FileName>] [overwrite] [showprogress] [targetfolder <FilePath>] [targetname -|<FileName>] [overwrite] [showprogress]
@ -1398,7 +1387,7 @@ gam <UserTypeEntity> show tokens|token [clientid <ClientID>]
gam <UserTypeEntity> print tokens|token [todrive] [clientid <ClientID>] gam <UserTypeEntity> print tokens|token [todrive] [clientid <ClientID>]
gam print tokens|token [todrive] [clientid <ClientID>] [<UserTypeEntity>] gam print tokens|token [todrive] [clientid <ClientID>] [<UserTypeEntity>]
gam <UserTypeEntity> update user <UserAttributes> gam <UserTypeEntity> update user <UserAttribute>
gam <UserTypeEntity> deprovision|deprov gam <UserTypeEntity> deprovision|deprov

View File

@ -1093,7 +1093,7 @@ def buildAlertCenterGAPIObject(user):
def buildActivityGAPIObject(user): def buildActivityGAPIObject(user):
userEmail = convertUIDtoEmailAddress(user) userEmail = convertUIDtoEmailAddress(user)
return (userEmail, buildGAPIServiceObject('appsactivity', userEmail)) return (userEmail, buildGAPIServiceObject('driveactivity', userEmail))
def buildDriveGAPIObject(user): def buildDriveGAPIObject(user):
@ -2720,7 +2720,7 @@ def deletePhoto(users):
for user in users: for user in users:
i += 1 i += 1
print(f'Deleting photo for {user}{currentCount(i, count)}') print(f'Deleting photo for {user}{currentCount(i, count)}')
gapi.call(cd.users().photos(), 'delete', userKey=user) gapi.call(cd.users().photos(), 'delete', userKey=user, soft_errors=True)
def printDriveSettings(users): def printDriveSettings(users):
@ -2788,23 +2788,58 @@ def getTeamDriveThemes(users):
def printDriveActivity(users): def printDriveActivity(users):
drive_ancestorId = 'root' def _get_user_info(user_id):
drive_fileId = None if user_id.startswith('people/'):
user_id = user_id[7:]
entry = user_info.get(user_id)
if entry is None:
result = gapi.call(cd.users(), 'get',
soft_errors=True,
userKey=user_id, fields='primaryEmail,name.fullName')
if result:
entry = (result['primaryEmail'], result['name']['fullName'])
else:
entry = (f'uid:{user_id}', 'Unknown')
user_info[user_id] = entry
return entry
def _update_known_users(structure):
if isinstance(structure, list):
for v in structure:
if isinstance(v, (dict, list)):
_update_known_users(v)
elif isinstance(structure, dict):
for k, v in sorted(iter(structure.items())):
if k != 'knownUser':
if isinstance(v, (dict, list)):
_update_known_users(v)
else:
entry = _get_user_info(v['personName'])
v['emailAddress'] = entry[0]
v['personName'] = entry[1]
break
cd = buildGAPIObject('directory')
drive_key = 'ancestorName'
drive_fileId = 'root'
user_info = {}
todrive = False todrive = False
titles = [ titles = [
'user.name', 'user.permissionId', 'target.id', 'target.name', 'user.name', 'user.emailAddress', 'target.id', 'target.name',
'target.mimeType' 'target.mimeType', 'eventTime'
] ]
sort_titles = titles[:]
csvRows = [] csvRows = []
i = 5 i = 5
while i < len(sys.argv): while i < len(sys.argv):
activity_object = sys.argv[i].lower().replace('_', '') activity_object = sys.argv[i].lower().replace('_', '')
if activity_object == 'fileid': if activity_object == 'fileid':
drive_fileId = sys.argv[i + 1] drive_fileId = sys.argv[i + 1]
drive_ancestorId = None drive_key = 'itemName'
i += 2 i += 2
elif activity_object == 'folderid': elif activity_object == 'folderid':
drive_ancestorId = sys.argv[i + 1] drive_fileId = sys.argv[i + 1]
drive_key = 'ancestorName'
i += 2 i += 2
elif activity_object == 'todrive': elif activity_object == 'todrive':
todrive = True todrive = True
@ -2812,23 +2847,57 @@ def printDriveActivity(users):
else: else:
controlflow.invalid_argument_exit(sys.argv[i], controlflow.invalid_argument_exit(sys.argv[i],
'gam <users> show driveactivity') 'gam <users> show driveactivity')
for user in users: for user in users:
user, activity = buildActivityGAPIObject(user) user, activity = buildActivityGAPIObject(user)
if not activity: if not activity:
continue continue
page_token = None
total_items = 0
kwargs = {drive_key: f'items/{drive_fileId}',
'pageToken': page_token}
page_message = gapi.got_total_items_msg(f'Activities for {user}', '') page_message = gapi.got_total_items_msg(f'Activities for {user}', '')
feed = gapi.get_all_pages(activity.activities(), while True:
'list', feed = gapi.call(activity.activity(), 'query', body=kwargs)
'activities', page_token, total_items = gapi.process_page(feed, 'activities', None, total_items, page_message, None)
page_message=page_message, kwargs['pageToken'] = page_token
source='drive.google.com', if feed:
userId='me', for activity_event in feed.get('activities', []):
drive_ancestorId=drive_ancestorId, event_row = {}
groupingStrategy='none', actors = activity_event.get('actors', [])
drive_fileId=drive_fileId) if actors:
for item in feed: userId = actors[0].get('user', {}).get('knownUser', {}).get('personName', '')
display.add_row_titles_to_csv_file( if not userId:
utils.flatten_json(item['combinedEvent']), csvRows, titles) userId = actors[0].get('impersonation', {}).get('impersonatedUser', {}).get('knownUser', {}).get('personName', '')
if userId:
entry = _get_user_info(userId)
event_row['user.name'] = entry[1]
event_row['user.emailAddress'] = entry[0]
targets = activity_event.get('targets', [])
if targets:
driveItem = targets[0].get('driveItem')
if driveItem:
event_row['target.id'] = driveItem['name'][6:]
event_row['target.name'] = driveItem['title']
event_row['target.mimeType'] = driveItem['mimeType']
else:
teamDrive = targets[0].get('teamDrive')
if teamDrive:
event_row['target.id'] = teamDrive['name'][11:]
event_row['target.name'] = teamDrive['title']
if 'timestamp' in activity_event:
event_row['eventTime'] = activity_event.pop('timestamp')
elif 'timeRange' in activity_event:
timeRange = activity_event.pop('timeRange')
event_row['eventTime'] = f'{timeRange["startTime"]}-{timeRange["endTime"]}'
_update_known_users(activity_event)
display.add_row_titles_to_csv_file(
utils.flatten_json(activity_event, flattened=event_row), csvRows, titles)
del feed
if not page_token:
gapi.finalize_page_message(page_message)
break
display.sort_csv_titles(sort_titles, titles)
display.write_csv_file(csvRows, titles, 'Drive Activity', todrive) display.write_csv_file(csvRows, titles, 'Drive Activity', todrive)
@ -3570,6 +3639,10 @@ def getDriveFileAttribute(i, body, parameters, myarg, update=False):
return i return i
def has_multiple_parents(body):
return len(body.get('parents', [])) > 1
def doUpdateDriveFile(users): def doUpdateDriveFile(users):
fileIdSelection = {'fileIds': [], 'query': None} fileIdSelection = {'fileIds': [], 'query': None}
media_body = None media_body = None
@ -3618,6 +3691,9 @@ def doUpdateDriveFile(users):
body.setdefault('parents', []) body.setdefault('parents', [])
for a_parent in more_parents: for a_parent in more_parents:
body['parents'].append({'id': a_parent}) body['parents'].append({'id': a_parent})
if has_multiple_parents(body):
sys.stderr.write(f"Multiple parents ({len(body['parents'])}) specified for {user}, only one is allowed.\n")
continue
if fileIdSelection['query']: if fileIdSelection['query']:
fileIdSelection['fileIds'] = doDriveSearch( fileIdSelection['fileIds'] = doDriveSearch(
drive, query=fileIdSelection['query']) drive, query=fileIdSelection['query'])
@ -3705,6 +3781,9 @@ def createDriveFile(users):
body.setdefault('parents', []) body.setdefault('parents', [])
for a_parent in more_parents: for a_parent in more_parents:
body['parents'].append({'id': a_parent}) body['parents'].append({'id': a_parent})
if has_multiple_parents(body):
sys.stderr.write(f"Multiple parents ({len(body['parents'])}) specified for {user}, only one is allowed.\n")
continue
if parameters[DFA_LOCALFILEPATH]: if parameters[DFA_LOCALFILEPATH]:
media_body = googleapiclient.http.MediaFileUpload( media_body = googleapiclient.http.MediaFileUpload(
parameters[DFA_LOCALFILEPATH], parameters[DFA_LOCALFILEPATH],

View File

@ -218,6 +218,61 @@ def got_total_items_first_last_msg(items):
return f'Got {TOTAL_ITEMS_MARKER} {items}: {FIRST_ITEM_MARKER} - {LAST_ITEM_MARKER}' + '\n' return f'Got {TOTAL_ITEMS_MARKER} {items}: {FIRST_ITEM_MARKER} - {LAST_ITEM_MARKER}' + '\n'
def process_page(page, items, all_items, total_items, page_message, message_attribute):
"""Process one page of a Google service function response.
Append a list of items to the aggregate list of items
Args:
page: list of items
items: see get_all_pages
all_items: aggregate list of items
total_items: length of all_items
page_message: see get_all_pages
message_attribute: get_all_pages
Returns:
The page token and total number of items
"""
if page:
page_token = page.get('nextPageToken')
page_items = page.get(items, [])
num_page_items = len(page_items)
total_items += num_page_items
if all_items is not None:
all_items.extend(page_items)
else:
page_token = None
num_page_items = 0
# Show a paging message to the user that indicates paging progress
if page_message:
show_message = page_message.replace(TOTAL_ITEMS_MARKER,
str(total_items))
if message_attribute:
first_item = page_items[0] if num_page_items > 0 else {}
last_item = page_items[-1] if num_page_items > 1 else first_item
if isinstance(message_attribute, str):
first_item = str(first_item.get(message_attribute, ''))
last_item = str(last_item.get(message_attribute, ''))
else:
for attr in message_attribute:
first_item = first_item.get(attr, {})
last_item = last_item.get(attr, {})
first_item = str(first_item)
last_item = str(last_item)
show_message = show_message.replace(FIRST_ITEM_MARKER, first_item)
show_message = show_message.replace(LAST_ITEM_MARKER, last_item)
sys.stderr.write('\r')
sys.stderr.flush()
sys.stderr.write(show_message)
return (page_token, total_items)
def finalize_page_message(page_message):
""" Issue final page_message """
if page_message and (page_message[-1] != '\n'):
sys.stderr.write('\r\n')
sys.stderr.flush()
def get_all_pages(service, def get_all_pages(service,
function, function,
items='items', items='items',
@ -274,46 +329,12 @@ def get_all_pages(service,
soft_errors=soft_errors, soft_errors=soft_errors,
throw_reasons=throw_reasons, throw_reasons=throw_reasons,
retry_reasons=retry_reasons, retry_reasons=retry_reasons,
pageToken=page_token,
**kwargs) **kwargs)
if page: page_token, total_items = process_page(page, items, all_items, total_items, page_message, message_attribute)
page_token = page.get('nextPageToken')
page_items = page.get(items, [])
num_page_items = len(page_items)
total_items += num_page_items
all_items.extend(page_items)
else:
page_token = None
num_page_items = 0
# Show a paging message to the user that indicates paging progress
if page_message:
show_message = page_message.replace(TOTAL_ITEMS_MARKER,
str(total_items))
if message_attribute:
first_item = page_items[0] if num_page_items > 0 else {}
last_item = page_items[-1] if num_page_items > 1 else first_item
if type(message_attribute) is str:
first_item = str(first_item.get(message_attribute, ''))
last_item = str(last_item.get(message_attribute, ''))
else:
for attr in message_attribute:
first_item = first_item.get(attr, {})
last_item = last_item.get(attr, {})
first_item = str(first_item)
last_item = str(last_item)
show_message = show_message.replace(FIRST_ITEM_MARKER, first_item)
show_message = show_message.replace(LAST_ITEM_MARKER, last_item)
sys.stderr.write('\r')
sys.stderr.flush()
sys.stderr.write(show_message)
if not page_token: if not page_token:
# End the paging status message and return all items. finalize_page_message(page_message)
if page_message and (page_message[-1] != '\n'):
sys.stderr.write('\r\n')
sys.stderr.flush()
return all_items return all_items
kwargs['pageToken'] = page_token
# TODO: Make this private once all execution related items that use this method # TODO: Make this private once all execution related items that use this method

View File

@ -1,3 +1,7 @@
import sys
import googleapiclient
import gam import gam
from gam.var import * from gam.var import *
from gam import controlflow from gam import controlflow
@ -160,6 +164,7 @@ def print_():
members = membersCountOnly = managers = managersCountOnly = owners = ownersCountOnly = False members = membersCountOnly = managers = managersCountOnly = owners = ownersCountOnly = False
gapi_directory_customer.setTrueCustomerId() gapi_directory_customer.setTrueCustomerId()
parent = f'customers/{GC_Values[GC_CUSTOMER_ID]}' parent = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
usemember = None
memberDelimiter = '\n' memberDelimiter = '\n'
todrive = False todrive = False
titles = [] titles = []
@ -171,6 +176,10 @@ def print_():
if myarg == 'todrive': if myarg == 'todrive':
todrive = True todrive = True
i += 1 i += 1
elif myarg == 'enterprisemember':
member = gam.convertUIDtoEmailAddress(sys.argv[i + 1], email_types=['user', 'group'])
usemember = f"member_key_id == '{member}' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels"
i += 2
elif myarg == 'delimiter': elif myarg == 'delimiter':
memberDelimiter = sys.argv[i + 1] memberDelimiter = sys.argv[i + 1]
i += 2 i += 2
@ -222,16 +231,36 @@ def print_():
display.add_titles_to_csv_file([ display.add_titles_to_csv_file([
'Owners', 'Owners',
], titles) ], titles)
gam.printGettingAllItems('Groups', None) gam.printGettingAllItems('Groups', usemember)
page_message = gapi.got_total_items_first_last_msg('Groups') page_message = gapi.got_total_items_first_last_msg('Groups')
entityList = gapi.get_all_pages(ci.groups(), if usemember:
'list', try:
'groups', result = gapi.get_all_pages(ci.groups().memberships(),
page_message=page_message, 'searchTransitiveGroups',
message_attribute=['groupKey', 'id'], 'memberships',
parent=parent, throw_reasons=[gapi_errors.ErrorReason.FOUR_O_O],
view='FULL', page_message=page_message,
pageSize=500) message_attribute=['groupKey', 'id'],
parent='groups/-', query=usemember,
fields='nextPageToken,memberships(group,groupKey(id),relationType)',
pageSize=1000)
except googleapiclient.errors.HttpError:
controlflow.system_error_exit(
2,
f'enterprisemember requires Enterprise license')
entityList = []
for entity in result:
if entity['relationType'] == 'DIRECT':
entityList.append(gapi.call(ci.groups(), 'get', name=entity['group']))
else:
entityList = gapi.get_all_pages(ci.groups(),
'list',
'groups',
page_message=page_message,
message_attribute=['groupKey', 'id'],
parent=parent,
view='FULL',
pageSize=500)
i = 0 i = 0
count = len(entityList) count = len(entityList)
for groupEntity in entityList: for groupEntity in entityList:
@ -319,6 +348,7 @@ def print_members():
todrive = False todrive = False
gapi_directory_customer.setTrueCustomerId() gapi_directory_customer.setTrueCustomerId()
parent = f'customers/{GC_Values[GC_CUSTOMER_ID]}' parent = f'customers/{GC_Values[GC_CUSTOMER_ID]}'
usemember = None
roles = [] roles = []
titles = ['group'] titles = ['group']
csvRows = [] csvRows = []
@ -339,6 +369,10 @@ def print_members():
f'{role} is not a valid role for "gam print group-members {myarg}"' f'{role} is not a valid role for "gam print group-members {myarg}"'
) )
i += 2 i += 2
elif myarg == 'enterprisemember':
member = gam.convertUIDtoEmailAddress(sys.argv[i + 1], email_types=['user', 'group'])
usemember = f"member_key_id == '{member}' && 'cloudidentity.googleapis.com/groups.discussion_forum' in labels"
i += 2
elif myarg in ['cigroup', 'cigroups']: elif myarg in ['cigroup', 'cigroups']:
group_email = gam.normalizeEmailAddressOrUID(sys.argv[i + 1]) group_email = gam.normalizeEmailAddressOrUID(sys.argv[i + 1])
groups_to_get = [group_email] groups_to_get = [group_email]
@ -347,19 +381,36 @@ def print_members():
controlflow.invalid_argument_exit(sys.argv[i], controlflow.invalid_argument_exit(sys.argv[i],
'gam print cigroup-members') 'gam print cigroup-members')
if not groups_to_get: if not groups_to_get:
gam.printGettingAllItems('Groups', None) gam.printGettingAllItems('Groups', usemember)
page_message = gapi.got_total_items_first_last_msg('Groups') page_message = gapi.got_total_items_first_last_msg('Groups')
groups_to_get = gapi.get_all_pages( if usemember:
ci.groups(), try:
'list', groups_to_get = gapi.get_all_pages(ci.groups().memberships(),
'groups', 'searchTransitiveGroups',
message_attribute=['groupKey', 'id'], 'memberships',
page_message=page_message, throw_reasons=[gapi_errors.ErrorReason.FOUR_O_O],
parent=parent, message_attribute=['groupKey', 'id'],
view='BASIC', page_message=page_message,
pageSize=1000, parent='groups/-', query=usemember,
fields='nextPageToken,groups(groupKey(id))') pageSize=1000,
groups_to_get = [group['groupKey']['id'] for group in groups_to_get] fields='nextPageToken,memberships(groupKey(id),relationType)')
except googleapiclient.errors.HttpError:
controlflow.system_error_exit(
2,
f'enterprisemember requires Enterprise license')
groups_to_get = [group['groupKey']['id'] for group in groups_to_get if group['relationType'] == 'DIRECT']
else:
groups_to_get = gapi.get_all_pages(
ci.groups(),
'list',
'groups',
message_attribute=['groupKey', 'id'],
page_message=page_message,
parent=parent,
view='BASIC',
pageSize=1000,
fields='nextPageToken,groups(groupKey(id))')
groups_to_get = [group['groupKey']['id'] for group in groups_to_get]
i = 0 i = 0
count = len(groups_to_get) count = len(groups_to_get)
for group_email in groups_to_get: for group_email in groups_to_get:

View File

@ -16,11 +16,22 @@ from gam.gapi.directory import orgunits as gapi_directory_orgunits
from gam import utils from gam import utils
def _display_cros_command_result(cd, device_id, command_id, times_to_check_status):
print(f'deviceId: {device_id}, commandId: {command_id}')
final_states = {'EXPIRED', 'CANCELLED', 'EXECUTED_BY_CLIENT'}
for _ in range(0, times_to_check_status):
time.sleep(2)
result = gapi.call(cd.customer().devices().chromeos().commands(), 'get',
customerId=GC_Values[GC_CUSTOMER_ID], deviceId=device_id,
commandId=command_id)
display.print_json(result)
if result.get('state') in final_states:
return
def issue_command(): def issue_command():
cd = gapi_directory.build() cd = gapi_directory.build()
i, devices = getCrOSDeviceEntity(3, cd) i, devices = getCrOSDeviceEntity(3, cd)
body = {} body = {}
final_states = ['EXPIRED', 'CANCELLED', 'EXECUTED_BY_CLIENT']
valid_commands = gapi.get_enum_values_minus_unspecified( valid_commands = gapi.get_enum_values_minus_unspecified(
cd._rootDesc['schemas'] cd._rootDesc['schemas']
['DirectoryChromeosdevicesIssueCommandRequest'] ['DirectoryChromeosdevicesIssueCommandRequest']
@ -68,36 +79,28 @@ def issue_command():
except googleapiclient.errors.HttpError: except googleapiclient.errors.HttpError:
controlflow.system_error_exit(4, '400 response from Google. This ' \ controlflow.system_error_exit(4, '400 response from Google. This ' \
'usually indicates the devices was not in a state where it will' \ 'usually indicates the devices was not in a state where it will' \
' accept the command. For example, reboot and take_a_screenshot' \ ' accept the command. For example, reboot, set_volume and take_a_screenshot' \
' require the device to be in auto-start kiosk app mode.') ' require the device to be in auto-start kiosk app mode.')
display.print_json(result)
command_id = result.get('commandId') command_id = result.get('commandId')
for i in range(0, times_to_check_status): _display_cros_command_result(cd, device_id, command_id, times_to_check_status)
time.sleep(2)
result = gapi.call(cd.customer().devices().chromeos().commands(), 'get',
customerId=GC_Values[GC_CUSTOMER_ID], deviceId=device_id,
commandId=command_id)
display.print_json(result)
state = result.get('state')
if state in final_states:
break
def get_command(): def get_command():
cd = gapi_directory.build() cd = gapi_directory.build()
i, devices = getCrOSDeviceEntity(3, cd) i, devices = getCrOSDeviceEntity(3, cd)
command_id = None command_id = None
times_to_check_status = 1
while i < len(sys.argv): while i < len(sys.argv):
myarg = sys.argv[i].lower().replace('_', '') myarg = sys.argv[i].lower().replace('_', '')
if myarg == 'commandid': if myarg == 'commandid':
command_id = sys.argv[i+1] command_id = sys.argv[i+1]
i += 2 i += 2
elif myarg == 'timestocheckstatus':
times_to_check_status = int(sys.argv[i+1])
i += 2
else: else:
controlflow.invalid_argument_exit(sys.argv[i], 'gam getcommand cros') controlflow.invalid_argument_exit(sys.argv[i], 'gam getcommand cros')
for device_id in devices: for device_id in devices:
result = gapi.call(cd.customer().devices().chromeos().commands(), 'get', _display_cros_command_result(cd, device_id, command_id, times_to_check_status)
customerId=GC_Values[GC_CUSTOMER_ID], deviceId=device_id,
commandId=command_id)
display.print_json(result)
def doUpdateCros(): def doUpdateCros():
cd = gapi_directory.build() cd = gapi_directory.build()

View File

@ -11,6 +11,7 @@ from gam import display
from gam import fileutils from gam import fileutils
from gam import gapi from gam import gapi
from gam.gapi import storage as gapi_storage from gam.gapi import storage as gapi_storage
from gam.gapi.directory import orgunits as gapi_directory_orgunits
from gam import utils from gam import utils
@ -131,7 +132,7 @@ def createExport():
i += 2 i += 2
elif searchMethod == 'ORG_UNIT': elif searchMethod == 'ORG_UNIT':
body['query']['orgUnitInfo'] = { body['query']['orgUnitInfo'] = {
'orgUnitId': gam.getOrgUnitId(sys.argv[i + 1])[1] 'orgUnitId': gapi_directory_orgunits.getOrgUnitId(sys.argv[i + 1])[1]
} }
i += 2 i += 2
elif searchMethod == 'SHARED_DRIVE': elif searchMethod == 'SHARED_DRIVE':
@ -301,7 +302,7 @@ def createHold():
i += 2 i += 2
elif myarg in ['orgunit', 'ou']: elif myarg in ['orgunit', 'ou']:
body['orgUnit'] = { body['orgUnit'] = {
'orgUnitId': gam.getOrgUnitId(sys.argv[i + 1])[1] 'orgUnitId': gapi_directory_orgunits.getOrgUnitId(sys.argv[i + 1])[1]
} }
i += 2 i += 2
elif myarg in ['start', 'starttime']: elif myarg in ['start', 'starttime']:
@ -407,7 +408,7 @@ def getHoldInfo():
acct_email = gam.convertUIDtoEmailAddress(uid, cd, [account_type]) acct_email = gam.convertUIDtoEmailAddress(uid, cd, [account_type])
results['accounts'][i]['email'] = acct_email results['accounts'][i]['email'] = acct_email
if 'orgUnit' in results: if 'orgUnit' in results:
results['orgUnit']['orgUnitPath'] = gam.doGetOrgInfo( results['orgUnit']['orgUnitPath'] = gapi_directory_orgunits.info(
results['orgUnit']['orgUnitId'], return_attrib='orgUnitPath') results['orgUnit']['orgUnitId'], return_attrib='orgUnitPath')
display.print_json(results) display.print_json(results)
@ -496,7 +497,7 @@ def updateHold():
i += 2 i += 2
elif myarg in ['orgunit', 'ou']: elif myarg in ['orgunit', 'ou']:
body['orgUnit'] = { body['orgUnit'] = {
'orgUnitId': gam.getOrgUnitId(sys.argv[i + 1])[1] 'orgUnitId': gapi_directory_orgunits.getOrgUnitId(sys.argv[i + 1])[1]
} }
i += 2 i += 2
elif myarg in ['start', 'starttime']: elif myarg in ['start', 'starttime']:

View File

@ -233,7 +233,6 @@ PRODUCTID_NAME_MAPPINGS = {
'101034': 'G Suite Archived', '101034': 'G Suite Archived',
'Google-Apps': 'Google Workspace', 'Google-Apps': 'Google Workspace',
'Google-Chrome-Device-Management': 'Google Chrome Device Management', 'Google-Chrome-Device-Management': 'Google Chrome Device Management',
'Google-Coordinate': 'Google Coordinate',
'Google-Drive-storage': 'Google Drive Storage', 'Google-Drive-storage': 'Google Drive Storage',
'Google-Vault': 'Google Vault', 'Google-Vault': 'Google Vault',
} }
@ -241,7 +240,6 @@ PRODUCTID_NAME_MAPPINGS = {
# Legacy APIs that use v1 discovery. Newer APIs should all use v2. # Legacy APIs that use v1 discovery. Newer APIs should all use v2.
V1_DISCOVERY_APIS = { V1_DISCOVERY_APIS = {
'admin', 'admin',
'appsactivity',
'calendar', 'calendar',
'drive', 'drive',
'oauth2', 'oauth2',
@ -260,7 +258,7 @@ API_NAME_MAPPING = {
API_VER_MAPPING = { API_VER_MAPPING = {
'alertcenter': 'v1beta1', 'alertcenter': 'v1beta1',
'appsactivity': 'v1', 'driveactivity': 'v2',
'calendar': 'v3', 'calendar': 'v3',
'cbcm': 'v1.1beta1', 'cbcm': 'v1.1beta1',
'classroom': 'v1', 'classroom': 'v1',
@ -293,8 +291,8 @@ USERINFO_EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
API_SCOPE_MAPPING = { API_SCOPE_MAPPING = {
'alertcenter': ['https://www.googleapis.com/auth/apps.alerts',], 'alertcenter': ['https://www.googleapis.com/auth/apps.alerts',],
'appsactivity': [ 'driveactivity': [
'https://www.googleapis.com/auth/activity', 'https://www.googleapis.com/auth/drive.activity',
'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive',
], ],
'calendar': ['https://www.googleapis.com/auth/calendar',], 'calendar': ['https://www.googleapis.com/auth/calendar',],
@ -907,6 +905,7 @@ CROS_ARGUMENT_TO_PROPERTY_MAP = {
'ethernetmacaddress0': ['ethernetMacAddress0',], 'ethernetmacaddress0': ['ethernetMacAddress0',],
'firmwareversion': ['firmwareVersion',], 'firmwareversion': ['firmwareVersion',],
'lastenrollmenttime': ['lastEnrollmentTime',], 'lastenrollmenttime': ['lastEnrollmentTime',],
'lastknownnetwork': ['lastKnownNetwork'],
'lastsync': ['lastSync',], 'lastsync': ['lastSync',],
'location': ['annotatedLocation',], 'location': ['annotatedLocation',],
'macaddress': ['macAddress',], 'macaddress': ['macAddress',],