mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-08 16:21:38 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b0c8b75cb | ||
|
|
6eb7e59d56 | ||
|
|
5b4cf97702 | ||
|
|
997bd56bd6 | ||
|
|
e66db1a117 | ||
|
|
e3a5f33981 | ||
|
|
877465a82f | ||
|
|
7e9477c6ea | ||
|
|
1b2fc06f6f | ||
|
|
3d3b3eac85 | ||
|
|
882b930928 | ||
|
|
4d804177c4 | ||
|
|
de71baff60 | ||
|
|
79de854440 |
2
.github/workflows/pushwiki.yml
vendored
2
.github/workflows/pushwiki.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
cd GAM.wiki
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add *.md
|
||||
git add -A
|
||||
git commit -m "[no ci] Push Wiki changes"
|
||||
git status
|
||||
git push
|
||||
|
||||
@@ -565,6 +565,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
See: https://support.google.com/mail/answer/7190
|
||||
<QueryGroup> ::= <String>
|
||||
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups
|
||||
<QueryItem> ::= <UniqueID>|<String>
|
||||
<QueryMemberRestrictions> ::= <String>
|
||||
See: https://cloud.google.com/identity/docs/reference/rest/v1beta1/SecuritySettings#MemberRestriction
|
||||
<QueryMobile> ::= <String>
|
||||
@@ -5422,6 +5423,15 @@ gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
gam print vaultcounts [todrive <ToDriveAttributes>*]
|
||||
matter <MatterItem> operation <String> [wait <Integer>]
|
||||
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
(accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
(shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
@@ -5432,12 +5442,13 @@ gam create vaultexport|export matter <MatterItem> [name <String>] corpus calenda
|
||||
[locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
[responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
[(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
[driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[driveversiondate <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
gam delete vaultexport|export <ExportItem> matter <MatterItem>
|
||||
@@ -5493,18 +5504,21 @@ gam show vaultexports|exports
|
||||
[fields <VaultExportFieldNameList>] [shownames]
|
||||
[formatjson]
|
||||
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
[(accounts|groups|users <EmailItemList>) | (orgunit|org|ou <OrgUnit>)]
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>] [covereddata calllogs|textmessages|voicemails]
|
||||
[includerooms <Boolean>] (covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails|returnidonly]
|
||||
gam update vaulthold|hold <HoldItem> matter <MatterItem>
|
||||
[([addaccounts|addgroups|addusers <EmailItemList>] [removeaccounts|removegroups|removeusers <EmailItemList>]) | (orgunit|org|ou <OrgUnit>)]
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>] [covereddata calllogs|textmessages|voicemails]
|
||||
[includerooms <Boolean>] (covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails]
|
||||
gam delete vaulthold|hold <HoldItem> matter <MatterItem>
|
||||
|
||||
@@ -1,7 +1,36 @@
|
||||
7.22.05
|
||||
|
||||
Added a variant of `gam create vaultexport` that gets its query parameters from a saved Vault query.
|
||||
|
||||
```
|
||||
gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[driveclientsideencryption any|encrypted|unencrypted]
|
||||
[includeaccessinfo <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
|
||||
7.22.04
|
||||
|
||||
Added a variant of `gam create vaulthold` that gets its parameters from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
|
||||
7.22.03
|
||||
|
||||
Fix backwards compatability bug introduced in 7.22.00 for `gam print users` that changed `suspended`
|
||||
from a field name to a query option; it is now correctly interpreted as a field name.
|
||||
|
||||
7.22.02
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed
|
||||
by includinbg the pysocks library needed by the latest httplib2 library.
|
||||
by including the pysocks library needed by the latest httplib2 library.
|
||||
|
||||
7.22.00
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.22.02'
|
||||
__version__ = '7.22.05'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
#pylint: disable=wrong-import-position
|
||||
@@ -18989,10 +18989,10 @@ def doPrintAliases():
|
||||
pass
|
||||
elif myarg == 'select':
|
||||
_, users = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
|
||||
elif myarg in SUSPENDED_ARGUMENTS:
|
||||
isSuspended = _getIsSuspended(myarg)
|
||||
elif myarg in ARCHIVED_ARGUMENTS:
|
||||
isArchived = _getIsArchived(myarg)
|
||||
elif myarg == 'issuspended':
|
||||
isSuspended = getBoolean()
|
||||
elif myarg == 'isarchived':
|
||||
isArchived = getBoolean()
|
||||
elif myarg in {'user','users'}:
|
||||
users.extend(convertEntityToList(getString(Cmd.OB_EMAIL_ADDRESS_LIST, minLen=0)))
|
||||
elif myarg in {'group', 'groups'}:
|
||||
@@ -41654,7 +41654,7 @@ def convertQueryNameToID(v, nameOrId, matterId, matterNameId):
|
||||
query = callGAPI(v.matters().savedQueries(), 'get',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.BAD_REQUEST, GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
|
||||
matterId=matterId, savedQueryId=cg.group(1))
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']))
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']), query['query'])
|
||||
except (GAPI.notFound, GAPI.badRequest):
|
||||
entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, nameOrId])
|
||||
except (GAPI.forbidden, GAPI.invalidArgument) as e:
|
||||
@@ -41663,12 +41663,12 @@ def convertQueryNameToID(v, nameOrId, matterId, matterNameId):
|
||||
try:
|
||||
queries = callGAPIpages(v.matters().savedQueries(), 'list', 'savedQueries',
|
||||
throwReasons=[GAPI.FORBIDDEN, GAPI.INVALID_ARGUMENT],
|
||||
matterId=matterId, fields='savedQueries(savedQueryId,displayName),nextPageToken')
|
||||
matterId=matterId, fields='savedQueries(savedQueryId,displayName,query),nextPageToken')
|
||||
except (GAPI.forbidden, GAPI.invalidArgument) as e:
|
||||
ClientAPIAccessDeniedExit(str(e))
|
||||
for query in queries:
|
||||
if query['displayName'].lower() == nameOrIdlower:
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']))
|
||||
return (query['savedQueryId'], query['displayName'], formatVaultNameId(query['savedQueryId'], query['displayName']), query['query'])
|
||||
entityDoesNotHaveItemExit([Ent.VAULT_MATTER, matterNameId, Ent.VAULT_QUERY, nameOrId])
|
||||
|
||||
def getMatterItem(v, state=None):
|
||||
@@ -41891,12 +41891,13 @@ def _buildVaultQuery(myarg, query, corpusArgumentMap):
|
||||
query['hangoutsChatOptions'] = {'includeRooms': getBoolean()}
|
||||
# mail
|
||||
elif myarg == 'excludedrafts':
|
||||
query['mailOptions'] = {'excludeDrafts': getBoolean()}
|
||||
query.setdefault('mailOptions', {})['excludeDrafts'] = getBoolean()
|
||||
elif myarg == 'mailclientsideencryption':
|
||||
query.setdefault('mailOptions', {})['clientSideEncryptedOption'] = getChoice(VAULT_CSE_OPTION_MAP, mapChoice=True)
|
||||
# voice
|
||||
elif myarg == 'covereddata':
|
||||
query['voiceOptions'] = {'coveredData': getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)}
|
||||
query.setdefault('voiceOptions', {'coveredData': []})
|
||||
query['voiceOptions']['coveredData'].append(getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True))
|
||||
|
||||
def _validateVaultQuery(body, corpusArgumentMap):
|
||||
if 'corpus' not in body['query']:
|
||||
@@ -41908,7 +41909,16 @@ def _validateVaultQuery(body, corpusArgumentMap):
|
||||
if body['query']['corpus'] != corpus:
|
||||
body['exportOptions'].pop(options, None)
|
||||
|
||||
# gam create vaultexport|export matter <MatterItem> [name <String>] corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
# gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
# vaultquery <QueryItem>
|
||||
# [driveclientsideencryption any|encrypted|unencrypted]
|
||||
# [includeaccessinfo <Boolean>]
|
||||
# [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
# [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
# [format ics|mbox|pst|xml]
|
||||
# [region any|europe|us] [showdetails|returnidonly]
|
||||
# gam create vaultexport|export matter <MatterItem> [name <String>]
|
||||
# corpus calendar|drive|gemini|groups|hangouts_chat|mail|voice
|
||||
# (accounts <EmailAddressEntity>) | (orgunit|org|ou <OrgUnitPath>) | everyone
|
||||
# (shareddrives|teamdrives (<SharedDriveIDList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
# (rooms (<ChatSpaceList>|(select <FileSelector>|<CSVFileSelector>))) |
|
||||
@@ -41918,23 +41928,25 @@ def _validateVaultQuery(body, corpusArgumentMap):
|
||||
# [locationquery <StringList>] [peoplequery <StringList>] [minuswords <StringList>]
|
||||
# [responsestatuses <AttendeeStatus>(,<AttendeeStatus>)*] [calendarversiondate <Date>|<Time>]
|
||||
# [(includeshareddrives <Boolean>)|(shareddrivesoption included|included_if_account_is_not_a_member|not_included)]
|
||||
# [driveversiondate <Date>|<Time>] [includeaccessinfo <Boolean>]
|
||||
# [driveclientsideencryption any|encrypted|unencrypted]
|
||||
# [driveversiondate <Date>|<Time>]
|
||||
# [includerooms <Boolean>]
|
||||
# (covereddata calllogs|textmessages|voicemails)*
|
||||
# [driveclientsideencryption any|encrypted|unencrypted]
|
||||
# [includeaccessinfo <Boolean>]
|
||||
# [excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
# [showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
# [covereddata calllogs|textmessages|voicemails]
|
||||
# [format ics|mbox|pst|xml]
|
||||
# [region any|europe|us] [showdetails|returnidonly]
|
||||
def doCreateVaultExport():
|
||||
v = buildGAPIObject(API.VAULT)
|
||||
matterId = None
|
||||
body = {'query': {'dataScope': 'ALL_DATA'}, 'exportOptions': {}}
|
||||
includeAccessInfo = None
|
||||
exportFormat = None
|
||||
useNewExport = None
|
||||
showConfidentialModeContent = None
|
||||
exportLinkedDriveFiles = None
|
||||
returnIdOnly = showDetails = False
|
||||
useNewExport = None
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'matter':
|
||||
@@ -41942,22 +41954,22 @@ def doCreateVaultExport():
|
||||
body['matterId'] = matterId
|
||||
elif myarg == 'name':
|
||||
body['name'] = getString(Cmd.OB_STRING)
|
||||
elif matterId is not None and myarg == 'vaultquery':
|
||||
_, _, _, body['query'] = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
elif myarg in VAULT_QUERY_ARGS:
|
||||
_buildVaultQuery(myarg, body['query'], VAULT_CORPUS_ARGUMENT_MAP)
|
||||
elif myarg == 'usenewexport':
|
||||
useNewExport = getBoolean()
|
||||
elif myarg == 'includeaccessinfo':
|
||||
includeAccessInfo = getBoolean()
|
||||
elif myarg == 'format':
|
||||
exportFormat = getChoice(VAULT_EXPORT_FORMAT_MAP, mapChoice=True)
|
||||
elif myarg == 'usenewexport':
|
||||
useNewExport = getBoolean()
|
||||
elif myarg == 'showconfidentialmodecontent':
|
||||
showConfidentialModeContent = getBoolean()
|
||||
elif myarg == 'exportlinkeddrivefiles':
|
||||
exportLinkedDriveFiles = getBoolean()
|
||||
elif myarg == 'region':
|
||||
body['exportOptions']['region'] = getChoice(VAULT_EXPORT_REGION_MAP, mapChoice=True)
|
||||
elif myarg == 'includeaccessinfo':
|
||||
body['exportOptions'].setdefault('driveOptions', {})['includeAccessInfo'] = getBoolean()
|
||||
elif myarg == 'covereddata':
|
||||
body['exportOptions'].setdefault('voiceOptions', {})['coveredData'] = getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)
|
||||
elif myarg == 'showdetails':
|
||||
showDetails = True
|
||||
returnIdOnly = False
|
||||
@@ -41977,7 +41989,10 @@ def doCreateVaultExport():
|
||||
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':
|
||||
if body['query']['corpus'] == 'DRIVE':
|
||||
if includeAccessInfo is not None:
|
||||
body['exportOptions'][optionsField]['includeAccessInfo'] = includeAccessInfo
|
||||
else:
|
||||
body['exportOptions'][optionsField] = {'exportFormat': exportFormat}
|
||||
if body['query']['corpus'] == 'MAIL':
|
||||
if showConfidentialModeContent is not None:
|
||||
@@ -42459,6 +42474,34 @@ def _showVaultHold(matterNameId, hold, cd, FJQC, k=0, kcount=0):
|
||||
showJSON(None, hold, timeObjects=VAULT_HOLD_TIME_OBJECTS)
|
||||
Ind.Decrement()
|
||||
|
||||
def _useVaultQuery(v, matterId, matterNameId, body):
|
||||
_, _, _, query = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
body['corpus'] = query['corpus']
|
||||
method = query.get('method')
|
||||
if method == 'ACCOUNT':
|
||||
body['accounts'] = []
|
||||
for email in query['accountInfo']['emails']:
|
||||
body['accounts'].append({'email': email})
|
||||
elif method == 'ORG_UNIT':
|
||||
body['orgUnit'] = {'orgUnitId': query['orgUnitInfo']['orgUnitId']}
|
||||
queryType = VAULT_CORPUS_QUERY_MAP[query['corpus']]
|
||||
if queryType is None:
|
||||
return
|
||||
body['query'] = {queryType: {}}
|
||||
if query['corpus'] == 'DRIVE':
|
||||
body['query'][queryType]['includeSharedDriveFiles'] = query['driveOptions'].get('includeSharedDrives', False)
|
||||
elif query['corpus'] in {'GROUPS', 'MAIL'}:
|
||||
if query.get('terms'):
|
||||
body['query'][queryType]['terms'] = query['terms']
|
||||
if query.get('startTime'):
|
||||
body['query'][queryType]['startTime'] = query['startTime']
|
||||
if query.get('endTime'):
|
||||
body['query'][queryType]['endTime'] = query['endTime']
|
||||
elif query['corpus'] == 'HANGOUTS_CHAT':
|
||||
body['query'][queryType]['includeRooms'] = query['hangoutsChatOptions'].get('includeRooms', False)
|
||||
elif query['corpus'] == 'VOICE':
|
||||
body['query'][queryType]['coveredData'] = query['voiceOptions']['coveredData']
|
||||
|
||||
def _getHoldQueryParameters(myarg, queryParameters):
|
||||
if myarg == 'query':
|
||||
queryParameters['queryLocation'] = Cmd.Location()
|
||||
@@ -42474,7 +42517,8 @@ def _getHoldQueryParameters(myarg, queryParameters):
|
||||
elif myarg in {'includeshareddrives', 'includeteamdrives'}:
|
||||
queryParameters['includeSharedDriveFiles'] = getBoolean()
|
||||
elif myarg == 'covereddata':
|
||||
queryParameters['coveredData'] = getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True)
|
||||
queryParameters.setdefault('coveredData', [])
|
||||
queryParameters['coveredData'].append(getChoice(VAULT_VOICE_COVERED_DATA_MAP, mapChoice=True))
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
@@ -42509,7 +42553,11 @@ def _setHoldQuery(body, queryParameters):
|
||||
if queryParameters.get('coveredData'):
|
||||
body['query'][queryType]['coveredData'] = queryParameters['coveredData']
|
||||
|
||||
# gam create vaulthold|hold matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
# gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
# vaultquery <QueryItem>
|
||||
# [showdetails|returnidonly]
|
||||
# gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
# corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
# [(accounts|groups|users <EmailItemList>) | (orgunit|org|ou <OrgUnit>)]
|
||||
# [query <QueryVaultCorpus>]
|
||||
# [terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
@@ -42523,13 +42571,16 @@ def doCreateVaultHold():
|
||||
matterId = None
|
||||
accounts = []
|
||||
queryParameters = {}
|
||||
returnIdOnly = showDetails = False
|
||||
returnIdOnly = showDetails = usedVaultQuery = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'matter':
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
elif myarg == 'name':
|
||||
body['name'] = getString(Cmd.OB_STRING)
|
||||
elif matterId is not None and myarg == 'vaultquery':
|
||||
_useVaultQuery(v, matterId, matterNameId, body)
|
||||
usedVaultQuery = True
|
||||
elif myarg == 'corpus':
|
||||
body['corpus'] = getChoice(VAULT_CORPUS_ARGUMENT_MAP, mapChoice=True)
|
||||
elif myarg in {'accounts', 'users', 'groups'}:
|
||||
@@ -42553,7 +42604,8 @@ def doCreateVaultHold():
|
||||
missingArgumentExit(f'corpus {"|".join(VAULT_CORPUS_ARGUMENT_MAP)}')
|
||||
if 'name' not in body:
|
||||
body['name'] = f'GAM {body["corpus"]} Hold - {ISOformatTimeStamp(todaysTime())}'
|
||||
_setHoldQuery(body, queryParameters)
|
||||
if not usedVaultQuery:
|
||||
_setHoldQuery(body, queryParameters)
|
||||
if accounts:
|
||||
body['accounts'] = []
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
@@ -43006,7 +43058,7 @@ def doInfoVaultQuery():
|
||||
v = buildGAPIObject(API.VAULT)
|
||||
if not Cmd.ArgumentIsAhead('matter'):
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
queryId, queryName, queryNameId = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
queryId, queryName, queryNameId, _ = convertQueryNameToID(v, getString(Cmd.OB_QUERY_ITEM), matterId, matterNameId)
|
||||
else:
|
||||
queryName = getString(Cmd.OB_QUERY_ITEM)
|
||||
cd = drive = None
|
||||
@@ -43016,7 +43068,7 @@ def doInfoVaultQuery():
|
||||
myarg = getArgument()
|
||||
if myarg == 'matter':
|
||||
matterId, matterNameId = getMatterItem(v)
|
||||
queryId, queryName, queryNameId = convertQueryNameToID(v, queryName, matterId, matterNameId)
|
||||
queryId, queryName, queryNameId, _ = convertQueryNameToID(v, queryName, matterId, matterNameId)
|
||||
elif myarg == 'shownames':
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
_, drive = buildGAPIServiceObject(API.DRIVE3, _getAdminEmail())
|
||||
@@ -45754,71 +45806,81 @@ def doPrintUsers(entityList=None):
|
||||
csvPF.WriteRowNoFilter(row)
|
||||
|
||||
def _printUser(userEntity, i, count):
|
||||
if isSuspended is None or isSuspended == userEntity.get('suspended', isSuspended):
|
||||
if showValidColumn:
|
||||
userEntity[showValidColumn] = True
|
||||
userEmail = userEntity['primaryEmail']
|
||||
if printOptions['emailParts']:
|
||||
if userEmail.find('@') != -1:
|
||||
userEntity['primaryEmailLocal'], userEntity['primaryEmailDomain'] = splitEmailAddress(userEmail)
|
||||
if 'languages' in userEntity and not FJQC.formatJSON:
|
||||
userEntity['languages'] = _formatLanguagesList(userEntity.pop('languages'), delimiter)
|
||||
for location in userEntity.get('locations', []):
|
||||
location['buildingName'] = _getBuildingNameById(cd, location.get('buildingId', ''))
|
||||
if quotePlusPhoneNumbers:
|
||||
for phone in userEntity.get('phones', []):
|
||||
phoneNumber = phone.get('value', '')
|
||||
if phoneNumber.startswith('+'):
|
||||
phone['value'] = "'"+phoneNumber
|
||||
if schemaParms['selectedSchemaFields']:
|
||||
_filterSchemaFields(userEntity, schemaParms)
|
||||
if printOptions['getGroupFeed']:
|
||||
printGettingAllEntityItemsForWhom(Ent.GROUP_MEMBERSHIP, userEmail, i, count)
|
||||
try:
|
||||
groups = callGAPIpages(cd.groups(), 'list', 'groups',
|
||||
pageMessage=getPageMessageForWhom(),
|
||||
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
userKey=userEmail, orderBy='email', fields='nextPageToken,groups(email)')
|
||||
numGroups = len(groups)
|
||||
if not printOptions['groupsInColumns']:
|
||||
userEntity['GroupsCount'] = numGroups
|
||||
userEntity['Groups'] = delimiter.join([groupname['email'] for groupname in groups])
|
||||
else:
|
||||
if numGroups > printOptions['maxGroups']:
|
||||
printOptions['maxGroups'] = numGroups
|
||||
userEntity['Groups'] = numGroups
|
||||
for j, group in enumerate(groups):
|
||||
userEntity[f'Groups{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{j}'] = group['email']
|
||||
except (GAPI.invalidMember, GAPI.invalidInput):
|
||||
badRequestWarning(Ent.GROUP, Ent.MEMBER, userEmail)
|
||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||
accessErrorExit(cd)
|
||||
if aliasMatchPattern and 'aliases' in userEntity:
|
||||
userEntity['aliases'] = [alias for alias in userEntity['aliases'] if aliasMatchPattern.match(alias)]
|
||||
if printOptions['getLicenseFeed'] or printOptions['getLicenseFeedByUser']:
|
||||
if printOptions['getLicenseFeed']:
|
||||
u_licenses = licenses.get(userEmail.lower(), [])
|
||||
if (isSuspended is None and isArchived is None):
|
||||
showUser = True
|
||||
elif (isSuspended is not None and isArchived is None):
|
||||
showUser = isSuspended == userEntity.get('suspended', isSuspended)
|
||||
elif (isSuspended is None and isArchived is not None):
|
||||
showUser = isArchived == userEntity.get('archived', isArchived)
|
||||
else:
|
||||
showUser = ((isSuspended == userEntity.get('suspended', isSuspended)) or
|
||||
(isArchived == userEntity.get('archived', isArchived)))
|
||||
if not showUser:
|
||||
return
|
||||
if showValidColumn:
|
||||
userEntity[showValidColumn] = True
|
||||
userEmail = userEntity['primaryEmail']
|
||||
if printOptions['emailParts']:
|
||||
if userEmail.find('@') != -1:
|
||||
userEntity['primaryEmailLocal'], userEntity['primaryEmailDomain'] = splitEmailAddress(userEmail)
|
||||
if 'languages' in userEntity and not FJQC.formatJSON:
|
||||
userEntity['languages'] = _formatLanguagesList(userEntity.pop('languages'), delimiter)
|
||||
for location in userEntity.get('locations', []):
|
||||
location['buildingName'] = _getBuildingNameById(cd, location.get('buildingId', ''))
|
||||
if quotePlusPhoneNumbers:
|
||||
for phone in userEntity.get('phones', []):
|
||||
phoneNumber = phone.get('value', '')
|
||||
if phoneNumber.startswith('+'):
|
||||
phone['value'] = "'"+phoneNumber
|
||||
if schemaParms['selectedSchemaFields']:
|
||||
_filterSchemaFields(userEntity, schemaParms)
|
||||
if printOptions['getGroupFeed']:
|
||||
printGettingAllEntityItemsForWhom(Ent.GROUP_MEMBERSHIP, userEmail, i, count)
|
||||
try:
|
||||
groups = callGAPIpages(cd.groups(), 'list', 'groups',
|
||||
pageMessage=getPageMessageForWhom(),
|
||||
throwReasons=GAPI.GROUP_LIST_USERKEY_THROW_REASONS,
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
userKey=userEmail, orderBy='email', fields='nextPageToken,groups(email)')
|
||||
numGroups = len(groups)
|
||||
if not printOptions['groupsInColumns']:
|
||||
userEntity['GroupsCount'] = numGroups
|
||||
userEntity['Groups'] = delimiter.join([groupname['email'] for groupname in groups])
|
||||
else:
|
||||
u_licenses = getUserLicenses(lic, userEntity, skus)
|
||||
if not oneLicensePerRow:
|
||||
userEntity['LicensesCount'] = len(u_licenses)
|
||||
if u_licenses:
|
||||
userEntity['Licenses'] = delimiter.join(u_licenses)
|
||||
userEntity['LicensesDisplay'] = delimiter.join([SKU.skuIdToDisplayName(skuId) for skuId in u_licenses])
|
||||
if numGroups > printOptions['maxGroups']:
|
||||
printOptions['maxGroups'] = numGroups
|
||||
userEntity['Groups'] = numGroups
|
||||
for j, group in enumerate(groups):
|
||||
userEntity[f'Groups{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{j}'] = group['email']
|
||||
except (GAPI.invalidMember, GAPI.invalidInput):
|
||||
badRequestWarning(Ent.GROUP, Ent.MEMBER, userEmail)
|
||||
except (GAPI.resourceNotFound, GAPI.domainNotFound, GAPI.forbidden, GAPI.badRequest):
|
||||
accessErrorExit(cd)
|
||||
if aliasMatchPattern and 'aliases' in userEntity:
|
||||
userEntity['aliases'] = [alias for alias in userEntity['aliases'] if aliasMatchPattern.match(alias)]
|
||||
if printOptions['getLicenseFeed'] or printOptions['getLicenseFeedByUser']:
|
||||
if printOptions['getLicenseFeed']:
|
||||
u_licenses = licenses.get(userEmail.lower(), [])
|
||||
else:
|
||||
u_licenses = []
|
||||
u_licenses = getUserLicenses(lic, userEntity, skus)
|
||||
if not oneLicensePerRow:
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
userEntity['LicensesCount'] = len(u_licenses)
|
||||
if u_licenses:
|
||||
for skuId in u_licenses:
|
||||
userEntity['License'] = skuId
|
||||
userEntity['LicenseDisplay'] = SKU.skuIdToDisplayName(skuId)
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
userEntity['License'] = userEntity['LicenseDisplay'] = ''
|
||||
userEntity['Licenses'] = delimiter.join(u_licenses)
|
||||
userEntity['LicensesDisplay'] = delimiter.join([SKU.skuIdToDisplayName(skuId) for skuId in u_licenses])
|
||||
else:
|
||||
u_licenses = []
|
||||
if not oneLicensePerRow:
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
if u_licenses:
|
||||
for skuId in u_licenses:
|
||||
userEntity['License'] = skuId
|
||||
userEntity['LicenseDisplay'] = SKU.skuIdToDisplayName(skuId)
|
||||
_writeUserEntity(userEntity)
|
||||
else:
|
||||
userEntity['License'] = userEntity['LicenseDisplay'] = ''
|
||||
_writeUserEntity(userEntity)
|
||||
|
||||
def _updateDomainCounts(emailAddress):
|
||||
nonlocal domainCounts
|
||||
@@ -45911,10 +45973,10 @@ def doPrintUsers(entityList=None):
|
||||
showDeleted = True
|
||||
elif entityList is None and myarg == 'select':
|
||||
_, entityList = getEntityToModify(defaultEntityType=Cmd.ENTITY_USERS)
|
||||
elif myarg in SUSPENDED_ARGUMENTS:
|
||||
isSuspended = _getIsSuspended(myarg)
|
||||
elif myarg in ARCHIVED_ARGUMENTS:
|
||||
isArchived = _getIsArchived(myarg)
|
||||
elif myarg == 'issuspended':
|
||||
isSuspended = getBoolean()
|
||||
elif myarg == 'isarchived':
|
||||
isArchived = getBoolean()
|
||||
elif myarg == 'orderby':
|
||||
orderBy, sortOrder = getOrderBySortOrder(USERS_ORDERBY_CHOICE_MAP)
|
||||
elif myarg == 'userview':
|
||||
@@ -46092,6 +46154,8 @@ def doPrintUsers(entityList=None):
|
||||
# If no individual fields were specified (allfields, basic, full) or individual fields other than primaryEmail were specified, look up each user
|
||||
if isSuspended is not None and fieldsList:
|
||||
fieldsList.append('suspended')
|
||||
if isArchived is not None and fieldsList:
|
||||
fieldsList.append('archived')
|
||||
if projectionSet or len(set(fieldsList)) > 1 or showValidColumn:
|
||||
jcount = len(entityList)
|
||||
fields = getFieldsFromFieldsList(fieldsList)
|
||||
|
||||
@@ -462,6 +462,7 @@
|
||||
See: https://support.google.com/mail/answer/7190
|
||||
<QueryGroup> ::= <String>
|
||||
See: https://developers.google.com/admin-sdk/directory/v1/guides/search-groups
|
||||
<QueryItem> ::= <UniqueID>|<String>
|
||||
<QueryMemberRestrictions> ::= <String>
|
||||
See: https://cloud.google.com/identity/docs/reference/rest/v1beta1/SecuritySettings#MemberRestriction
|
||||
<QueryMobile> ::= <String>
|
||||
|
||||
@@ -10,9 +10,24 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 7.22.01
|
||||
### - 7.22.04
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed.
|
||||
Added a variant of `gam create vaulthold` that gets its parameters from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
|
||||
### 7.22.03
|
||||
|
||||
Fix backwards compatability bug introduced in 7.22.00 for `gam print users` that changed `suspended`
|
||||
from a field name to a query option; it is now correctly interpreted as a field name.
|
||||
|
||||
### 7.22.02
|
||||
|
||||
An update to the httplib2 library caused GAM proxy connections to fail; this has been fixed
|
||||
by including the pysocks library needed by the latest httplib2 library.
|
||||
|
||||
### 7.22.00
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ writes the credentials into the file oauth2.txt.
|
||||
admin@server:/Users/admin$ rm -f /Users/admin/GAMConfig/oauth2.txt
|
||||
admin@server:/Users/admin$ gam version
|
||||
WARNING: Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: /Users/admin/GAMConfig/oauth2.txt, Not Found
|
||||
GAM 7.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.22.04 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
MacOS Sequoia 15.6.1 x86_64
|
||||
|
||||
@@ -570,17 +570,12 @@ gam config auto_batch_min 1 csv_output_row_filter "owners.0.emailAddress:notrege
|
||||
### Multiple parents
|
||||
No existing parents are copied for source top/sub files/folders.
|
||||
|
||||
### Removed options
|
||||
The following options will generate an error; they were removed in 6.23.00:
|
||||
* `copysubfileparents` and `copysubfolderparents`.
|
||||
|
||||
### Move Folder Permissions
|
||||
When a folder is moved by recreating it, its permissions are not copied; these options control copying permissions for folders.
|
||||
When a folder is moved by recreating it, its permissions are not copied by the Drive API; these options control copying permissions for folders.
|
||||
|
||||
For options of the form `option [<Boolean>]`; if `<Boolean>` is omitted, `true` is assumed.
|
||||
|
||||
When recreated, a target folder inherits the permissions of its parent folder; these options control whether/how GAM copies the existing source folder permissions;
|
||||
The default values of options introduced in version 6.14.00 are set to match the behavior of earlier versions.
|
||||
|
||||
When `mergewithparent` is `true`:
|
||||
* `copymergewithparentfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder; this is the default action.
|
||||
@@ -594,7 +589,7 @@ When `duplicatefolders` is `merge` and a sub folder is a duplicate:
|
||||
* `copymergedsubfolderpermissions false` - The permissions of the source sub folder are not not copied to the target folder.
|
||||
* `copymergedsubfolderpermissions true` - The permissions of the source sub folder are copied to the target folder; this is the default action.
|
||||
|
||||
When `duplicatefolders` is `duplicatename` or `uniquename` and a top/sub folder is not a duplicate:
|
||||
When `duplicatefolders` is `merge` or `duplicatename` or `uniquename` and a top/sub folder is not a duplicate:
|
||||
* `copytopfolderpermissions true` - The permissions of the source top folder are copied to the target folder; this is the default action.
|
||||
* `copytopfolderpermissions false` - The permissions of the source top folder are not not copied to the target folder.
|
||||
* `copysubfolderpermissions true` - The permissions of the source sub folders are copied to the target folder; this is the default action.
|
||||
|
||||
@@ -424,12 +424,12 @@ gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv mult
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add My Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -447,12 +447,12 @@ gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add Shared Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
## Remove ACLs for all users-groups in external domains
|
||||
@@ -469,18 +469,22 @@ Replace `<Types>` as required:
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions pm notrole owner <Types> <Domains> em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add My Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./AddMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -499,18 +503,22 @@ Replace `<Types>` as required:
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect csv ./SharedDriveShares.csv multiprocess redirect stderr - multiprocess csv SharedDriveOrganizers.csv gam user "~organizers" print filelist select shareddriveid "~id" fields id,name,mimetype,basicpermissions,driveid showdrivename pm <Types> <Domains> inherited false em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
Add Shared Drive ACLs with a different email address and the same role.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefleacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
gam config num_threads 20 redirect stdout ./ReplaceSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" add drivefileacl "~id" "~permission.type" newemail@domain.rom role "~permission.role"
|
||||
```
|
||||
|
||||
## Remove domainCanFind-domainWithLink ACLs for internal domain
|
||||
@@ -529,7 +537,7 @@ gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv mult
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -546,7 +554,7 @@ gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
## Remove My Drive ACLs for external domains
|
||||
@@ -558,13 +566,17 @@ Get My Drive ACLs sharing to external domain(s)
|
||||
Replace `<Domains>` with specification of external domain(s)
|
||||
* `domain domain.com` - A single external domain
|
||||
* `domainlist domain1.com,domain2.com,domain3.com...` - A list of external domains
|
||||
|
||||
If you want domains other than your internal domain(s)
|
||||
* `notdomain domain.com` - A single internal domain
|
||||
* `notdomainlist domain1.com,domain2.com,domain3.com...` - A list of internal domains
|
||||
```
|
||||
gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv multiprocess redirect stderr - multiprocess all users print filelist fields id,name,mimetype,basicpermissions pm type domain <Domains> em pmfilter oneitemperrow
|
||||
```
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
## Remove anyoneCanFind-anyoneWithLink ACLs
|
||||
@@ -583,7 +595,7 @@ gam config auto_batch_min 1 num_threads 20 redirect csv ./MyDriveShares.csv mult
|
||||
|
||||
Delete those My Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteMyDriveShares.txt multiprocess redirect stderr stdout csv MyDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
### Shared Drives
|
||||
@@ -599,5 +611,5 @@ gam config num_threads 20 csv_input_row_filter "organizers:regex:^.+$" redirect
|
||||
|
||||
Delete those Shared Drive ACLs.
|
||||
```
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefleacl "~id" "id:~~permission.id~~"
|
||||
gam config num_threads 20 redirect stdout ./DeleteSharedDriveShares.txt multiprocess redirect stderr stdout csv SharedDriveShares.csv gam user "~Owner" delete drivefileacl "~id" "id:~~permission.id~~"
|
||||
```
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<MatterItem> ::= <UniqueID>|<String>
|
||||
<MatterState> ::= open|closed|deleted
|
||||
<MatterStateList> ::= "<MatterState>(,<MatterState>)*"
|
||||
<QueryItem> ::= <UniqueID>|<String>
|
||||
<SharedDriveID> ::= <String>
|
||||
<SharedDriveIDList> ::= "<SharedDriveID>(,<SharedDriveID>)*"
|
||||
<URL> ::= <String>
|
||||
@@ -259,7 +260,7 @@ gam create vaultexport|export matter <MatterItem> [name <String>] corpus calenda
|
||||
[includerooms <Boolean>]
|
||||
[excludedrafts <Boolean>] [mailclientsideencryption any|encrypted|unencrypted]
|
||||
[showconfidentialmodecontent <Boolean>] [usenewexport <Boolean>] [exportlinkeddrivefiles <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[format ics|mbox|pst|xml]
|
||||
[region any|europe|us] [showdetails|returnidonly]
|
||||
```
|
||||
@@ -376,7 +377,8 @@ For `corpus groups`, `corpus hangouts_chat`, `corpus mail` and `corpus voice`, y
|
||||
* `format mbox` - Export in MBOX format, this is the default
|
||||
* `format pst` - Export in PST format
|
||||
|
||||
For `corpus voice` you can specify thet data covered by the export:
|
||||
For `corpus voice` you can specify thet data covered by the export,
|
||||
multiple values are allowed.:
|
||||
* `covereddata calllogs` - Call logs
|
||||
* `covereddata textmessages` - Voice text messages
|
||||
* `covereddata voicemail` - Voicemail
|
||||
@@ -606,13 +608,28 @@ The `shownames` argument controls whether account and org unit names are display
|
||||
|
||||
## Vault Holds
|
||||
## Create Vault Holds
|
||||
### Create a hold from a saved Vault query.
|
||||
```
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>]
|
||||
vaultquery <QueryItem>
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
Specify the name of the hold:
|
||||
* `name <String>` - The hold will be named `<String>`
|
||||
* `default` - The hold will be named `GAM <corpus> Hold - <Time>`
|
||||
|
||||
Use the `showdetails` option to have the full details of the hold displayed.
|
||||
|
||||
Use the `returnidonly` option to have only the hold ID displayed.
|
||||
|
||||
### Create a hold from parameters.
|
||||
```
|
||||
gam create vaulthold|hold matter <MatterItem> [name <String>] corpus calendar|drive|mail|groups|hangouts_chat|voice
|
||||
[(accounts|groups|users <EmailItemList>) | (orgunit|org|ou <OrgUnit>)]
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails|returnidonly]
|
||||
```
|
||||
@@ -649,7 +666,8 @@ 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 voice` you can specify the data covered by the hold:
|
||||
For `corpus voice` you can specify the data covered by the hold,
|
||||
multiple values are allowed.:
|
||||
* `covereddata calllogs` - Call logs
|
||||
* `covereddata textmessages` - Voice text messages
|
||||
* `covereddata voicemail` - Voicemail
|
||||
@@ -665,7 +683,7 @@ gam update vaulthold|hold <HoldItem> matter <MatterItem>
|
||||
[query <QueryVaultCorpus>]
|
||||
[terms <String>] [start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>]
|
||||
[includerooms <Boolean>]
|
||||
[covereddata calllogs|textmessages|voicemails]
|
||||
(covereddata calllogs|textmessages|voicemails)*
|
||||
[includeshareddrives <Boolean>]
|
||||
[showdetails]
|
||||
```
|
||||
@@ -684,7 +702,8 @@ For a hold with `corpus hangouts_chat` you can specify advanced search options:
|
||||
* `includerooms False` - Do not include rooms, this is the default
|
||||
* `includerooms True` - Include rooms
|
||||
|
||||
For a hold with `corpus voice` you can specify the data covered by the hold:
|
||||
For a hold with `corpus voice` you can specify the data covered by the hold,
|
||||
multiple values are allowed.:
|
||||
* `covereddata calllogs` - Call logs
|
||||
* `covereddata textmessages` - Voice text messages
|
||||
* `covereddata voicemail` - Voicemail
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.22.04 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
macOS Sequoia 15.7 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
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.22.04 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
macOS Sequoia 15.7 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
|
||||
```
|
||||
gam version extended
|
||||
GAM 7.22.01 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.22.04 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.13.7 64-bit final
|
||||
macOS Sequoia 15.7 x86_64
|
||||
|
||||
@@ -180,29 +180,3 @@ Service Account Access
|
||||
* [Users - Tasks](Users-Tasks)
|
||||
* [Users - YouTube](Users-YouTube)
|
||||
* [Users - Web Resources and Sites](Users-Web-Resources-and-Sites)
|
||||
|
||||
GAM Tutorials
|
||||
* [Account Auditing](l-ExamplesAccountAuditing)
|
||||
* [Calendar Settings](l-CalendarExamples)
|
||||
* [Chat Bot commands](Chat-Bot)
|
||||
* [Chrome Browser Management](l-Chrome-Browser-Management)
|
||||
* [Chrome Policy Settings](l-Chrome-Policy-Settings)
|
||||
* [Context Aware Access levels](Context-Aware-Access-Levels)
|
||||
* [Data Transfers](l-Data-Transfers)
|
||||
* [Domain Verification](l-DomainVerification)
|
||||
* [Google Drive Management](l-GoogleDriveManagement)
|
||||
* [Group Settings](l-GAM3GroupSettings)
|
||||
* [Inbound SSO Settings](l-Inbound-SSO-Settings)
|
||||
* [Managing Admins](l-Managing-Admins)
|
||||
* [Managing Classroom](l-Managing-Google-Classroom)
|
||||
* [Managing Custom User Schemas](l-Custom-Schemas)
|
||||
* [Managing Devices](l-Managing-Devices)
|
||||
* [Managing Organizations](l-ExamplesOrganizations)
|
||||
* [Managing Product Licenses](l-LicenseExamples)
|
||||
* [Managing Users, Groups, Aliases, Domains, Mobile and Chrome Devices, and Resource Calendars](l-GAM3DirectoryCommands)
|
||||
* [OAuth Authentication Related Commands](l-OAuthKeyManagement)
|
||||
* [Print Users, Groups, Aliases, Mobile and Chrome OS devices, OUs, Licenses and Reports](l-GAM3CSVListings)
|
||||
* [Printers](l-Printers)
|
||||
* [Unmanaged Users and Invitations](l-UnmanagedUsersExamples)
|
||||
* [User Email Settings](l-ExamplesEmailSettings)
|
||||
* [User Security Settings](l-SecurityExamples)
|
||||
|
||||
Reference in New Issue
Block a user