Updates for API changes

Updated `gam <CrOSTypeEntity> update action <CrOSAction>` to use the new API function `batchChangeStatus`

Updated `gam create vaultexport matter <MatterItem>` to support `corpus calendar`.
This commit is contained in:
Ross Scroggs
2023-12-22 19:38:06 -08:00
parent ae46ae8738
commit 0d9c6a77b6
10 changed files with 218 additions and 91 deletions

View File

@@ -160,8 +160,10 @@ The second form is backwards compatible with Standard GAM and selection with `<C
```
<CrOSAction> ::=
deprovision_different_model_replace|
deprovision_different_model_replacement|
deprovision_retiring_device|
deprovision_same_model_replace|
deprovision_same_model_replacement|
deprovision_upgrade_transfer|
disable|
reenable|
@@ -403,13 +405,15 @@ gam update ou csvkmd cros.csv keyfield OU datafield deviceId add croscsvdata dev
deprovision_same_model_replace|
deprovision_upgrade_transfer|
disable|
reenable|
pre_provisioned_disable|
pre_provisioned_reenable
reenable
gam <CrOSTypeEntity> update action <CrOSAction> [acknowledge_device_touch_requirement]
[actionbatchsize <Integer>]
gam update cros <CrOSEntity> action <CrOSAction> [acknowledge_device_touch_requirement]
[actionbatchsize <Integer>]
```
As of GAM version `6.67.00`, the new API function `batchChangeStatus` 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.
As deprovisioning ChromeOS devices is not reversible, you must enter `acknowledge_device_touch_requirement`
when `<CrOSAction>` is `deprovision_same_model_replace`, `deprovision_different_model_replace`,

View File

@@ -10,6 +10,15 @@ 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
### 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)

View File

@@ -334,7 +334,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$ ./gam version
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
GAMADV-XTD3 6.66.16 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.67.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.10.8 64-bit final
MacOS High Sierra 10.13.6 x86_64
@@ -1002,7 +1002,7 @@ writes the credentials into the file oauth2.txt.
C:\GAMADV-XTD3>del C:\GAMConfig\oauth2.txt
C:\GAMADV-XTD3>gam version
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
GAMADV-XTD3 6.66.16 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.67.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final
Windows-10-10.0.17134 AMD64

View File

@@ -333,6 +333,9 @@ Select the users for whom information is desired.
* `showorgunit` - Add a column labelled `orgUnitPath` to the output; an additional API call is made to get the email addresses of the users in `<OrgUnitPath>`
* `select <UserTypeEntity>` - A selected collection of users, e.g., `select group staff@domain.com`; there is one API call per user
By default, when `user all` is specified (or no user specification in supplied), GAM backs up looking for data with a (basically) random user. If the randaom
doesn't have any data, the command reports that no data was found. Use `allverifyuser <UserItem>` to specify a specific user to use to search for data.
Specify the report date; the default is today's date.
* `date <Date>` - A single date; there is one API call
* `range <Date> <Date>` - A range of dates; there is an API call per date

View File

@@ -37,6 +37,7 @@
## Definitions
```
<AttendeeStatus> ::= accepted|declined|needsaction|tentative
<EmailItem> ::= <EmailAddress>|<UniqueID>|<String>
<EmailItemList> ::= "<EmailItem>(,<EmailItem>)*"
<EmailAddressList> ::= "<EmailAddess>(,<EmailAddress>)*"
@@ -192,12 +193,9 @@ This command can be useful for discovering legacy former employee accounts which
gam print vaultcounts [todrive <ToDriveAttributes>*]
matter <MatterItem> corpus mail|groups
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
[scope <all_data|held_data|unprocessed_data>]
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
[excludedrafts <Boolean>]
[includerooms <Boolean>]
[includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>]
[wait <Integer>]
```
Check the status of a previous count operation with the name from a previous command.
@@ -210,16 +208,18 @@ gam print vaultcounts [todrive <ToDriveAttributes>*]
## Create Vault Exports
Create a Google Vault export request.
```
gam create vaultexport|export matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat|voice
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
[scope <all_data|held_data|unprocessed_data>]
[scope all_data|held_data|unprocessed_data]
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
[includerooms <Boolean>]
[excludedrafts <Boolean>] [format mbox|pst]
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>]
[includerooms <Boolean>]
[covereddata calllogs|textmessages|voicemails]
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
[region any|europe|us] [showdetails|returnidonly]
```
<MatterItem> specifies the matter name or ID the export should be associated with.
@@ -228,7 +228,8 @@ Specify the name of the export:
* `name <String>` - The export will be named `<String>`
* `default` - The export will be named `GAM <corpus> Export - <Time>`
Specify the corpus of data, this option is required::
Specify the corpus of data, this option is required:
* `calendar`
* `drive`
* `mail`
* `groups`
@@ -247,11 +248,36 @@ Specify the scope of data to include in the export:
* `held_data` - Data on Hold
* `unprocessed_data` - Data not processed
You can specify search terms to limit the scope of data:
* `terms <String>` - [Vault search](https://support.google.com/vault/answer/2474474)
Specify time limits on the scope of data:
* `start|starttime <Date>|<Time>` - The start time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
* `end|endtime <Date>|<Time>` - The end time range for the search query. These timestamps are in GMT and rounded down to the start of the given date.
* `timezone <TimeZone>` - The time zone name. It should be an IANA TZ name, such as "America/Los_Angeles"
For `corpus calendar`, you can specify advanced search options:
* `locationquery <StringList>`
* Matches only those events whose location contains all of the words in the given set.
* If the string contains quoted phrases, this method only matches those events whose location contain the exact phrase.
* Entries in the set are considered in "and".
* Word splitting example: ["New Zealand"] vs ["New","Zealand"] "New Zealand": matched by both "New and better Zealand": only matched by the latter.
* `peoplequery <StringList>`
* Matches only those events whose attendees contain all of the words in the given set.
* Entries in the set are considered in "and".
* `minuswords <StringList>`
* Matches only those events that do not contain any of the words in the given set in title, description, location, or attendees.
* Entries in the set are considered in "or".
* `responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*
* Matches only events for which the custodian gave one of these responses. If the set is empty, there will be no filtering on responses.
* `calendarversiondate <Date>|<Time>`
* Search the current version of the Calendar event, but export the contents of the last version saved before 12:00 AM UTC on the specified date.
* Enter the date in UTC.
For `corpus calendar`, you can specify the format of the exported data:
* `format ics` - Export in ICS format, this is the default
* `format pst` - Export in PST format
For `corpus drive`, you can specify advanced search options:
* `driveversiondate <Date>|<Time>` - Search the versions of the Drive file as of the reference date. These timestamps are in GMT and rounded down to the given date.
* `includeshareddrives False` - Do not include Shared Drives in the search, this is the default.
@@ -265,9 +291,6 @@ For `corpus hangouts_chat` you can specify advanced search options:
* `includerooms False` - Do not include rooms, this is the default
* `includerooms True` - Include rooms
For `corpus mail`, you can specify search terms to limit the scope of data:
* `terms <String>` - [Vault search](https://support.google.com/vault/answer/2474474)
For `corpus mail`, you can specify whether to exclude draft messages:
* `excludedrafts False` - Do not exclude drafts, this is the default
* `excludedrafts True` - Exclude drafts
@@ -282,7 +305,7 @@ For `corpus mail`, you can specify whether to use the new export system:
See: https://support.google.com/vault/answer/4388708#new_gmail_export&zippy=%2Cfebruary-new-gmail-export-system-available
For `corpus mail`, `corpus groups` and `corpus hangouts_chat`, you can specify the format of the exported data:
For `corpus mail`, `corpus groups`, `corpus hangouts_chat`and `corpus voice`, you can specify the format of the exported data:
* `format mbox` - Export in MBOX format, this is the default
* `format pst` - Export in PST format

View File

@@ -4,7 +4,7 @@
Print the current version of Gam with details
```
gam version
GAMADV-XTD3 6.66.16 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.67.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64
@@ -16,7 +16,7 @@ Time: 2023-06-02T21:10:00-07:00
Print the current version of Gam with details and time offset information
```
gam version timeoffset
GAMADV-XTD3 6.66.16 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.67.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64
@@ -28,7 +28,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
```
gam version extended
GAMADV-XTD3 6.66.16 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
GAMADV-XTD3 6.67.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64
@@ -65,7 +65,7 @@ MacOS High Sierra 10.13.6 x86_64
Path: /Users/Admin/bin/gamadv-xtd3
Version Check:
Current: 5.35.08
Latest: 6.66.16
Latest: 6.67.00
echo $?
1
```
@@ -73,7 +73,7 @@ echo $?
Print the current version number without details
```
gam version simple
6.66.16
6.67.00
```
In Linux/MacOS you can do:
```
@@ -83,7 +83,7 @@ echo $VER
Print the current version of Gam and address of this Wiki
```
gam help
GAM 6.66.16 - https://github.com/taers232c/GAMADV-XTD3
GAM 6.67.00 - https://github.com/taers232c/GAMADV-XTD3
Ross Scroggs <ross.scroggs@gmail.com>
Python 3.12.0 64-bit final
MacOS Monterey 12.7 x86_64

View File

@@ -2164,8 +2164,10 @@ gam print chromehistory releases [todrive <ToDriveAttribute>*]
<CrOSAction> ::=
deprovision_different_model_replace|
deprovision_different_model_replacement|
deprovision_retiring_device|
deprovision_same_model_replace|
deprovision_same_model_replacement|
deprovision_upgrade_transfer|
disable|
reenable|
@@ -2173,7 +2175,9 @@ gam print chromehistory releases [todrive <ToDriveAttribute>*]
pre_provisioned_reenable
gam update cros <CrOSEntity> action <CrOSAction> [acknowledge_device_touch_requirement]
[actionbatchsize <Integer>]
gam <CrOSTypeEntity> update action <CrOSAction> [acknowledge_device_touch_requirement]
[actionbatchsize <Integer>]
<CrOSCommand>
reboot|
@@ -4894,25 +4898,25 @@ gam show vaultmatters|matters [matterstate <MatterStateList>]
gam print vaultcounts [todrive <ToDriveAttributes>*]
matter <MatterItem> corpus mail|groups
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
[scope [all_data|held_data|unprocessed_data]]
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
[excludedrafts <Boolean>]
[includerooms <Boolean>]
[includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>]
[wait <Integer>]
gam print vaultcounts [todrive <ToDriveAttributes>*]
matter <MatterItem> operation <String> [wait <Integer>]
gam create vaultexport|export matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat|voice
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
(shareddrives|teamdrives <SharedDriveIDList>) | (rooms <RoomList>)
[scope [all_data|held_data|unprocessed_data]]
[scope all_data|held_data|unprocessed_data]
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
[includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
[includerooms <Boolean>]
[excludedrafts <Boolean>] [format mbox|pst]
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>]
[includerooms <Boolean>] [covereddata calllogs|textmessages|voicemails]
[includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
[covereddata calllogs|textmessages|voicemails]
[region any|europe|us] [showdetails|returnidonly]
gam delete vaultexport|export <ExportItem> matter <MatterItem>
gam delete vaultexport|export <MatterItem> <ExportItem>

View File

@@ -2,6 +2,15 @@
Merged GAM-Team version
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)

View File

@@ -22521,28 +22521,29 @@ UPDATE_CROS_ARGUMENT_TO_PROPERTY_MAP = {
}
CROS_ACTION_CHOICE_MAP = {
'deprovisionsamemodelreplace': ('deprovision', 'same_model_replacement'),
'deprovisionsamemodelreplacement': ('deprovision', 'same_model_replacement'),
'deprovisiondifferentmodelreplace': ('deprovision', 'different_model_replacement'),
'deprovisiondifferentmodelreplacement': ('deprovision', 'different_model_replacement'),
'deprovisionupgradetransfer': ('deprovision', 'upgrade_transfer'),
'deprovisionretiringdevice': ('deprovision', 'retiring_device'),
'disable': ('disable', None),
'reenable': ('reenable', None),
'preprovisioneddisable': ('pre_provisioned_disable', None),
'preprovisionedreenable': ('pre_provisioned_reenable', None)
'deprovisiondifferentmodelreplace': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION', 'DEPROVISION_REASON_DIFFERENT_MODEL_REPLACEMENT'),
'deprovisiondifferentmodelreplacement': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION', 'DEPROVISION_REASON_DIFFERENT_MODEL_REPLACEMENT'),
'deprovisionretiringdevice': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION', 'DEPROVISION_REASON_RETIRING_DEVICE'),
'deprovisionsamemodelreplace': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION', 'DEPROVISION_REASON_SAME_MODEL_REPLACEMENT'),
'deprovisionsamemodelreplacement': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION', 'DEPROVISION_REASON_SAME_MODEL_REPLACEMENT'),
'deprovisionupgradetransfer': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION', 'DEPROVISION_REASON_UPGRADE_TRANSFER'),
'disable': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DISABLE', None),
'reenable': ('CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_REENABLE', None),
# 'preprovisioneddisable': ('pre_provisioned_disable', None),
# 'preprovisionedreenable': ('pre_provisioned_reenable', None)
}
CROS_ACTION_NAME_MAP = {
'deprovision': Act.DEPROVISION,
'disable': Act.DISABLE,
'reenable': Act.REENABLE,
'pre_provisioned_disable': Act.PRE_PROVISIONED_DISABLE,
'pre_provisioned_reenable': Act.PRE_PROVISIONED_REENABLE
'CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION': Act.DEPROVISION,
'CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DISABLE': Act.DISABLE,
'CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_REENABLE': Act.REENABLE,
# 'pre_provisioned_disable': Act.PRE_PROVISIONED_DISABLE,
# 'pre_provisioned_reenable': Act.PRE_PROVISIONED_REENABLE
}
# gam <CrOSTypeEntity> update <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatchupdate]
# gam <CrOSTypeEntity> update action <CrOSAction> [acknowledge_device_touch_requirement]
# [actionbatchsize <Integer>]
def updateCrOSDevices(entityList):
cd = buildGAPIObject(API.DIRECTORY)
noBatchUpdate = False
@@ -22551,6 +22552,7 @@ def updateCrOSDevices(entityList):
orgUnitPath = updateNotes = None
ackWipe = False
quickCrOSMove = GC.Values[GC.QUICK_CROS_MOVE]
actionBatchSize = 10
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg in UPDATE_CROS_ARGUMENT_TO_PROPERTY_MAP:
@@ -22564,16 +22566,18 @@ def updateCrOSDevices(entityList):
update_body[up] = getString(Cmd.OB_STRING, minLen=0)
elif myarg == 'action':
actionLocation = Cmd.Location()
action_body['action'], deprovisionReason = getChoice(CROS_ACTION_CHOICE_MAP, mapChoice=True)
action_body['changeChromeOsDeviceStatusAction'], deprovisionReason = getChoice(CROS_ACTION_CHOICE_MAP, mapChoice=True)
if deprovisionReason:
action_body['deprovisionReason'] = deprovisionReason
Act.Set(CROS_ACTION_NAME_MAP[action_body['action']])
Act.Set(CROS_ACTION_NAME_MAP[action_body['changeChromeOsDeviceStatusAction']])
elif myarg == 'acknowledgedevicetouchrequirement':
ackWipe = True
elif myarg == 'quickcrosmove':
quickCrOSMove = getBoolean()
elif myarg == 'nobatchupdate':
noBatchUpdate = getBoolean()
elif myarg == 'actionbatchsize':
actionBatchSize = getInteger(minVal=10, maxVal=250)
else:
unknownArgumentExit()
if action_body and update_body:
@@ -22585,28 +22589,44 @@ def updateCrOSDevices(entityList):
entityActionFailedWarning([Ent.CROS_DEVICE, ''], f'{Ent.Singular(Ent.ORGANIZATIONAL_UNIT)}: {orgUnitPath}, {Msg.DOES_NOT_EXIST}')
return
i, count, entityList = getEntityArgument(entityList)
function = None
# Action
if action_body:
if action_body['action'] == 'deprovision' and not ackWipe:
if action_body['changeChromeOsDeviceStatusAction'] == 'CHANGE_CHROME_OS_DEVICE_STATUS_ACTION_DEPROVISION' and not ackWipe:
stderrWarningMsg(Msg.REFUSING_TO_DEPROVISION_DEVICES.format(count))
systemErrorExit(ACTION_NOT_PERFORMED_RC, None)
function = 'action'
parmId = 'resourceId'
kwargs = {parmId: None, 'body': action_body}
else:
if update_body or noBatchUpdate:
if orgUnitPath and (not quickCrOSMove or noBatchUpdate):
update_body['orgUnitPath'] = orgUnitPath
if GC.Values[GC.UPDATE_CROS_OU_WITH_ID]:
update_body['orgUnitId'] = orgUnitId
orgUnitPath = None
function = 'update'
parmId = 'deviceId'
kwargs = {parmId: None, 'body': update_body, 'fields': ''}
if orgUnitPath:
Act.Set(Act.ADD)
_batchMoveCrOSesToOrgUnit(cd, orgUnitPath, orgUnitId, 0, 0, entityList, quickCrOSMove)
Act.Set(Act.UPDATE)
while i < count:
bcount = min(count-i, actionBatchSize)
action_body['deviceIds'] = entityList[i:i+bcount]
try:
result = callGAPI(cd.customer().devices().chromeos(), 'batchChangeStatus',
throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.CONDITION_NOT_MET, GAPI.INVALID_INPUT,
GAPI.BAD_REQUEST, GAPI.FORBIDDEN],
customerId=GC.Values[GC.CUSTOMER_ID], body=action_body)
for status in result['changeChromeOsDeviceStatusResults']:
i += 1
deviceId = status['deviceId']
if 'error' not in status:
entityActionPerformed([Ent.CROS_DEVICE, deviceId], i, count)
else:
entityActionFailedWarning([Ent.CROS_DEVICE, deviceId], status['error']['message'], i, count)
except (GAPI.invalid, GAPI.invalidArgument, GAPI.conditionNotMet, GAPI.invalidInput, GAPI.badRequest, GAPI.forbidden) as e:
entityActionFailedExit([Ent.CROS_DEVICE, None], str(e))
return
# Update
function = None
if update_body or noBatchUpdate:
if orgUnitPath and (not quickCrOSMove or noBatchUpdate):
update_body['orgUnitPath'] = orgUnitPath
if GC.Values[GC.UPDATE_CROS_OU_WITH_ID]:
update_body['orgUnitId'] = orgUnitId
orgUnitPath = None
function = 'update'
parmId = 'deviceId'
kwargs = {parmId: None, 'body': update_body, 'fields': ''}
if orgUnitPath:
Act.Set(Act.ADD)
_batchMoveCrOSesToOrgUnit(cd, orgUnitPath, orgUnitId, 0, 0, entityList, quickCrOSMove)
Act.Set(Act.UPDATE)
if function is None:
return
for deviceId in entityList:
@@ -37878,10 +37898,12 @@ VAULT_SEARCH_METHODS_MAP = {
'rooms': 'ROOM',
'shareddrive': 'SHARED_DRIVE',
'shareddrives': 'SHARED_DRIVE',
'sitesurl': 'SITES_URL',
'teamdrive': 'SHARED_DRIVE',
'teamdrives': 'SHARED_DRIVE',
}
VAULT_CORPUS_ARGUMENT_MAP = {
'calendar': 'CALENDAR',
'drive': 'DRIVE',
'mail': 'MAIL',
'groups': 'GROUPS',
@@ -37892,6 +37914,12 @@ VAULT_COUNTS_CORPUS_ARGUMENT_MAP = {
'mail': 'MAIL',
'groups': 'GROUPS',
}
VAULT_RESPONSE_STATUS_MAP = {
'accepted': 'ATTENDEE_RESPONSE_ACCEPTED',
'declined': 'ATTENDEE_RESPONSE_DECLINED',
'needsaction': 'ATTENDEE_RESPONSE_NEEDS_ACTION',
'tentative': 'ATTENDEE_RESPONSE_TENTATIVE',
}
VAULT_VOICE_COVERED_DATA_MAP = {
'calllogs': 'CALL_LOGS',
'textmessages': 'TEXT_MESSAGES',
@@ -37903,15 +37931,24 @@ VAULT_EXPORT_DATASCOPE_MAP = {
'unprocesseddata': 'UNPROCESSED_DATA',
}
VAULT_EXPORT_FORMAT_MAP = {
'ics': 'ICS',
'mbox': 'MBOX',
'pst': 'PST',
}
VAULT_CORPUS_EXPORT_FORMATS = {
'CALENDAR': ['ICS', 'PST'],
'DRIVE': [],
'GROUPS': ['MBOX', 'PST'],
'HANGOUTS_CHAT': ['MBOX', 'PST'],
'VOICE' : ['MBOX', 'PST'],
}
VAULT_EXPORT_REGION_MAP = {
'any': 'ANY',
'europe': 'EUROPE',
'us': 'US',
}
VAULT_CORPUS_OPTIONS_MAP = {
'CALENDAR': 'calendarOptions',
'DRIVE': 'driveOptions',
'MAIL': 'mailOptions',
'GROUPS': 'groupsOptions',
@@ -37927,8 +37964,17 @@ VAULT_CORPUS_QUERY_MAP = {
}
VAULT_QUERY_ARGS = [
'corpus', 'scope', 'terms', 'start', 'starttime', 'end', 'endtime', 'timezone',
'includerooms', 'excludedrafts',
'driveversiondate', 'includeshareddrives', 'includeteamdrives'] + list(VAULT_SEARCH_METHODS_MAP.keys())
# calendar
'locationquery', 'peoplequery', 'minuswords', 'responsestatuses', 'caldendarversiondate',
# drive
'driveversiondate', 'includeshareddrives', 'includeteamdrives',
# hangoutsChat
'includerooms',
# mail
'excludedrafts',
# voice
'covereddata',
] + list(VAULT_SEARCH_METHODS_MAP.keys())
def _buildVaultQuery(myarg, query, corpusArgumentMap):
if not query:
@@ -37949,6 +37995,8 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
query['sharedDriveInfo'] = {'sharedDriveIds': getString(Cmd.OB_SHAREDDRIVE_ID_LIST).replace(',', ' ').split()}
elif searchMethod == 'ROOM':
query['hangoutsChatInfo'] = {'roomId': getString(Cmd.OB_ROOM_LIST).replace(',', ' ').split()}
elif searchMethod == 'SITES_URL':
query['sitesUrlInfo'] = {'urls': getString(Cmd.OB_URL_LIST).replace(',', ' ').split()}
elif myarg == 'scope':
query['dataScope'] = getChoice(VAULT_EXPORT_DATASCOPE_MAP, mapChoice=True)
elif myarg == 'terms':
@@ -37959,37 +38007,64 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
query['endTime'] = getTimeOrDeltaFromNow()
elif myarg == 'timezone':
query['timeZone'] = getString(Cmd.OB_STRING)
elif myarg == 'includerooms':
query['hangoutsChatOptions'] = {'includeRooms': getBoolean()}
elif myarg == 'excludedrafts':
query['mailOptions'] = {'excludeDrafts': getBoolean()}
# calendar
elif myarg == 'locationquery':
query.setdefault('calendarOptions', {})['locationQuery'] = shlexSplitList(getString(Cmd.OB_STRING_LIST))
elif myarg == 'peoplequery':
query.setdefault('calendarOptions', {})['peopleQuery'] = shlexSplitList(getString(Cmd.OB_STRING_LIST))
elif myarg == 'minuswords':
query.setdefault('calendarOptions', {})['minusWords'] = shlexSplitList(getString(Cmd.OB_STRING_LIST))
elif myarg == 'responsestatuses':
query.setdefault('calendarOptions', {})['responseStatuses'] = []
for response in getString(Cmd.OB_FIELD_NAME_LIST).lower().replace('_', '').replace(',', ' ').split():
if response in VAULT_RESPONSE_STATUS_MAP:
query['calendarOptions']['responseStatuses'].append(VAULT_RESPONSE_STATUS_MAP[response])
else:
invalidChoiceExit(response, VAULT_RESPONSE_STATUS_MAP, True)
elif myarg == 'calendarversiondate':
query.setdefault('calendarOptions', {})['versionDate'] = getTimeOrDeltaFromNow()
# drive
elif myarg == 'driveversiondate':
query.setdefault('driveOptions', {})['versionDate'] = getTimeOrDeltaFromNow()
elif myarg in {'includeshareddrives', 'includeteamdrives'}:
query.setdefault('driveOptions', {})['includeSharedDrives'] = getBoolean()
# hangoutsChat
elif myarg == 'includerooms':
query['hangoutsChatOptions'] = {'includeRooms': getBoolean()}
# mail
elif myarg == 'excludedrafts':
query['mailOptions'] = {'excludeDrafts': getBoolean()}
# voice
elif myarg == 'covereddata':
query['voiceOptions'] = {'coveredData': getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)}
def _validateVaultQuery(query):
if 'corpus' not in query:
def _validateVaultQuery(body):
if 'corpus' not in body['query']:
missingArgumentExit(f'corpus {formatChoiceList(VAULT_CORPUS_ARGUMENT_MAP)}')
if 'searchMethod' not in query:
if 'searchMethod' not in body['query']:
missingArgumentExit(formatChoiceList(VAULT_SEARCH_METHODS_MAP))
for corpus, options in iter(VAULT_CORPUS_OPTIONS_MAP.items()):
if body['query']['corpus'] != corpus:
body['exportOptions'].pop(options, None)
# gam create vaultexport|export matter <MatterItem> [name <String>] corpus drive|mail|groups|hangouts_chat|voice
# gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
# (shareddrives|teamdrives <TeamDriveIDList>) | (rooms <RoomList>)
# [scope <all_data|held_data|unprocessed_data>]
# [terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
# [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
# [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
# [includeshareddrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
# [includerooms <Boolean>]
# [excludedrafts <Boolean>] [format mbox|pst]
# [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>]
# [includerooms <Boolean>]
# [covereddata calllogs|textmessages|voicemails]
# [includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
# [region any|europe|us] [showdetails|returnidonly]
def doCreateVaultExport():
v = buildGAPIObject(API.VAULT)
matterId = None
body = {'query': {'dataScope': 'ALL_DATA'}, 'exportOptions': {}}
exportFormat = 'MBOX'
exportFormat = None
showConfidentialModeContent = None
returnIdOnly = showDetails = False
useNewExport = None
@@ -38024,24 +38099,26 @@ def doCreateVaultExport():
unknownArgumentExit()
if not matterId:
missingArgumentExit('matter')
_validateVaultQuery(body['query'])
_validateVaultQuery(body)
if exportFormat is not None:
if not exportFormat in VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']]:
invalidChoiceExit(exportFormat, VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']], False)
elif body['query']['corpus'] != 'DRIVE':
exportFormat = VAULT_CORPUS_EXPORT_FORMATS[body['query']['corpus']][0]
if 'name' not in body:
body['name'] = f'GAM {body["query"]["corpus"]} Export - {ISOformatTimeStamp(todaysTime())}'
optionsField = VAULT_CORPUS_OPTIONS_MAP[body['query']['corpus']]
if body['query']['corpus'] != 'DRIVE':
body['exportOptions'].pop('driveOptions', None)
body['exportOptions'][optionsField] = {'exportFormat': exportFormat}
if body['query']['corpus'] == 'MAIL':
if showConfidentialModeContent is not None:
body['exportOptions'][optionsField]['showConfidentialModeContent'] = showConfidentialModeContent
if useNewExport is not None:
body['exportOptions'][optionsField]['useNewExport'] = useNewExport
if body['query']['corpus'] != 'VOICE':
body['exportOptions'].pop('voiceOptions', None)
try:
export = callGAPI(v.matters().exports(), 'create',
throwReasons=[GAPI.ALREADY_EXISTS, GAPI.BAD_REQUEST, GAPI.BACKEND_ERROR, GAPI.INVALID_ARGUMENT,
GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.QUOTA_EXCEEDED],
GAPI.INVALID, GAPI.FAILED_PRECONDITION, GAPI.FORBIDDEN, GAPI.QUOTA_EXCEEDED],
matterId=matterId, body=body)
if not returnIdOnly:
entityActionPerformed([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, formatVaultNameId(export['name'], export['id'])])
@@ -38050,7 +38127,7 @@ def doCreateVaultExport():
else:
writeStdout(f'{export["id"]}\n')
except (GAPI.alreadyExists, GAPI.badRequest, GAPI.backendError, GAPI.invalidArgument,
GAPI.failedPrecondition, GAPI.forbidden, GAPI.quotaExceeded) as e:
GAPI.invalid, GAPI.failedPrecondition, GAPI.forbidden, GAPI.quotaExceeded) as e:
entityActionFailedWarning([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_EXPORT, body.get('name')], str(e))
# gam delete vaultexport|export <ExportItem> matter <MatterItem>
@@ -39508,12 +39585,9 @@ PRINT_VAULT_COUNTS_TITLES = ['account', 'count', 'error']
# gam print vaultcounts [todrive <ToDriveAttributes>*]
# matter <MatterItem> corpus mail|groups
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
# (shareddrives|teamdrives <TeamDriveIDList>) | (rooms <RoomList>)
# [scope <all_data|held_data|unprocessed_data>]
# [terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>] [timezone <TimeZone>]
# [excludedrafts <Boolean>]
# [includerooms <Boolean>]
# [includeshareddrives|includeteamdrives <Boolean>] [driveversiondate <Date>|<Time>]
# [wait <Integer>]
# gam print vaultcounts [todrive <ToDriveAttributes>*]
# matter <MatterItem> operation <String> [wait <Integer>]
@@ -39544,8 +39618,8 @@ def doPrintVaultCounts():
operation = {'name': name}
doWait = False
else:
_validateVaultQuery(query)
body['query'] = query
_validateVaultQuery(body)
try:
operation = callGAPI(v.matters(), 'count',
throwReasons=[GAPI.INVALID_ARGUMENT],
@@ -67148,7 +67222,7 @@ def printShowDelegates(users):
printGettingAllEntityItemsForWhom(Ent.DELEGATE, user, i, count)
try:
result = callGAPI(gmail.users().settings().delegates(), 'list',
throwReasons=GAPI.GMAIL_THROW_REASONS+[GAPI.PERMISSION_DENIED],
throwReasons=GAPI.GMAIL_THROW_REASONS+[GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
userId='me')
delegates = result.get('delegates', []) if result is not None else []
jcount = len(delegates)
@@ -67195,7 +67269,7 @@ def printShowDelegates(users):
'delegationStatus': delegate['verificationStatus']})
elif GC.Values[GC.CSV_OUTPUT_USERS_AUDIT]:
csvPF.WriteRowNoFilter({'User': user})
except GAPI.permissionDenied as e:
except (GAPI.permissionDenied, GAPI.failedPrecondition) as e:
entityActionFailedWarning([Ent.USER, user, Ent.DELEGATE, None], str(e), i, count)
except (GAPI.serviceNotAvailable, GAPI.badRequest):
entityServiceNotApplicableWarning(Ent.USER, user, i, count)

View File

@@ -991,6 +991,7 @@ class GamCLArgs():
OB_TRANSFER_ID = 'TransferID'
OB_URI = 'URI'
OB_URL = 'URL'
OB_URL_LIST = 'URLList'
OB_USER_ENTITY = 'UserEntity'
OB_USER_ITEM = 'UserItem'
OB_USER_NAME = 'UserName'