mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-03 22:01:39 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
42ee41d218 | ||
|
|
d8f0666e70 | ||
|
|
3d15d2a820 | ||
|
|
0c593b5809 | ||
|
|
d76ef999c5 | ||
|
|
ddaad4d655 | ||
|
|
36a1bdc56b | ||
|
|
089a5994aa | ||
|
|
3e9b46b650 | ||
|
|
7ca3b4d7da | ||
|
|
22d70ca2c3 | ||
|
|
b3acdf5955 | ||
|
|
c13a5215fe | ||
|
|
45750b591a | ||
|
|
c76f1b2128 | ||
|
|
e85e7f6868 | ||
|
|
055c74ed2e | ||
|
|
4ba9385c23 | ||
|
|
9d8442c7ad | ||
|
|
cc19878ba4 | ||
|
|
23ed20a298 | ||
|
|
5b32bc31c7 | ||
|
|
e1260dbd95 | ||
|
|
ea41edbfcb | ||
|
|
869eb3a0c2 | ||
|
|
61735701b3 | ||
|
|
c60ef582be | ||
|
|
cd8c43a0cc | ||
|
|
7582c42eff | ||
|
|
d9a75af87c | ||
|
|
6c443fa0c6 | ||
|
|
b6a9229a67 | ||
|
|
84175ba80d | ||
|
|
56c2b77f25 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -165,7 +165,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
cache.tar.xz
|
||||
key: gam-${{ matrix.jid }}-20260508
|
||||
key: gam-${{ matrix.jid }}-20260523
|
||||
|
||||
- name: Untar Cache archive
|
||||
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
|
||||
|
||||
@@ -10,15 +10,15 @@ authors = [
|
||||
dependencies = [
|
||||
"arrow==1.4.0",
|
||||
"chardet==7.4.3",
|
||||
"cryptography==47.0.0",
|
||||
"cryptography==48.0.0",
|
||||
"distro==1.9.0 ; sys_platform=='linux'",
|
||||
"filelock==3.29.0",
|
||||
"google-api-python-client==2.195.0",
|
||||
"google-auth-httplib2==0.3.1",
|
||||
"google-auth-oauthlib==1.3.1",
|
||||
"google-auth==2.50.0",
|
||||
"google-api-python-client==2.196.0",
|
||||
"google-auth-httplib2==0.4.0",
|
||||
"google-auth-oauthlib==1.4.0",
|
||||
"google-auth==2.53.0",
|
||||
"httplib2==0.31.2",
|
||||
"lxml==6.1.0",
|
||||
"lxml==6.1.1",
|
||||
"passlib==1.7.4",
|
||||
"pathvalidate==3.3.1",
|
||||
"pysocks==1.7.1",
|
||||
|
||||
@@ -270,7 +270,7 @@ If an item contains spaces, it should be surrounded by ".
|
||||
assuredcontrolsplus | 1010390002 | Assured Controls Plus |
|
||||
bce | beyondcorp | beyondcorpenterprise | cep | chromeenterprisepremium | 1010400001 | Chrome Enterprise Premium |
|
||||
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
|
||||
cloudidentity | identity | 1010010001 | Cloud Identity |
|
||||
cloudidentityfree | cloudidentity | identity | 1010010001 | Cloud Identity Free |
|
||||
cloudidentitypremium | identitypremium | 1010050001 | Cloud Identity Premium |
|
||||
cloudsearch | 1010350001 | Cloud Search |
|
||||
colabpro | 1010500001 | Colab Pro |
|
||||
@@ -1665,11 +1665,15 @@ gam <UserTypeEntity> show analyticdatastreams
|
||||
<CalendarEntity> ::=
|
||||
<CalendarList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
|
||||
<CalendarACLRole> ::= editor|freebusy|freebusyreader|owner|reader|writer|none
|
||||
<CalendarACLScope> ::= <EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|domain:<DomainName>|domain|default
|
||||
<CalendarACLScopeList> ::= "<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarACLScopeEntity> ::=
|
||||
<CalendarACLScopeList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
<CalendarACLRole> ::=
|
||||
editor|freebusy|freebusyreader|owner|reader|writer|writerwithoutprivateaccess|none
|
||||
<CalendarACLScope> ::=
|
||||
<EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|
|
||||
domain:<DomainName>|domain|default
|
||||
<CalendarACLScopeList> ::=
|
||||
"<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarACLScopeEntity>::=
|
||||
<CalendarACLScopeList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
|
||||
gam calendars <CalendarEntity> create|add acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
|
||||
gam calendars <CalendarEntity> update acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
|
||||
@@ -2511,6 +2515,7 @@ gam <CrOSTypeEntity> update <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatc
|
||||
autoupdateexpiration|
|
||||
autoupdatethrough|
|
||||
backlightinfo|
|
||||
bluetoothadapterinfo|
|
||||
bootmode|
|
||||
chromeostype|
|
||||
cpuinfo|
|
||||
@@ -2544,6 +2549,7 @@ gam <CrOSTypeEntity> update <CrOSAttribute>+ [quickcrosmove [<Boolean>]] [nobatc
|
||||
orgunitpath|org|ou|
|
||||
osupdatestatus|
|
||||
osversion|
|
||||
osversioncompliance|
|
||||
platformversion|
|
||||
recentusers|
|
||||
screenshotfiles|
|
||||
@@ -2725,25 +2731,30 @@ gam <CrOSTypeEntity> get devicefile [select <DeviceFileEntity>] [targetfolder <F
|
||||
Print telemetry data for specified CrOS devices.
|
||||
|
||||
<CrOSTelemetryFieldName> ::=
|
||||
appreport|
|
||||
audiostatusreport|
|
||||
batteryinfo|
|
||||
batterystatusreport|
|
||||
bootPerformancereport|
|
||||
bootperformancereport|
|
||||
cpuinfo|
|
||||
cpustatusreport|
|
||||
customer|
|
||||
deviceid|
|
||||
graphicsinfo|
|
||||
graphicsstatusreport|
|
||||
heartbeatstatusreport|
|
||||
kioskappstatusreport|
|
||||
memoryinfo|
|
||||
memorystatusreport|
|
||||
name|
|
||||
networkbandwidthreport|
|
||||
networkdiagnosticsreport|
|
||||
networkinfo|
|
||||
networkstatusreport|
|
||||
orgunitid|
|
||||
osupdatestatus|
|
||||
peripheralsreport|
|
||||
runtimecountersreport|
|
||||
serialnumber|
|
||||
storageinfo|
|
||||
storagestatusreport|
|
||||
@@ -2751,20 +2762,22 @@ Print telemetry data for specified CrOS devices.
|
||||
<CrOSTelemetryFieldNameList> ::= "<CrOSTelemetryFieldName>(,<CrOSTelemetryFieldName>)*"
|
||||
|
||||
<CrOSTelemetryListFieldName> ::=
|
||||
appreport|
|
||||
audiostatusreport|
|
||||
batteryinfo|
|
||||
batterystatusreport|
|
||||
bootperformancereport|
|
||||
cpuinfo|
|
||||
cpustatusreport|
|
||||
graphicsstatusreport|
|
||||
heartbeatstatusreport|
|
||||
kioskappstatusreport|
|
||||
memorystatusreport|
|
||||
networkbandwidthreport|
|
||||
networkdiagnosticsreport|
|
||||
networkstatusreport|
|
||||
osupdatestatus|
|
||||
peripheralsreport|
|
||||
storagestatusreport|
|
||||
thunderboltinfo
|
||||
runtimecountersreport|
|
||||
storagestatusreport
|
||||
<CrOSTelemetryListFieldNameList> ::= "<CrOSTelemetryListFieldName>(,<CrOSTelemetryLIstFieldName>)*"
|
||||
|
||||
gam info crostelemetry <SerialNumber>
|
||||
@@ -2781,7 +2794,7 @@ gam show crostelemetry
|
||||
gam print crostelemetry [todrive <ToDriveAttribute>*]
|
||||
[(ou|org|orgunit|ou_and_children <OrgUnitItem>)|(cros_sn <SerialNumber>)|(filter <String>)]
|
||||
<CrOSTelemetryFieldName>* [fields <CrOSTelemetryFieldNameList>]
|
||||
[reverselists <CrOSTelemetryListFieldNameList>]
|
||||
[reverselists <CrOSTelemetryListFieldNameList>] [oneitemperrow]
|
||||
[start <Date>] [end <Date>] [listlimit <Number>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
|
||||
@@ -4885,10 +4898,15 @@ gam print resources [todrive <ToDriveAttribute>*] [allfields|<ResourceFieldName>
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
|
||||
<CalendarACLRole> ::= editor|freebusy|freebusyreader|owner|reader|writer|none
|
||||
<CalendarACLScope> ::= <EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|domain:<DomainName>|domain|default
|
||||
<CalendarACLScopeList> ::= "<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarACLScopeEntity> ::= <CalendarACLScopeList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
<CalendarACLRole> ::=
|
||||
editor|freebusy|freebusyreader|owner|reader|writer|writerwithoutprivateaccess|none
|
||||
<CalendarACLScope> ::=
|
||||
<EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|
|
||||
domain:<DomainName>|domain|default
|
||||
<CalendarACLScopeList> ::=
|
||||
"<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarACLScopeEntity>::=
|
||||
<CalendarACLScopeList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
|
||||
gam resource <ResourceID> create|add acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
|
||||
gam resource <ResourceID> update acls|calendaracls <CalendarACLRole> <CalendarACLScopeEntity> [sendnotifications <Boolean>]
|
||||
@@ -6117,7 +6135,8 @@ gam <UserTypeEntity> print businessprofileaccounts [todrive <ToDriveAttribute>*]
|
||||
|
||||
# Users - Calendars
|
||||
|
||||
<CalendarACLRole> ::= editor|freebusy|freebusyreader|owner|reader|writer
|
||||
<CalendarACLRole> ::=
|
||||
editor|freebusy|freebusyreader|owner|reader|writer|writerwithoutprivateaccess|none
|
||||
|
||||
<CalendarSelectProperty> ::=
|
||||
(minaccessrole <CalendarACLRole>)|
|
||||
@@ -6768,13 +6787,41 @@ gam <UserTypeEntity> info chatmessage name <ChatMessage>
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> show chatmessages
|
||||
<ChatSpace>+
|
||||
[showdeleted [<Boolean>]] [filter <String>]
|
||||
[showdeleted [<Boolean>]
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime [ascending|descending]]
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> print chatmessages [todrive <ToDriveAttribute>*]
|
||||
<ChatSpace>+
|
||||
[showdeleted [<Boolean>]] [filter <String>]
|
||||
[showdeleted [<Boolean>]
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[thread <ChatThread>])
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime [ascending|descending]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
|
||||
gam <UserTypeEntity> show chatsearchmessages
|
||||
keywords <StringList>
|
||||
<ChatSpace>*
|
||||
[displaynames [all|any] <StringList>]
|
||||
[senders <EmailAddressEntity>]*
|
||||
[usermentions [all|any] <EmailAddressEntity>]*
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[hasattachment]
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime|relevance]
|
||||
[formatjson]
|
||||
gam <UserTypeEntity> print chatsearchmessages [todrive <ToDriveAttribute>*]
|
||||
keywords <StringList>
|
||||
<ChatSpace>*
|
||||
[displaynames [all|any] <StringList>]
|
||||
[senders <EmailAddressEntity>]*
|
||||
[usermentions [all|any] <EmailAddressEntity>]*
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[hasattachment]
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime|relevance]
|
||||
[formatjson [quotechar <Character>]]
|
||||
|
||||
gam <UserTypeEntity> info chatevent name <ChatEvent>
|
||||
@@ -8031,12 +8078,12 @@ gam <UserTypeEntity> export thread|threads
|
||||
[quick|notquick] [doit] [max_to_export <Number>])|(ids <ThreadIDEntity>)
|
||||
[targetfolder <FilePath>] [targetname <FileName>] [overwrite [<Boolean>]]
|
||||
|
||||
gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
gam <UserTypeEntity> forward message|messages [recipient|to] <RecipientEntity>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
[subject <String>] [addorigfieldstosubject [<Boolean>]] [altcharset <String>]
|
||||
gam <UserTypeEntity> forward thread|thtreads recipient|to <RecipientEntity>
|
||||
gam <UserTypeEntity> forward thread|thtreads [recipient|to] <RecipientEntity>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
|
||||
@@ -1,3 +1,71 @@
|
||||
7.44.03
|
||||
|
||||
Added `writerwithoutprivateaccess` to `<CalendarACLRole>`; this will become effective 2026-06-29.
|
||||
* See: https://developers.google.com/workspace/calendar/release-notes#June_01_2026
|
||||
|
||||
7.44.02
|
||||
|
||||
Added fields `bluetoothadapterinfo` and `osversioncompliance` to `<CrOSFieldName>` for use
|
||||
in `gam info|print cros`.
|
||||
|
||||
7.44.01
|
||||
|
||||
Added option `oneitemperrow` to `gam print crostelemetry` to have each of a device's
|
||||
report field entries displayed on a separate row with all of the other device fields.
|
||||
|
||||
Added additional fields to `<CrOSTelemetryFieldName>`and `<CrOSTelemetryListFieldName>`:
|
||||
```
|
||||
appreport
|
||||
heartbeatstatusreport
|
||||
kioskappstatusreport
|
||||
networkbandwidthreport
|
||||
runtimecountersreport
|
||||
```
|
||||
|
||||
7.44.00
|
||||
|
||||
Added support for User data `archivalTime` and `suspensionTime` that is available
|
||||
when fields `archived` and `suspended` are requested in `gam info user` and `gam print users`.
|
||||
|
||||
Added the following options to `gam <UserTypeEntity> show chatmessages` to simplify specifying a filter.
|
||||
```
|
||||
start|starttime <Date>|<Time>
|
||||
end|endtime <Date>|<Time>
|
||||
range <Date>|<Time> <Date>|<Time>
|
||||
thread <ChatThread>
|
||||
```
|
||||
|
||||
Added commands to search for and display chat messages.
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-messages-by-searching
|
||||
|
||||
These commands are in Developer Preview; to use them you must have these values set in `gam.cfg`.
|
||||
```
|
||||
developer_preview_apis = chat
|
||||
developer_preview_api_key = <DeveloperPreviewKey>
|
||||
```
|
||||
|
||||
Upgraded to Python 3.14.5.
|
||||
|
||||
7.43.10
|
||||
|
||||
Updated `gam <UserTypeEntity> forward message|thread [recipient|to] <RecipientEntity>` to not forward messages
|
||||
to the `Bcc` recipients of the original message.
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> forward message|thread [recipient|to] <RecipientEntity> addorigfieldstosubject`
|
||||
where the recipient of the forwarded message was added to the subject line instead of the recipient of the original message.
|
||||
|
||||
7.43.09
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> print filelist` that caused a trap.
|
||||
|
||||
7.43.08
|
||||
|
||||
Fixed bug and formatting issues in `gam info device <DeviceEntity>`.
|
||||
|
||||
7.43.07
|
||||
|
||||
Improved validation of `<QueryCrOS>`, `<QueryDevice>` and `<QueryMobile>`.
|
||||
|
||||
7.43.06
|
||||
|
||||
Updated commands that use `<QueryCrOS>`, `<QueryDevice>` or `<QueryMobile>` to validate
|
||||
|
||||
@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
|
||||
"""
|
||||
|
||||
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
|
||||
__version__ = '7.43.06'
|
||||
__version__ = '7.44.03'
|
||||
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
|
||||
|
||||
# pylint: disable=wrong-import-position
|
||||
@@ -1002,6 +1002,13 @@ def getChoiceAndValue(item, choices, delimiter):
|
||||
missingArgumentExit(item)
|
||||
invalidChoiceExit(choice, choices, False)
|
||||
|
||||
AND_OR_CONJUNCTION_MAP = {
|
||||
'and': 'AND',
|
||||
'or': 'OR',
|
||||
'all': 'AND',
|
||||
'any': 'OR',
|
||||
}
|
||||
|
||||
SUSPENDED_ARGUMENTS = {'notsuspended', 'suspended', 'issuspended'}
|
||||
SUSPENDED_CHOICE_MAP = {'notsuspended': False, 'suspended': True}
|
||||
def _getIsSuspended(myarg):
|
||||
@@ -6072,7 +6079,13 @@ def getQueries(myarg):
|
||||
return shlexSplitList(getString(Cmd.OB_QUERY_LIST))
|
||||
|
||||
def _validateDeviceQuery(entityType, query):
|
||||
if (':' not in query) or ('?' in query):
|
||||
if ':' in query:
|
||||
qfield, qvalue = query.split(':', 1)
|
||||
qfield = qfield.strip()
|
||||
else:
|
||||
qfield = ''
|
||||
qvalue = query
|
||||
if (not qfield) or (not qvalue) or ('?' in query):
|
||||
Cmd.Backup()
|
||||
usageErrorExit(Msg.INVALID_DEVICE_QUERY.format(Ent.Singular(entityType), query))
|
||||
|
||||
@@ -24636,7 +24649,7 @@ def _getFilterDateTime():
|
||||
return (filterDate, filterDate.replace(tzinfo='UTC'))
|
||||
|
||||
CROS_FIELDS_CHOICE_MAP = {
|
||||
'activetimeranges': ['activeTimeRanges.activeTime', 'activeTimeRanges.date'],
|
||||
'activetimeranges': 'activeTimeRanges',
|
||||
'annotatedassetid': 'annotatedAssetId',
|
||||
'annotatedlocation': 'annotatedLocation',
|
||||
'annotateduser': 'annotatedUser',
|
||||
@@ -24645,12 +24658,13 @@ CROS_FIELDS_CHOICE_MAP = {
|
||||
'autoupdateexpiration': 'autoUpdateExpiration',
|
||||
'autoupdatethrough': 'autoUpdateThrough',
|
||||
'backlightinfo': 'backlightInfo',
|
||||
'bluetoothadapterinfo': 'bluetoothAdapterInfo',
|
||||
'bootmode': 'bootMode',
|
||||
'chromeostype': 'chromeOsType',
|
||||
'cpuinfo': 'cpuInfo',
|
||||
'cpustatusreports': 'cpuStatusReports',
|
||||
'deprovisionreason': 'deprovisionReason',
|
||||
'devicefiles': ['deviceFiles.type', 'deviceFiles.createTime'],
|
||||
'devicefiles': 'deviceFiles',
|
||||
'deviceid': 'deviceId',
|
||||
'devicelicensetype': 'deviceLicenseType',
|
||||
'diskspaceusage': 'diskSpaceUsage',
|
||||
@@ -24680,9 +24694,10 @@ CROS_FIELDS_CHOICE_MAP = {
|
||||
'orgunitpath': 'orgUnitPath',
|
||||
'osupdatestatus': 'osUpdateStatus',
|
||||
'osversion': 'osVersion',
|
||||
'osversioncompliance': 'osVersionCompliance',
|
||||
'ou': 'orgUnitPath',
|
||||
'platformversion': 'platformVersion',
|
||||
'recentusers': ['recentUsers.email', 'recentUsers.type'],
|
||||
'recentusers': 'recentUsers',
|
||||
'screenshotfiles': 'screenshotFiles',
|
||||
'serialnumber': 'serialNumber',
|
||||
'status': 'status',
|
||||
@@ -24690,11 +24705,11 @@ CROS_FIELDS_CHOICE_MAP = {
|
||||
'systemramfreereports': 'systemRamFreeReports',
|
||||
'systemramtotal': 'systemRamTotal',
|
||||
'tag': 'annotatedAssetId',
|
||||
'timeranges': ['activeTimeRanges.activeTime', 'activeTimeRanges.date'],
|
||||
'times': ['activeTimeRanges.activeTime', 'activeTimeRanges.date'],
|
||||
'timeranges': 'activeTimeRanges',
|
||||
'times': 'activeTimeRanges',
|
||||
'tpmversioninfo': 'tpmVersionInfo',
|
||||
'user': 'annotatedUser',
|
||||
'users': ['recentUsers.email', 'recentUsers.type'],
|
||||
'users': 'recentUsers',
|
||||
'willautorenew': 'willAutoRenew',
|
||||
}
|
||||
CROS_BASIC_FIELDS_LIST = ['deviceId', 'annotatedAssetId', 'annotatedLocation', 'annotatedUser', 'lastSync', 'notes', 'serialNumber', 'status']
|
||||
@@ -24715,6 +24730,7 @@ CROS_SCALAR_PROPERTY_PRINT_ORDER = [
|
||||
'firmwareVersion',
|
||||
'platformVersion',
|
||||
'osVersion',
|
||||
'osVersionCompliance',
|
||||
'bootMode',
|
||||
'meid',
|
||||
'dockMacAddress',
|
||||
@@ -24963,6 +24979,9 @@ def infoCrOSDevices(entityList):
|
||||
backlightInfo = _filterBasicList(cros, 'backLightInfo', True, listLimit)
|
||||
if backlightInfo:
|
||||
showJSON('backlightInfo', backlightInfo, dictObjectsKey={'backlightInfo': 'path'})
|
||||
bluetoothAdapterInfo = _filterBasicList(cros, 'bluetoothAdapterInfo', True, listLimit)
|
||||
if bluetoothAdapterInfo:
|
||||
showJSON('bluetoothAdapterInfo', bluetoothAdapterInfo, dictObjectsKey={'bluetoothAdapterInfo': 'address'})
|
||||
fanInfo = _filterBasicList(cros, 'fanInfo', True, listLimit)
|
||||
if fanInfo:
|
||||
showJSON('fanInfo', fanInfo)
|
||||
@@ -25192,7 +25211,8 @@ CROS_ENTITIES_MAP = {
|
||||
}
|
||||
|
||||
CROS_INDEXED_TITLES = ['activeTimeRanges', 'recentUsers', 'deviceFiles',
|
||||
'cpuStatusReports', 'cpuInfo', 'backlightInfo', 'fanInfo', 'diskVolumeReports', 'lastKnownNetwork', 'screenshotFiles', 'systemRamFreeReports']
|
||||
'cpuStatusReports', 'cpuInfo', 'backlightInfo', 'bluetoothAdapterInfo', 'fanInfo',
|
||||
'diskVolumeReports', 'lastKnownNetwork', 'screenshotFiles', 'systemRamFreeReports']
|
||||
|
||||
# gam print cros [todrive <ToDriveAttribute>*]
|
||||
# [(query <QueryCrOS>)|(queries <QueryCrOSList>) [querytime<String> <Time>]
|
||||
@@ -25266,7 +25286,7 @@ def doPrintCrOSDevices(entityList=None):
|
||||
return
|
||||
row = {}
|
||||
for attrib in cros:
|
||||
if attrib in {'cpuInfo', 'backlightInfo', 'fanInfo'}:
|
||||
if attrib in {'cpuInfo', 'backlightInfo', 'bluetoothAdapterInfo', 'fanInfo'}:
|
||||
flattenJSON({attrib: cros[attrib]}, flattened=row)
|
||||
elif attrib not in {'kind', 'etag', 'diskSpaceUsage', 'osUpdateStatus', 'tpmVersionInfo', 'activeTimeRanges', 'recentUsers',
|
||||
'deviceFiles', 'cpuStatusReports', 'diskVolumeReports', 'lastKnownNetwork', 'screenshotFiles', 'systemRamFreeReports'}:
|
||||
@@ -25298,7 +25318,7 @@ def doPrintCrOSDevices(entityList=None):
|
||||
for key in ['email', 'type']:
|
||||
new_row[f'recentUsers{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{key}'] = recentUsers[i][key]
|
||||
if i < lenDF:
|
||||
for key in ['type', 'createTime']:
|
||||
for key in ['name', 'type', 'downloadUrl', 'createTime']:
|
||||
new_row[f'deviceFiles{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}{key}'] = deviceFiles[i][key]
|
||||
if i < lenCSR:
|
||||
new_row[f'cpuStatusReports{GC.Values[GC.CSV_OUTPUT_SUBFIELD_DELIMITER]}reportTime'] = cpuStatusReports[i]['reportTime']
|
||||
@@ -25814,6 +25834,7 @@ def doPrintCrOSEntity(entityList):
|
||||
doPrintCrOSActivity(entityList)
|
||||
|
||||
CROS_TELEMETRY_FIELDS_CHOICE_MAP = {
|
||||
'appreport': 'appReport',
|
||||
'audiostatusreport': 'audioStatusReport',
|
||||
'batteryinfo': 'batteryInfo',
|
||||
'batterystatusreport': 'batteryStatusReport',
|
||||
@@ -25824,35 +25845,41 @@ CROS_TELEMETRY_FIELDS_CHOICE_MAP = {
|
||||
'deviceid': 'deviceId',
|
||||
'graphicsinfo': 'graphicsInfo',
|
||||
'graphicsstatusreport': 'graphicsStatusReport',
|
||||
'heartbeatstatusreport': 'heartbeatStatusReport',
|
||||
'kioskappstatusreport': 'kioskAppStatusReport',
|
||||
'memoryinfo': 'memoryInfo',
|
||||
'memorystatusreport': 'memoryStatusReport',
|
||||
'name': 'name',
|
||||
'networkinfo': 'networkInfo',
|
||||
'networkbandwidthreport': 'networkBandwidthReport',
|
||||
'networkdiagnosticsreport': 'networkDiagnosticsReport',
|
||||
'networkinfo': 'networkInfo',
|
||||
'networkstatusreport': 'networkStatusReport',
|
||||
'orgunitid': 'orgUnitId',
|
||||
'osupdatestatus': 'osUpdateStatus',
|
||||
'peripheralsreport': 'peripheralsReport',
|
||||
'runtimecountersreport': 'runtimeCountersReport',
|
||||
'serialnumber': 'serialNumber',
|
||||
'storageinfo': 'storageInfo',
|
||||
'storagestatusreport': 'storageStatusReport',
|
||||
'thunderboltinfo': 'thunderboltInfo',
|
||||
}
|
||||
CROS_TELEMETRY_LIST_FIELDS_CHOICE_MAP = {
|
||||
'appreport': 'appReport',
|
||||
'audiostatusreport': 'audioStatusReport',
|
||||
'batteryinfo': 'batteryInfo',
|
||||
'batterystatusreport': 'batteryStatusReport',
|
||||
'bootperformancereport': 'bootPerformanceReport',
|
||||
'cpuinfo': 'cpuInfo',
|
||||
'cpustatusreport': 'cpuStatusReport',
|
||||
'graphicsstatusreport': 'graphicsStatusReport',
|
||||
'heartbeatstatusreport': 'heartbeatStatusReport',
|
||||
'kioskappstatusreport': 'kioskAppStatusReport',
|
||||
'memorystatusreport': 'memoryStatusReport',
|
||||
'networkbandwidthreport': 'networkBandwidthReport',
|
||||
'networkdiagnosticsreport': 'networkDiagnosticsReport',
|
||||
'networkstatusreport': 'networkStatusReport',
|
||||
'osupdatestatus': 'osUpdateStatus',
|
||||
'peripheralsreport': 'peripheralsReport',
|
||||
'runtimecountersreport': 'runtimeCountersReport',
|
||||
'storagestatusreport': 'storageStatusReport',
|
||||
'thunderboltinfo': 'thunderboltInfo',
|
||||
}
|
||||
|
||||
CROS_TELEMETRY_SCALAR_FIELDS = ['deviceId', 'serialNumber', 'customer', 'name', 'orgUnitId', 'orgUnitPath']
|
||||
@@ -25874,7 +25901,7 @@ CROS_TELEMETRY_TIME_OBJECTS = {'reportTime', 'lastUpdateTime', 'lastUpdateCheckT
|
||||
# gam print crostelemetry [todrive <ToDriveAttribute>*]
|
||||
# [(ou|org|orgunit|ou_and_children <OrgUnitItem>)|(cros_sn <SerialNumber>)|(filter <String>)]
|
||||
# <CrOSTelemetryFieldName>* [fields <CrOSTelemetryFieldNameList>]
|
||||
# [reverselists <CrOSTelemetryListFieldNameList>]
|
||||
# [reverselists <CrOSTelemetryListFieldNameList>] [oneitemperrow]
|
||||
# [start <Date>] [end <Date>] [listlimit <Number>]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
def doInfoPrintShowCrOSTelemetry():
|
||||
@@ -25915,13 +25942,32 @@ def doInfoPrintShowCrOSTelemetry():
|
||||
|
||||
def _printDevice(device):
|
||||
_cleanDevice(device)
|
||||
if not FJQC.formatJSON:
|
||||
csvPF.WriteRowTitles(flattenJSON(device, timeObjects=CROS_TELEMETRY_TIME_OBJECTS))
|
||||
else:
|
||||
if FJQC.formatJSON:
|
||||
if (not csvPF.rowFilter and not csvPF.rowDropFilter) or csvPF.CheckRowTitles(flattenJSON(device, timeObjects=CROS_TELEMETRY_TIME_OBJECTS)):
|
||||
csvPF.WriteRowNoFilter({'deviceId': device['deviceId'],
|
||||
'JSON': json.dumps(cleanJSON(device, timeObjects=CROS_TELEMETRY_TIME_OBJECTS),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
return
|
||||
if not oneItemPerRow:
|
||||
csvPF.WriteRowTitles(flattenJSON(device, timeObjects=CROS_TELEMETRY_TIME_OBJECTS))
|
||||
return
|
||||
listLens = {}
|
||||
maxLen = 0
|
||||
for field in CROS_TELEMETRY_LIST_FIELDS_CHOICE_MAP.values():
|
||||
if field in device:
|
||||
listLens[field] = len(device[field])
|
||||
if listLens[field] > maxLen:
|
||||
maxLen = listLens[field]
|
||||
baserow = {}
|
||||
for field in CROS_TELEMETRY_SCALAR_FIELDS:
|
||||
if field in device:
|
||||
baserow[field] = device[field]
|
||||
for i in range(maxLen):
|
||||
row = baserow.copy()
|
||||
for field, fieldLen in listLens.items():
|
||||
if i < fieldLen:
|
||||
flattenJSON({field: device[field][i]}, flattened=row, timeObjects=CROS_TELEMETRY_TIME_OBJECTS)
|
||||
csvPF.WriteRowTitles(row)
|
||||
|
||||
def _showDevice(device, i=0, count=0):
|
||||
_cleanDevice(device)
|
||||
@@ -25948,11 +25994,12 @@ def doInfoPrintShowCrOSTelemetry():
|
||||
Act.Set(Act.SHOW)
|
||||
else:
|
||||
pfilters = []
|
||||
csvPF = CSVPrintFile(['deviceId'], CROS_TELEMETRY_SCALAR_FIELDS, CROS_TELEMETRY_LIST_FIELDS) if Act.csvFormat() else None
|
||||
csvPF = CSVPrintFile(['deviceId'], CROS_TELEMETRY_SCALAR_FIELDS) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
diskPercentOnly = showOrgUnitPath = False
|
||||
listLimit = 0
|
||||
startTime = endTime = None
|
||||
oneItemPerRow = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
@@ -26008,6 +26055,8 @@ def doInfoPrintShowCrOSTelemetry():
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
elif myarg == 'storagepercentonly':
|
||||
diskPercentOnly = True
|
||||
elif csvPF and myarg == 'oneitemperrow':
|
||||
oneItemPerRow = True
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, False)
|
||||
if fieldsList:
|
||||
@@ -26019,6 +26068,8 @@ def doInfoPrintShowCrOSTelemetry():
|
||||
readMask = ','.join(set(fieldsList))
|
||||
if csvPF and FJQC.formatJSON:
|
||||
csvPF.SetJSONTitles(['deviceId', 'JSON'])
|
||||
elif csvPF and not oneItemPerRow:
|
||||
csvPF.SetIndexedTitles(CROS_TELEMETRY_LIST_FIELDS)
|
||||
if not pfilters:
|
||||
pfilters = [(None, 'All')]
|
||||
for pfilter in pfilters:
|
||||
@@ -29155,24 +29206,37 @@ def infoChatMessage(users):
|
||||
def doInfoChatMessage():
|
||||
infoChatMessage([None])
|
||||
|
||||
CHAT_MESSAGES_ORDERBY_CHOICE_MAP = {
|
||||
'createtime': 'createTime'
|
||||
}
|
||||
|
||||
# gam <UserTypeEntity> show chatmessages
|
||||
# <ChatSpace>+
|
||||
# [showdeleted [<Boolean>]] [filter <String>]
|
||||
# [showdeleted [<Boolean>]]
|
||||
# [([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
# [thread <ChatThread>])
|
||||
# [fields <ChatMessageFieldNameList>]
|
||||
# [orderby createtime [ascending|descending]]
|
||||
# [formatjson]
|
||||
# gam <UserTypeEntity> print chatmessages [todrive <ToDriveAttribute>*]
|
||||
# <ChatSpace>+
|
||||
# [showdeleted [<Boolean>]] [filter <String>]
|
||||
# [([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
# [thread <ChatThread>])
|
||||
# [fields <ChatMessageFieldNameList>]
|
||||
# [orderby createtime [ascending|descending]]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
def printShowChatMessages(users):
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
csvPF = CSVPrintFile(['User', 'space.name', 'space.displayName', 'name'] if not isinstance(users, list) else ['space.name', 'space.displayName', 'name']) if Act.csvFormat() else None
|
||||
csvPF = CSVPrintFile(['User', 'space.name', 'space.displayName', 'name']) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
OBY = OrderBy(CHAT_MESSAGES_ORDERBY_CHOICE_MAP, ascendingKeyword='ASC', descendingKeyword='DESC')
|
||||
fieldsList = []
|
||||
pfilter = None
|
||||
parentList = []
|
||||
showDeleted = False
|
||||
startEndTime = StartEndTime()
|
||||
threadName = ''
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
@@ -29185,10 +29249,35 @@ def printShowChatMessages(users):
|
||||
showDeleted = getBoolean()
|
||||
elif myarg =='filter':
|
||||
pfilter = getString(Cmd.OB_STRING)
|
||||
elif myarg in {'start', 'starttime', 'end', 'endtime', 'range'}:
|
||||
startEndTime.Get(myarg)
|
||||
elif myarg == 'thread':
|
||||
threadName = getString(Cmd.OB_CHAT_THREAD)
|
||||
elif myarg == 'orderby':
|
||||
OBY.GetChoice()
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
if not parentList:
|
||||
missingArgumentExit('space')
|
||||
if startEndTime.startDateTime is not None or startEndTime.endDateTime is not None:
|
||||
if pfilter:
|
||||
pfilter += ' AND '
|
||||
else:
|
||||
pfilter = ''
|
||||
pfilter += '('
|
||||
if startEndTime.startDateTime is not None:
|
||||
pfilter += f'createTime > "{startEndTime.startDateTime}"'
|
||||
if startEndTime.endDateTime is not None:
|
||||
pfilter += ' AND '
|
||||
if startEndTime.endDateTime is not None:
|
||||
pfilter += f'createTime < "{startEndTime.endDateTime}"'
|
||||
pfilter += ')'
|
||||
if threadName:
|
||||
if pfilter:
|
||||
pfilter += ' AND '
|
||||
else:
|
||||
pfilter = ''
|
||||
pfilter += f'thread.name = {threadName}'
|
||||
chatSenders = {}
|
||||
fields = getItemFieldsFromFieldsList('messages', fieldsList)
|
||||
i, count, users = getEntityArgument(users)
|
||||
@@ -29219,7 +29308,8 @@ def printShowChatMessages(users):
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_MESSAGE, user, i, count, qfilter),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
pageSize=GC.Values[GC.CHAT_MAX_RESULTS], parent=parentName, filter=pfilter, showDeleted=showDeleted,
|
||||
pageSize=GC.Values[GC.CHAT_MAX_RESULTS], parent=parentName,
|
||||
filter=pfilter, showDeleted=showDeleted, orderBy=OBY.orderBy,
|
||||
fields=fields)
|
||||
for message in messages:
|
||||
if 'sender' in message:
|
||||
@@ -29250,6 +29340,183 @@ def printShowChatMessages(users):
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Chat Messages')
|
||||
|
||||
def _getChatSpaceDisplayName(chat, space, chatSpaces):
|
||||
spaceName = space['name']
|
||||
if spaceName not in chatSpaces:
|
||||
try:
|
||||
result = callGAPI(chat.spaces(), 'get',
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.INTERNAL_ERROR,
|
||||
GAPI.PERMISSION_DENIED, GAPI.FAILED_PRECONDITION],
|
||||
name=spaceName, fields='displayName')
|
||||
spaceDisplayName = result.get('displayName', 'None')
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.internalError, GAPI.permissionDenied, GAPI.failedPrecondition):
|
||||
spaceDisplayName = 'None'
|
||||
chatSpaces[spaceName] = spaceDisplayName
|
||||
space['displayName'] = chatSpaces[spaceName]
|
||||
|
||||
CHAT_SEARCHMESSAGES_ORDERBY_CHOICE_MAP = {
|
||||
'createtime': 'createTime',
|
||||
'relevance': 'relevance',
|
||||
}
|
||||
CHAT_SEARCHMESSAGES_VIEW_CHOICE_MAP = {'basic': 'SEARCH_MESSAGES_VIEW_BASIC', 'full': 'SEARCH_MESSAGES_VIEW_FULL'}
|
||||
|
||||
# gam <UserTypeEntity> show chatsearchmessages
|
||||
# keywords <StringList>
|
||||
# <ChatSpace>*
|
||||
# [displaynames [all|any] <StringList>]
|
||||
# [senders <EmailAddressEntity>]*
|
||||
# [usermentions [all|any] <EmailAddressEntity>]*
|
||||
# [([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
# [hasattachment [<Boolean>]]
|
||||
# [fields <ChatMessageFieldNameList>]
|
||||
# [orderby createtime|relevance]
|
||||
# [basic|full]
|
||||
# [formatjson]
|
||||
# gam <UserTypeEntity> print chatsearchmessages [todrive <ToDriveAttribute>*]
|
||||
# keywords <StringList>
|
||||
# <ChatSpace>*
|
||||
# [displaynames [all|any] <StringList>]
|
||||
# [senders <EmailAddressEntity>]*
|
||||
# [usermentions [all|any] <EmailAddressEntity>]*
|
||||
# [([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
# [hasattachment [<Boolean>]]
|
||||
# [fields <ChatMessageFieldNameList>]
|
||||
# [orderby createtime|relevance]
|
||||
# [basic|full]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
def printShowChatSearchMessages(users):
|
||||
if API.CHAT not in GM.Globals[GM.DEVELOPER_PREVIEW_APIS]:
|
||||
Cmd.Backup()
|
||||
usageErrorExit(Msg.DEVELOPER_PREVIEW_REQUIRED)
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
csvPF = CSVPrintFile(['User', 'space.name', 'space.displayName', 'name']) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
orderBy = None
|
||||
fieldsList = []
|
||||
keywordList = []
|
||||
spaceList = []
|
||||
displayNameConjunction = ''
|
||||
displayNameList = []
|
||||
senderList = []
|
||||
userMentionList = []
|
||||
startEndTime = StartEndTime()
|
||||
hasAttachment = False
|
||||
body = {'view': CHAT_SEARCHMESSAGES_VIEW_CHOICE_MAP['basic'],
|
||||
'pageSize': GC.Values[GC.CHAT_MAX_RESULTS], 'pageToken': None}
|
||||
parent = 'spaces/-'
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
elif myarg =='keywords':
|
||||
keywordList = getString(Cmd.OB_STRING_LIST, minLen=0).replace(',', ' ').split()
|
||||
elif myarg == 'space' or myarg.startswith('spaces/') or myarg.startswith('space/'):
|
||||
spaceList.append(getSpaceName(myarg))
|
||||
elif myarg == 'displaynames':
|
||||
displayNameConjunction = getChoice(AND_OR_CONJUNCTION_MAP, mapChoice=True, defaultChoice='OR')
|
||||
displayNameList = getString(Cmd.OB_STRING_LIST, minLen=0).replace(',', ' ').split()
|
||||
elif myarg == 'senders':
|
||||
senderList.extend(getNormalizedEmailAddressEntity(noUid=False))
|
||||
elif myarg == 'usermentions':
|
||||
userMentionConjunction = getChoice(AND_OR_CONJUNCTION_MAP, mapChoice=True, defaultChoice='OR')
|
||||
userMentionList.extend(getNormalizedEmailAddressEntity(noUid=False))
|
||||
elif myarg in {'start', 'starttime', 'end', 'endtime`', 'range'}:
|
||||
startEndTime.Get(myarg)
|
||||
elif myarg == 'hasattachment':
|
||||
hasAttachment = True
|
||||
elif myarg == 'orderby':
|
||||
orderBy = getChoice(CHAT_SEARCHMESSAGES_ORDERBY_CHOICE_MAP, mapChoice=True)
|
||||
elif myarg in CHAT_SEARCHMESSAGES_VIEW_CHOICE_MAP:
|
||||
body['view'] = CHAT_SEARCHMESSAGES_VIEW_CHOICE_MAP[myarg]
|
||||
elif getFieldsList(myarg, CHAT_MESSAGES_FIELDS_CHOICE_MAP, fieldsList, initialField='name', onlyFieldsArg=True):
|
||||
pass
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
if not keywordList:
|
||||
missingArgumentExit('keywords')
|
||||
if orderBy is not None:
|
||||
body['orderBy'] = f'{orderBy} desc'
|
||||
body['filter'] = f'({" ".join(keywordList)})'
|
||||
if spaceList:
|
||||
body['filter'] += ' AND ('
|
||||
for space in spaceList:
|
||||
body['filter'] += f'space.name = "{space}" OR '
|
||||
body['filter'] = body['filter'][:-4] + ')'
|
||||
if displayNameList:
|
||||
body['filter'] += ' AND ('
|
||||
for displayName in displayNameList:
|
||||
body['filter'] += f'space.display_name:{displayName}" {displayNameConjunction} '
|
||||
body['filter'] = body['filter'][:-(len(displayNameConjunction)+2)] + ')'
|
||||
if senderList:
|
||||
body['filter'] += ' AND ('
|
||||
for sender in senderList:
|
||||
body['filter'] += f'sender.name = "users/{sender}" OR '
|
||||
body['filter'] = body['filter'][:-4] + ')'
|
||||
if userMentionList:
|
||||
body['filter'] += ' AND ('
|
||||
for userMention in userMentionList:
|
||||
body['filter'] += f'annotations.user_mentions.user.name:"users/{userMention}" {userMentionConjunction} '
|
||||
body['filter'] = body['filter'][:-(len(userMentionConjunction)+2)] + ')'
|
||||
if startEndTime.startDateTime is not None or startEndTime.endDateTime is not None:
|
||||
body['filter'] += ' AND ('
|
||||
if startEndTime.startDateTime is not None:
|
||||
body['filter'] += f'createTime >= "{startEndTime.startDateTime}"'
|
||||
if startEndTime.endDateTime is not None:
|
||||
body['filter'] += ' AND '
|
||||
if startEndTime.endDateTime is not None:
|
||||
body['filter'] += f'createTime < "{startEndTime.endDateTime}"'
|
||||
body['filter'] += ')'
|
||||
if hasAttachment:
|
||||
body['filter'] += ' AND attachment:*'
|
||||
chatSenders = {}
|
||||
chatSpaces = {}
|
||||
fields = getItemFieldsFromFieldsList('results(message', fieldsList)
|
||||
if fields:
|
||||
fields += ')'
|
||||
i, count, users = getEntityArgument(users)
|
||||
for user in users:
|
||||
i += 1
|
||||
user, chat, kvList = buildChatServiceObject(API.CHAT_MESSAGES, user, i, count, [Ent.CHAT_SPACE, None])
|
||||
if not chat:
|
||||
continue
|
||||
_, chatsp, _ = buildChatServiceObject(API.CHAT_SPACES, user, i, count, [Ent.CHAT_SPACE, None])
|
||||
if not chat:
|
||||
continue
|
||||
try:
|
||||
results = callGAPIpages(chat.spaces().messages(), 'search', 'results',
|
||||
pageMessage=_getChatPageMessage(Ent.CHAT_MESSAGE, user, i, count, body['filter']),
|
||||
throwReasons=[GAPI.NOT_FOUND, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
parent='spaces/-', body=body, fields=fields, pageArgsInBody=True)
|
||||
for result in results:
|
||||
if 'sender' in result['message']:
|
||||
_getChatSenderEmail(cd, result['message']['sender'], chatSenders)
|
||||
if 'space' in result['message']:
|
||||
_getChatSpaceDisplayName(chatsp, result['message']['space'], chatSpaces)
|
||||
except (GAPI.notFound, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
exitIfChatNotConfigured(chat, kvList, str(e), i, count)
|
||||
continue
|
||||
except GAPI.failedPrecondition:
|
||||
userChatServiceNotEnabledWarning(user, i, count)
|
||||
break
|
||||
if not csvPF:
|
||||
jcount = len(results)
|
||||
if not FJQC.formatJSON:
|
||||
entityPerformActionNumItems(kvList, jcount, Ent.CHAT_MESSAGE, i, count)
|
||||
Ind.Increment()
|
||||
j = 0
|
||||
for result in results:
|
||||
j += 1
|
||||
_showChatItem(result['message'], Ent.CHAT_MESSAGE, FJQC, j, jcount)
|
||||
Ind.Decrement()
|
||||
elif results:
|
||||
for result in results:
|
||||
_printChatItem(user, result['message'], parent, Ent.CHAT_MESSAGE, csvPF, FJQC)
|
||||
elif GC.Values[GC.CSV_OUTPUT_USERS_AUDIT]:
|
||||
csvPF.WriteRowNoFilter({'User': user})
|
||||
if csvPF:
|
||||
csvPF.writeCSVfile('Chat Messages')
|
||||
|
||||
# gam <UserTypeEntity> info chatevent name <ChatEvent>
|
||||
# [formatjson]
|
||||
def infoChatEvent(users):
|
||||
@@ -29295,7 +29562,7 @@ def doInfoChatEvent():
|
||||
# filter <String>
|
||||
# [formatjson [quotechar <Character>]]
|
||||
def printShowChatEvents(users):
|
||||
csvPF = CSVPrintFile(['User', 'space.name', 'space.displayName', 'name'] if not isinstance(users, list) else ['space.name', 'space.displayName', 'name']) if Act.csvFormat() else None
|
||||
csvPF = CSVPrintFile(['User', 'space.name', 'space.displayName', 'name']) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
pfilter = None
|
||||
parentList = []
|
||||
@@ -31087,7 +31354,7 @@ def getCIDeviceUserEntity():
|
||||
pageMessage = getPageMessage()
|
||||
try:
|
||||
deviceUsers = callGAPIpages(ci.devices().deviceUsers(), 'list', 'deviceUsers',
|
||||
throwReasons=[GAPI.INVALID, GAPI.PERMISSION_DENIED],
|
||||
throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
pageMessage=pageMessage,
|
||||
customer=customer, filter=query, parent='devices/-',
|
||||
@@ -31096,7 +31363,7 @@ def getCIDeviceUserEntity():
|
||||
except GAPI.invalid:
|
||||
Cmd.Backup()
|
||||
usageErrorExit(Msg.INVALID_QUERY)
|
||||
except GAPI.permissionDenied as e:
|
||||
except (GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
entityActionFailedWarning([Ent.DEVICE_USER, None], str(e))
|
||||
return ([], ci, customer, False)
|
||||
|
||||
@@ -31450,7 +31717,7 @@ def doInfoCIDevice():
|
||||
else:
|
||||
FJQC.GetFormatJSON(myarg)
|
||||
fields = getFieldsFromFieldsList(fieldsList)
|
||||
userFields = getFieldsFromFieldsList(userFieldsList)
|
||||
userFields = getItemFieldsFromFieldsList('deviceUsers', userFieldsList)
|
||||
i = 0
|
||||
count = len(entityList)
|
||||
for device in entityList:
|
||||
@@ -31462,7 +31729,7 @@ def doInfoCIDevice():
|
||||
name=name, customer=customer, fields=fields)
|
||||
if getDeviceUsers:
|
||||
device_users = callGAPIpages(ci.devices().deviceUsers(), 'list', 'deviceUsers',
|
||||
throwReasons=[GAPI.INVALID, GAPI.PERMISSION_DENIED],
|
||||
throwReasons=[GAPI.INVALID, GAPI.INVALID_ARGUMENT, GAPI.PERMISSION_DENIED],
|
||||
parent=name, customer=customer, fields=userFields)
|
||||
for device_user in device_users:
|
||||
device_user['client_states'] = callGAPIpages(ci.devices().deviceUsers().clientStates(), 'list', 'clientStates',
|
||||
@@ -31486,7 +31753,7 @@ def doInfoCIDevice():
|
||||
Ind.Increment()
|
||||
showJSON(None, device_user, timeObjects=DEVICE_TIME_OBJECTS)
|
||||
Ind.Decrement()
|
||||
Ind.Decrement()
|
||||
Ind.Decrement()
|
||||
except GAPI.notFound:
|
||||
entityUnknownWarning(Ent.DEVICE, f'{name}')
|
||||
except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
@@ -31812,7 +32079,7 @@ def doPrintCIDeviceUsers():
|
||||
csvPF.WriteRowNoFilter({'name': deviceUser['name'],
|
||||
'JSON': json.dumps(cleanJSON(deviceUser, timeObjects=DEVICE_TIME_OBJECTS),
|
||||
ensure_ascii=False, sort_keys=True)})
|
||||
except (GAPI.invalid, GAPI.permissionDenied) as e:
|
||||
except (GAPI.invalid, GAPI.invalidArgument, GAPI.permissionDenied) as e:
|
||||
entityActionFailedWarning([Ent.DEVICE_USER, None], str(e))
|
||||
break
|
||||
if showItemCountOnly:
|
||||
@@ -40727,6 +40994,7 @@ CALENDAR_ACL_ROLES_MAP = {
|
||||
'read': 'reader',
|
||||
'reader': 'reader',
|
||||
'writer': 'writer',
|
||||
'writerwithoutprivateaccess': 'writerWithoutPrivateAccess',
|
||||
'none': 'none',
|
||||
}
|
||||
|
||||
@@ -47007,7 +47275,9 @@ USER_SCALAR_PROPERTY_PRINT_ORDER = [
|
||||
'ipWhitelisted',
|
||||
'suspended',
|
||||
'suspensionReason',
|
||||
'suspensionTime',
|
||||
'archived',
|
||||
'archivalTime',
|
||||
'changePasswordAtNextLogin',
|
||||
'id',
|
||||
'customerId',
|
||||
@@ -47098,7 +47368,7 @@ USER_FIELDS_CHOICE_MAP = {
|
||||
'agreed2terms': 'agreedToTerms',
|
||||
'agreedtoterms': 'agreedToTerms',
|
||||
'aliases': ['aliases', 'nonEditableAliases'],
|
||||
'archived': 'archived',
|
||||
'archived': ['archived', 'archivalTime'],
|
||||
'changepassword': 'changePasswordAtNextLogin',
|
||||
'changepasswordatnextlogin': 'changePasswordAtNextLogin',
|
||||
'creationtime': 'creationTime',
|
||||
@@ -47168,7 +47438,7 @@ USER_FIELDS_CHOICE_MAP = {
|
||||
'ssh': 'sshPublicKeys',
|
||||
'sshkeys': 'sshPublicKeys',
|
||||
'sshpublickeys': 'sshPublicKeys',
|
||||
'suspended': ['suspended', 'suspensionReason'],
|
||||
'suspended': ['suspended', 'suspensionReason', 'suspensionTime'],
|
||||
'thumbnailphotourl': 'thumbnailPhotoUrl',
|
||||
'username': 'primaryEmail',
|
||||
'website': 'websites',
|
||||
@@ -47204,7 +47474,7 @@ USER_MULTI_ATTR_FILTER_CHOICE_MAP = {
|
||||
|
||||
INFO_USER_OPTIONS = {'noaliases', 'nobuildingnames', 'nogroups', 'nolicenses', 'nolicences', 'noschemas', 'schemas', 'userview'}
|
||||
USER_SKIP_OBJECTS = {'thumbnailPhotoEtag'}
|
||||
USER_TIME_OBJECTS = {'creationTime', 'deletionTime', 'lastLoginTime'}
|
||||
USER_TIME_OBJECTS = {'creationTime', 'deletionTime', 'lastLoginTime', 'suspensionTime', 'archivalTime'}
|
||||
|
||||
def _getUserMultiAttributeFilters(myarg, userMultiAttributeFilters):
|
||||
up = getChoice(USER_MULTI_ATTR_FILTER_CHOICE_MAP, mapChoice=True)
|
||||
@@ -59699,7 +59969,7 @@ def printFileList(users):
|
||||
(DLP.onlySharedDrives and not driveId)):
|
||||
return
|
||||
if getCheckFilePermissions:
|
||||
if not incrementalPrint:
|
||||
if buildTree and not incrementalPrint:
|
||||
getSharedDriveACLsCount += 1
|
||||
if getSharedDriveACLsCount % 100 == 0:
|
||||
writeStderr(f'{Msg.GOT} {getSharedDriveACLsCount} {Ent.Plural(Ent.DRIVE_FILE_OR_FOLDER_ACL)} {Msg.FOR} {gettingEntity}\n')
|
||||
@@ -74589,10 +74859,10 @@ def _decodeHeader(header):
|
||||
stderrWarningMsg(Msg.INVALID_CHARSET.format(mg.group(1)))
|
||||
return header
|
||||
|
||||
# gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
# gam <UserTypeEntity> forward message|messages [recipient|to] <RecipientEntity>
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
# [subject <String>] [addorigfieldstosubject [<Boolean>]] [altcharset <String>]
|
||||
# gam <UserTypeEntity> forward thread|threads recipient|to <RecipientEntity>
|
||||
# gam <UserTypeEntity> forward thread|threads [recipient|to] <RecipientEntity>
|
||||
# (((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+ [quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
# [subject <String>] [addorigfieldstosubject [<Boolean>]] [altcharset <String>]
|
||||
def forwardMessagesThreads(users, entityType):
|
||||
@@ -74695,16 +74965,16 @@ def forwardMessagesThreads(users, entityType):
|
||||
msgSubject = f"Fwd: {_decodeHeader(message['Subject'])}"
|
||||
else:
|
||||
msgSubject = f"Subject: {subject}"
|
||||
for header in ['To', 'Cc', 'Subject']:
|
||||
if header in message:
|
||||
del message[header]
|
||||
message['To'] = msgTo
|
||||
if addOriginalFieldsToSubject:
|
||||
msgSubject += ' (Original'
|
||||
for header in ['From', 'To', 'Date']:
|
||||
if header in message:
|
||||
msgSubject += f' {header}: {message[header]}'
|
||||
msgSubject += ')'
|
||||
for header in ['To', 'Cc', 'Bcc', 'Subject']:
|
||||
if header in message:
|
||||
del message[header]
|
||||
message['To'] = msgTo
|
||||
message['Subject'] = msgSubject
|
||||
try:
|
||||
result = callGAPI(gmail.users().messages(), 'send',
|
||||
@@ -80162,17 +80432,12 @@ def CAABuildCondition():
|
||||
unknownArgumentExit()
|
||||
return condition
|
||||
|
||||
CAA_COMBINING_FUNCTIONS_MAP = {
|
||||
'and': 'AND',
|
||||
'or': 'OR',
|
||||
}
|
||||
|
||||
def CAABuildBasicLevel():
|
||||
basic_level = {'conditions': []}
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if myarg == 'combiningfunction':
|
||||
basic_level['combiningFunction'] = getChoice(CAA_COMBINING_FUNCTIONS_MAP, mapChoice=True)
|
||||
basic_level['combiningFunction'] = getChoice(AND_OR_CONJUNCTION_MAP, mapChoice=True)
|
||||
elif myarg == 'condition':
|
||||
basic_level['conditions'].append(CAABuildCondition())
|
||||
else:
|
||||
@@ -81693,6 +81958,7 @@ USER_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_CHATEVENT: printShowChatEvents,
|
||||
Cmd.ARG_CHATMEMBER: printShowChatMembers,
|
||||
Cmd.ARG_CHATMESSAGE: printShowChatMessages,
|
||||
Cmd.ARG_CHATSEARCHMESSAGE: printShowChatSearchMessages,
|
||||
Cmd.ARG_CHATSECTION: printShowChatSections,
|
||||
Cmd.ARG_CHATSECTIONITEM: printShowChatSectionItems,
|
||||
Cmd.ARG_CHATSPACE: printShowChatSpaces,
|
||||
@@ -81811,6 +82077,7 @@ USER_COMMANDS_WITH_OBJECTS = {
|
||||
Cmd.ARG_CHATEVENT: printShowChatEvents,
|
||||
Cmd.ARG_CHATMEMBER: printShowChatMembers,
|
||||
Cmd.ARG_CHATMESSAGE: printShowChatMessages,
|
||||
Cmd.ARG_CHATSEARCHMESSAGE: printShowChatSearchMessages,
|
||||
Cmd.ARG_CHATSECTION: printShowChatSections,
|
||||
Cmd.ARG_CHATSECTIONITEM: printShowChatSectionItems,
|
||||
Cmd.ARG_CHATSPACE: printShowChatSpaces,
|
||||
@@ -82039,6 +82306,7 @@ USER_COMMANDS_OBJ_ALIASES = {
|
||||
Cmd.ARG_CHATEVENTS: Cmd.ARG_CHATEVENT,
|
||||
Cmd.ARG_CHATMEMBERS: Cmd.ARG_CHATMEMBER,
|
||||
Cmd.ARG_CHATMESSAGES: Cmd.ARG_CHATMESSAGE,
|
||||
Cmd.ARG_CHATSEARCHMESSAGES: Cmd.ARG_CHATSEARCHMESSAGE,
|
||||
Cmd.ARG_CHATSECTIONS: Cmd.ARG_CHATSECTION,
|
||||
Cmd.ARG_CHATSECTIONITEMS: Cmd.ARG_CHATSECTIONITEM,
|
||||
Cmd.ARG_CHATSPACES: Cmd.ARG_CHATSPACE,
|
||||
|
||||
@@ -846,6 +846,8 @@ class GamCLArgs():
|
||||
ARG_CHATMEMBERS = 'chatmembers'
|
||||
ARG_CHATMESSAGE = 'chatmessage'
|
||||
ARG_CHATMESSAGES = 'chatmessages'
|
||||
ARG_CHATSEARCHMESSAGE = 'chatsearchmessage'
|
||||
ARG_CHATSEARCHMESSAGES = 'chatsearchmessages'
|
||||
ARG_CHATSECTION = 'chatsection'
|
||||
ARG_CHATSECTIONS = 'chatsections'
|
||||
ARG_CHATSECTIONITEM = 'chatsectionitem'
|
||||
|
||||
@@ -312,7 +312,7 @@ INVALID_ALIAS = 'Invalid Alias'
|
||||
INVALID_ATTENDEE_CHANGE = 'Invalid attendee change "{0}"'
|
||||
INVALID_CHARSET = 'Invalid charset "{0}"'
|
||||
INVALID_DATE_TIME_RANGE = '{0} {1} must be greater than/equal to {2} {3}'
|
||||
INVALID_DEVICE_QUERY = 'Invalid {0} query "{1}"; it must contain a ":" and must not contain a "?"'
|
||||
INVALID_DEVICE_QUERY = 'Invalid {0} query "{1}"; it must be if the form "field:value" and must not contain a "?"'
|
||||
INVALID_EMOJI_NAME = '{0} does not match pattern :[0-9a-z_-]:'
|
||||
INVALID_ENTITY = 'Invalid {0}, {1}'
|
||||
INVALID_EVENT_TIMERANGE = '{0} {1} must be less than {2}'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2025 Ross Scroggs All Rights Reserved.
|
||||
# Copyright (C) 2026 Ross Scroggs All Rights Reserved.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
# Products/SKUs
|
||||
_PRODUCTS = {
|
||||
'101001': 'Cloud Identity',
|
||||
'101001': 'Cloud Identity Free',
|
||||
'101005': 'Cloud Identity Premium',
|
||||
'101031': 'Google Workspace for Education',
|
||||
'101033': 'Google Voice',
|
||||
@@ -44,7 +44,7 @@ _PRODUCTS = {
|
||||
}
|
||||
_SKUS = {
|
||||
'1010010001': {
|
||||
'product': '101001', 'aliases': ['identity', 'cloudidentity'], 'displayName': 'Cloud Identity'},
|
||||
'product': '101001', 'aliases': ['identity', 'cloudidentity', 'cloudidentityfree'], 'displayName': 'Cloud Identity Free'},
|
||||
'1010050001': {
|
||||
'product': '101005', 'aliases': ['identitypremium', 'cloudidentitypremium'], 'displayName': 'Cloud Identity Premium'},
|
||||
'1010070001': {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2023 Ross Scroggs All Rights Reserved.
|
||||
# Copyright (C) 2026 Ross Scroggs All Rights Reserved.
|
||||
#
|
||||
# All Rights Reserved.
|
||||
#
|
||||
@@ -145,10 +145,14 @@ PROPERTIES = {
|
||||
{CLASS: PC_BOOLEAN, TITLE: 'IP Whitelisted',},
|
||||
'archived':
|
||||
{CLASS: PC_BOOLEAN, TITLE: 'Is Archived',},
|
||||
'archivalTime':
|
||||
{CLASS: PC_TIME, TITLE: 'Archival Time',},
|
||||
'suspended':
|
||||
{CLASS: PC_BOOLEAN, TITLE: 'Account Suspended',},
|
||||
'suspensionReason':
|
||||
{CLASS: PC_STRING, TITLE: 'Suspension Reason',},
|
||||
'suspensionTime':
|
||||
{CLASS: PC_TIME, TITLE: 'Suspension Time',},
|
||||
'changePasswordAtNextLogin':
|
||||
{CLASS: PC_BOOLEAN, TITLE: 'Must Change Password',},
|
||||
'recoveryEmail':
|
||||
|
||||
@@ -20,6 +20,9 @@ Calendar ACL roles (as seen in Calendar GUI):
|
||||
* `owner` - Make changes to events and manage sharing
|
||||
* `freebusy` & `freebusyreader` - See only free/busy (hide details)
|
||||
|
||||
Added `writerwithoutprivateaccess` to `<CalendarACLRole>` in 7.44.03; this will become effective 2026-06-29.
|
||||
* See: https://developers.google.com/workspace/calendar/release-notes#June_01_2026
|
||||
|
||||
## API documentation
|
||||
* [Calendar API - ACLs](https://developers.google.com/google-apps/calendar/v3/reference/acl)
|
||||
|
||||
@@ -30,10 +33,15 @@ Calendar ACL roles (as seen in Calendar GUI):
|
||||
<CalendarEntity> ::= <CalendarList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
|
||||
|
||||
<CalendarACLRole> ::= editor|freebusy|freebusyreader|owner|reader|writer
|
||||
<CalendarACLScope> ::= <EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|domain:<DomainName>|domain|default
|
||||
<CalendarACLScopeList> ::= "<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarACLScopeEntity>::= <CalendarACLScopeList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
<CalendarACLRole> ::=
|
||||
editor|freebusy|freebusyreader|owner|reader|writer|writerwithoutprivateaccess|none
|
||||
<CalendarACLScope> ::=
|
||||
<EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|
|
||||
domain:<DomainName>|domain|default
|
||||
<CalendarACLScopeList> ::=
|
||||
"<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarACLScopeEntity>::=
|
||||
<CalendarACLScopeList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
|
||||
```
|
||||
## Manage calendar access
|
||||
```
|
||||
|
||||
@@ -98,6 +98,7 @@ gam oauth create
|
||||
autoupdateexpiration|
|
||||
autoupdatethrough|
|
||||
backlightinfo|
|
||||
bluetoothadapterinfo|
|
||||
bootmode|
|
||||
chromeostype|
|
||||
cpuinfo|
|
||||
@@ -131,6 +132,7 @@ gam oauth create
|
||||
orgunitpath|org|ou|
|
||||
osupdatestatus|
|
||||
osversion|
|
||||
osversioncompliance|
|
||||
platformversion|
|
||||
recentusers|
|
||||
screenshotfiles|
|
||||
@@ -185,25 +187,30 @@ gam oauth create
|
||||
<CrOSActivityListFieldNameList> ::= "<CrOSActivityListFieldName>(,<CrOSActivityListFieldName>)*"
|
||||
|
||||
<CrOSTelemetryFieldName> ::=
|
||||
appreport|
|
||||
audiostatusreport|
|
||||
batteryinfo|
|
||||
batterystatusreport|
|
||||
bootPerformancereport|
|
||||
bootperformancereport|
|
||||
cpuinfo|
|
||||
cpustatusreport|
|
||||
customer|
|
||||
deviceid|
|
||||
graphicsinfo|
|
||||
graphicsstatusreport|
|
||||
heartbeatstatusreport|
|
||||
kioskappstatusreport|
|
||||
memoryinfo|
|
||||
memorystatusreport|
|
||||
name|
|
||||
networkbandwidthreport|
|
||||
networkdiagnosticsreport|
|
||||
networkinfo|
|
||||
networkstatusreport|
|
||||
orgunitid|
|
||||
osupdatestatus|
|
||||
peripheralsreport|
|
||||
runtimecountersreport|
|
||||
serialnumber|
|
||||
storageinfo|
|
||||
storagestatusreport|
|
||||
@@ -211,20 +218,22 @@ gam oauth create
|
||||
<CrOSTelemetryFieldNameList> ::= "<CrOSTelemetryFieldName>(,<CrOSTelemetryFieldName>)*"
|
||||
|
||||
<CrOSTelemetryListFieldName> ::=
|
||||
appreport|
|
||||
audiostatusreport|
|
||||
batteryinfo|
|
||||
batterystatusreport|
|
||||
bootperformancereport|
|
||||
cpuinfo|
|
||||
cpustatusreport|
|
||||
graphicsstatusreport|
|
||||
heartbeatstatusreport|
|
||||
kioskappstatusreport|
|
||||
memorystatusreport|
|
||||
networkbandwidthreport|
|
||||
networkdiagnosticsreport|
|
||||
networkstatusreport|
|
||||
osupdatestatus|
|
||||
peripheralsreport|
|
||||
storagestatusreport|
|
||||
thunderboltinfo
|
||||
runtimecountersreport|
|
||||
storagestatusreport
|
||||
<CrOSTelemetryListFieldNameList> ::= "<CrOSTelemetryListFieldName>(,<CrOSTelemetryLIstFieldName>)*"
|
||||
```
|
||||
|
||||
@@ -964,19 +973,21 @@ By default, Gam displays the information as an indented list of keys and values:
|
||||
gam print crostelemetry [todrive <ToDriveAttribute>*]
|
||||
[(ou|org|orgunit|ou_and_children <OrgUnitItem>)|(cros_sn <SerialNumber>)|(filter <String>)]
|
||||
<CrOSTelemetryFieldName>* [fields <CrOSTelemetryFieldNameList>]
|
||||
[reverselists <CrOSTelemetryListFieldNameList>]
|
||||
[reverselists <CrOSTelemetryListFieldNameList>] [oneitemperrow]
|
||||
[start <Date>] [end <Date>] [listlimit <Number>]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
Use these options to select CrOS devices; if none are chosen, all CrOS devices in the account are selected.
|
||||
|
||||
- `ou|org|orgunit <OrgUnitItem>` - Select CrOS devices directly in the OU `<OrgUnitItem>`
|
||||
- `ou_and_children <OrgUnitItem>` - Select CrOS devices in the OU `<OrgUnitItem>` and its sub OUs
|
||||
- `cros_sn <SerialNumber>` - Select the CrOS device with serial number `<SerialNumber>`.
|
||||
- `filter <String>` - Select the CrOS device with a filter.
|
||||
|
||||
Use these options to limit/modify the displayed lists.
|
||||
- `listlimit <Number>` - Limits the number of repetitions to `<Number>`; if not specified or `<Number>` equals zero, there is no limit.
|
||||
- `start <Date>` and `end <Date>` - Constrain list `reportTime` to fall within the specified `<Dates>`. If a `<Date>` isn't specified, there is no filtering in that range.
|
||||
- `reverselists <CrOSTelemetryListFieldNameList>` - For each list, change order from ascending (oldest to newest) to descending (newest to oldest); this makes it easy to get the `N` most recent values with `listlimit N reverselists cpustatusreport,memorystatusreport`
|
||||
- `reverselists <CrOSTelemetryListFieldNameList>` - For each list, change order from descending (newest to oldest) to ascending (oldest to newest)
|
||||
- `oneitemrerrow` - Display each instance of a list item on a separate row; by default, all list items are displayed on a single row
|
||||
|
||||
By default, all telemetry data is displayed, use the following to select specific fields:
|
||||
- `<CrOSTelemetryFieldName>*` - Specify fields individually
|
||||
|
||||
@@ -133,6 +133,8 @@ Use this table to filter/query for specific device types:
|
||||
|
||||
```
|
||||
## Create a company device
|
||||
This method is available only to customers who have one of the following SKUs: Enterprise Standard, Enterprise Plus, Enterprise for Education, and Cloud Identity Premium.
|
||||
|
||||
Adds a new device to the Google company-owned inventory. Once a user is assigned and enrolled on the device the device will be considered company-owned for management purposes.
|
||||
The device will also register as company-owned with Google services like [Context-Aware Access (CAA)](https://support.google.com/a/answer/9275380).
|
||||
```
|
||||
|
||||
@@ -16,12 +16,12 @@ In zsh, if an argument contains a `~`, `|`, `!`, `>`, or `<`, you must enclose t
|
||||
|
||||
To embed a `'` in a string enclosed in `"`, enter `'`; `name "Test'Group"`.
|
||||
|
||||
To embed a `"` in a string enclosed in `"`, enter `\"`; `name "Test\"Group"`.
|
||||
|
||||
To embed a `"` in a string enclosed in `'`, enter `"`; `name 'Test"Group'`.
|
||||
|
||||
To embed a `'` in a string enclosed in `'`, enter `'\''`; `name 'Test'\''Group'`.
|
||||
|
||||
To embed a `"` in a string enclosed in `"`, enter `\"`; `name "Test\"Group"`.
|
||||
|
||||
Linux and MacOS do not recognize smart or curly quotes, `“` and `”`, they can not be used to enclose arguments.
|
||||
|
||||
## Windows Command Prompt
|
||||
|
||||
@@ -10,6 +10,74 @@ 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.44.03
|
||||
|
||||
Added `writerwithoutprivateaccess` to `<CalendarACLRole>`; this will become effective 2026-06-29.
|
||||
* See: https://developers.google.com/workspace/calendar/release-notes#June_01_2026
|
||||
|
||||
### 7.44.02
|
||||
|
||||
Added fields `bluetoothadapterinfo` and `osversioncompliance` to `<CrOSFieldName>` for use
|
||||
in `gam info|print cros`.
|
||||
|
||||
### 7.44.01
|
||||
|
||||
Added option `oneitemperrow` to `gam print crostelemetry` to have each of a device's
|
||||
report field entries displayed on a separate row with all of the other device fields.
|
||||
|
||||
Added additional fields to `<CrOSTelemetryFieldName>`and `<CrOSTelemetryListFieldName>`:
|
||||
```
|
||||
appreport
|
||||
heartbeatstatusreport
|
||||
kioskappstatusreport
|
||||
networkbandwidthreport
|
||||
runtimecountersreport
|
||||
```
|
||||
|
||||
### 7.44.00
|
||||
|
||||
Added support for User data `archivalTime` and `suspensionTime` that is available
|
||||
when fields `archived` and `suspended` are requested in `gam info user` and `gam print users`.
|
||||
|
||||
Added the following options to `gam <UserTypeEntity> show chatmessages` to simplify specifying a filter.
|
||||
```
|
||||
start|starttime <Date>|<Time>
|
||||
end|endtime <Date>|<Time>
|
||||
range <Date>|<Time> <Date>|<Time>
|
||||
thread <ChatThread>
|
||||
```
|
||||
|
||||
Added commands to search for and display chat messages.
|
||||
* See: https://github.com/GAM-team/GAM/wiki/Users-Chat#display-chat-messages-by-searching
|
||||
|
||||
These commands are in Developer Preview; to use them you must have these values set in `gam.cfg`.
|
||||
```
|
||||
developer_preview_apis = chat
|
||||
developer_preview_api_key = <DeveloperPreviewKey>
|
||||
```
|
||||
|
||||
Upgraded to Python 3.14.5.
|
||||
|
||||
### 7.43.10
|
||||
|
||||
Updated `gam <UserTypeEntity> forward message|thread [recipient|to] <RecipientEntity>` to not forward messages
|
||||
to the `Bcc` recipients of the original message.
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> forward message|thread [recipient|to] <RecipientEntity> addorigfieldstosubject`
|
||||
where the recipient of the forwarded message was added to the subject line instead of the recipient of the original message.
|
||||
|
||||
### 7.43.09
|
||||
|
||||
Fixed bug in `gam <UserTypeEntity> print filelist` that caused a trap.
|
||||
|
||||
### 7.43.08
|
||||
|
||||
Fixed bug and formatting issues in `gam info device <DeviceEntity>`.
|
||||
|
||||
### 7.43.07
|
||||
|
||||
Improved validation of `<QueryCrOS>`, `<QueryDevice>` and `<QueryMobile>`.
|
||||
|
||||
### 7.43.06
|
||||
|
||||
Updated commands that use `<QueryCrOS>`, `<QueryDevice>` or `<QueryMobile>` to validate
|
||||
|
||||
@@ -251,10 +251,10 @@ writes the credentials into the file oauth2.txt.
|
||||
```
|
||||
gamteam@server:/Users/gamteam$ rm -f /Users/gamteam/GAMConfig/oauth2.txt
|
||||
gamteam@server:/Users/gamteam$ gam version
|
||||
GAM 7.43.06 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.44.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.4 64-bit final
|
||||
macOS Tahoe 26.4.1 arm64
|
||||
Python 3.14.5 64-bit final
|
||||
macOS Tahoe 26.5 arm64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Config File: /Users/gamteam/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
|
||||
@@ -1034,9 +1034,9 @@ writes the credentials into the file oauth2.txt.
|
||||
```
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
GAM 7.43.06 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM 7.44.03 - https://github.com/GAM-team/GAM - pythonsource
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.4 64-bit final
|
||||
Python 3.14.5 64-bit final
|
||||
Windows 11 10.0.26200 AMD64
|
||||
Path: C:\GAM7
|
||||
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
| Assured Controls | 1010390001 | assuredcontrols |
|
||||
| Assured Controls Plus | 1010390002 | assuredcontrolsplus |
|
||||
| Chrome Enterprise Premium | 1010400001 | cep | chromeenterprisepremium |
|
||||
| Cloud Identity | 1010010001 | cloudidentity |
|
||||
| Cloud Identity Free | 1010010001 | cloudidentity |
|
||||
| Cloud Identity Premium | 1010050001 | cloudidentitypremium |
|
||||
| Cloud Search | 1010350001 | cloudsearch |
|
||||
| Colab Pro | 1010500001 | colabpro |
|
||||
@@ -163,7 +163,7 @@
|
||||
assuredcontrolsplus | 1010390002 | Assured Controls Plus |
|
||||
bce | beyondcorp | beyondcorpenterprise | cep | chromeenterprisepremium | 1010400001 | Chrome Enterprise Premium |
|
||||
cdm | chrome | googlechromedevicemanagement | Google-Chrome-Device-Management |
|
||||
cloudidentity | identity | 1010010001 | Cloud Identity |
|
||||
cloudidentityfree| cloudidentity | identity | 1010010001 | Cloud Identity Free |
|
||||
cloudidentitypremium | identitypremium | 1010050001 | Cloud Identity Premium |
|
||||
cloudsearch | 1010350001 | Cloud Search |
|
||||
colabpro | 1010500001 | Colab Pro |
|
||||
|
||||
@@ -12,6 +12,7 @@ Thank you.
|
||||
* James Seymour - https://sites.google.com/view/gam--commands/
|
||||
* Kevin Melillo - https://github.com/KevinMelilloIEEE/gam-script
|
||||
* Korey Rideout - https://chatgpt.com/g/g-PTxxnVPMG-gam-assist-now-turbocharged-with-gam7
|
||||
* Paul Ogier (Taming.Tech) - GAM Scripts https://github.com/PaulOgier/GAMScripts
|
||||
* Paul Ogier (Taming.Tech) - GAM7 Course on Udemy https://taming.tech/GAMCourse
|
||||
* Paul Ogier (Taming.Tech) - GAM7 Tutorials https://www.youtube.com/watch?v=g9LDeyXQNLI&list=PL_dLiK09pJVhKJxZHNk9CHK0q5hkZ856w
|
||||
* Paul Ogier (Taming.Tech) - Installation videos
|
||||
|
||||
@@ -14,6 +14,9 @@ Calendar ACL roles (as seen in Calendar GUI):
|
||||
* `owner` - Make changes to events and manage sharing
|
||||
* `freebusy` & `freebusyreader` - See only free/busy (hide details)
|
||||
|
||||
Added `writerwithoutprivateaccess` to `<CalendarACLRole>` in 7.44.03; this will become effective 2026-06-29.
|
||||
* See: https://developers.google.com/workspace/calendar/release-notes#June_01_2026
|
||||
|
||||
## API documentation
|
||||
* [Calendar API - ACLs](https://developers.google.com/google-apps/calendar/v3/reference/acl)
|
||||
|
||||
@@ -55,10 +58,10 @@ Calendar ACL roles (as seen in Calendar GUI):
|
||||
(timezone <TimeZone>)
|
||||
|
||||
<CalendarACLRole> ::=
|
||||
editor|freebusy|freebusyreader|owner|reader|writer
|
||||
editor|freebusy|freebusyreader|owner|reader|writer|writerwithoutprivateaccess|none
|
||||
<CalendarACLScope> ::=
|
||||
<EmailAddress>|user:<EmailAdress>|group:<EmailAddress>|
|
||||
domain:<DomainName>|domain|default
|
||||
domain:<DomainName>|domain|default
|
||||
<CalendarACLScopeList> ::=
|
||||
"<CalendarACLScope>(,<CalendarACLScope>)*"
|
||||
<CalendarACLScopeEntity>::=
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
- [Display Chat Members](#display-chat-members)
|
||||
- [Manage Chat Messages](#manage-chat-messages)
|
||||
- [Display Chat Messages](#display-chat-messages)
|
||||
- [Display Chat Messages by Searching](#display-chat-messages-by-searching)
|
||||
- [Display Chat Events](#display-chat-events)
|
||||
- [Manage Chat Emojis](#manage-chat-emojis)
|
||||
- [Display Chat Emojis](#display-chat-emojis)
|
||||
@@ -65,6 +66,7 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
* [Chat API - Custom Emojis](https://developers.google.com/workspace/chat/api/reference/rest/v1/customEmojis)
|
||||
* [Chat API - Members](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.members/list)
|
||||
* [Chat API - Messages](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/list)
|
||||
* [Chat API - Search Messages](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/search)
|
||||
* [Chat API - Events](https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.spaceEvents/list)
|
||||
* [Chat API - User Sections](https://developers.google.com/workspace/chat/api/reference/rest/v1/users.sections)
|
||||
* [Apps in Google Chat](https://support.google.com/chat/answer/7655820)
|
||||
@@ -109,8 +111,8 @@ Google requires that you have a Chat Bot configured in order to use the Chat API
|
||||
<ChatThread> ::= spaces/<String>/threads/<String>
|
||||
<ChatSpaceType> ::=
|
||||
space|
|
||||
groupchat|
|
||||
directmessage
|
||||
groupchat|
|
||||
directmessage
|
||||
<ChatSpaceTypeList> ::= "<ChatSpaceType>(,<ChatSpaceType>)*"
|
||||
<ChatMessageID> ::= client-<String>
|
||||
<String> must contain only lowercase letters, numbers, and hyphens up to 56 characters in length.
|
||||
@@ -908,7 +910,7 @@ gam user user@domain.com delete chatmessage name spaces/AAAADi-pvqc/messages/PKJ
|
||||
```
|
||||
|
||||
## Display Chat Messages
|
||||
Display a specific Chat message.
|
||||
Display a specific chat message.
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> info chatmessage name <ChatMessage>
|
||||
@@ -923,12 +925,15 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
gam user user@domain.com info chatmessage name spaces/AAAADi-pvqc/messages/PKJrx90ooIU.PKJrx90ooIU
|
||||
```
|
||||
|
||||
### Display information about all chat messages in a chat space
|
||||
### Display information about chat messages in a chat space
|
||||
```
|
||||
gam <UserTypeEntity> show chatmessages
|
||||
<ChatSpace>+
|
||||
[showdeleted [<Boolean>]] [filter <String>]
|
||||
[showdeleted [<Boolean>]]
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[thread <ChatThread>])
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime [ascending|descending]]
|
||||
[formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
@@ -937,8 +942,11 @@ By default, Gam displays the information as an indented list of keys and values.
|
||||
```
|
||||
gam <UserTypeEntity> print chatmessages [todrive <ToDriveAttribute>*]
|
||||
<ChatSpace>+
|
||||
[showdeleted [<Boolean>]] [filter <String>]
|
||||
[showdeleted [<Boolean>]]
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[thread <ChatThread>])
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime [ascending|descending]]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
|
||||
@@ -952,38 +960,76 @@ The `quotechar <Character>` option allows you to choose an alternate quote chara
|
||||
|
||||
By default, deleted messages are not displayed; use `showdeleted` to also display deleted messages.
|
||||
|
||||
Use `filter <String>` to filter messages by `createTime` and `thread.name`.
|
||||
To filter messages by the time they were created:
|
||||
* `start|starttime <Date>|<Time>` - Display messages created on or after the `<Date>|<Time>`
|
||||
* `end|endtime <Date>|<Time>` - Display messages created before the `<Date>|<Time>`
|
||||
* `range <Date>|<Time> <Date>|<Time>` - Display messages created on or after the first `<Date>|<Time>` and before the second `<Date>|<Time>`
|
||||
|
||||
To filter messages by the date they were created, specify the createTime with a timestamp in RFC-3339 format and double quotation marks. For example, "2023-04-21T11:30:00-04:00".
|
||||
* Use the greater than operator `>` to list messages that were created after a timestamp.
|
||||
* Use the less than operator `<` to list messages that were created before a timestamp.
|
||||
* To filter messages within a time interval, use the AND operator between two timestamps.
|
||||
* To filter by thread, specify the thread.name, formatted as spaces/{space}/threads/{thread}. You can only specify one thread.name per query.
|
||||
* To filter by both thread and date, use the AND operator in your query.
|
||||
Use `thread <String>` to filter messages by their thread name, e.g., `spaces/AAAAAAAAAAA/threads/123`.
|
||||
|
||||
For example, the following queries are valid on Linux/MacOS:
|
||||
## Display Chat Messages by Searching
|
||||
These commands are in Developer Preview; to use them you must have these values set in `gam.cfg`.
|
||||
```
|
||||
filter 'createTime > "2012-04-21T11:30:00-04:00"'
|
||||
filter 'createTime > "2012-04-21T11:30:00-04:00" AND thread.name = spaces/AAAAAAAAAAA/threads/123'
|
||||
filter 'createTime > "2012-04-21T11:30:00+00:00" AND createTime < "2013-01-01T00:00:00+00:00" AND thread.name = spaces/AAAAAAAAAAA/threads/123'
|
||||
filter 'thread.name = spaces/AAAAAAAAAAA/threads/123'
|
||||
developer_preview_apis = chat
|
||||
developer_preview_api_key = <DeveloperPreviewKey>
|
||||
```
|
||||
See the following for search option details:
|
||||
https://developers.google.com/workspace/chat/api/reference/rest/v1/spaces.messages/search
|
||||
|
||||
For example, the following queries are valid on Windows Command Prompt:
|
||||
```
|
||||
filter "createTime > \"2012-04-21T11:30:00-04:00\""
|
||||
filter "createTime > \"2012-04-21T11:30:00-04:00\" AND thread.name = spaces/AAAAAAAAAAA/threads/123"
|
||||
filter "createTime > \"2012-04-21T11:30:00+00:00\" AND createTime < \"2013-01-01T00:00:00+00:00\" AND thread.name = spaces/AAAAAAAAAAA/threads/123"
|
||||
filter "thread.name = spaces/AAAAAAAAAAA/threads/123"
|
||||
```
|
||||
You must specify `keywords <StringList>`; messages that match any word|phrase in `<StringList>` are displayed.
|
||||
Phrases must be enclosed in `"`.
|
||||
* Linux, macOS, Windows Command Prompt - `keywords "\"things to do\" urgent"`
|
||||
* Windows Power Shell - ```keywords "`"things to do`" urgent"```
|
||||
|
||||
For example, the following queries are valid on Windows PowerShell:
|
||||
By default, all spaces the user has access to are searched; use the following options to limit the search.
|
||||
* `<ChatSpace>*` - Specific chat spaces
|
||||
* `displaynames [all|any] <StringList>` - Spaces with display names with partial matches of `all|any` of the words in `<StringList>`
|
||||
|
||||
Use the following to limit the search to messages with specific characteristics.
|
||||
* `senders <EmailAddressEntity>` - Messages with any sender in `<EmailAddressEntity>`
|
||||
* `usermentions [all|any] <EmailAddressEntity>` - Messages with mentions of `all|any` users in `<EmailAddressEntity>`
|
||||
* `start|starttime <Date>|<Time>` - Messages created on or after the `<Date>|<Time>`
|
||||
* `end|endtime <Date>|<Time>` - Messages created before the `<Date>|<Time>`
|
||||
* `range <Date>|<Time> <Date>|<Time>` - Messages created on or after the first `<Date>|<Time>` and before the second `<Date>|<Time>`
|
||||
* `hasattachment` - Messages with at least one attachment
|
||||
```
|
||||
filter 'createTime > \"2012-04-21T11:30:00-04:00\"'
|
||||
filter 'createTime > \"2012-04-21T11:30:00-04:00\" AND thread.name = spaces/AAAAAAAAAAA/threads/123"'
|
||||
filter 'createTime > \"2012-04-21T11:30:00+00:00\" AND createTime < \"2013-01-01T00:00:00+00:00\" AND thread.name = spaces/AAAAAAAAAAA/threads/123'
|
||||
filter 'thread.name = spaces/AAAAAAAAAAA/threads/123'
|
||||
gam <UserTypeEntity> show chatsearchmessages
|
||||
keywords <StringList>
|
||||
<ChatSpace>*
|
||||
[displaynames [all|any] <StringList>]
|
||||
[senders <EmailAddressEntity>]*
|
||||
[usermentions [all|any] <EmailAddressEntity>]*
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[hasattachment]
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime|relevance]
|
||||
[formatjson]
|
||||
```
|
||||
By default, Gam displays the information as an indented list of keys and values.
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
```
|
||||
gam <UserTypeEntity> print chatsearchmessages [todrive <ToDriveAttribute>*]
|
||||
keywords <StringList>
|
||||
<ChatSpace>*
|
||||
[displaynames [all|any] <StringList>]
|
||||
[senders <EmailAddressEntity>]*
|
||||
[usermentions [all|any] <EmailAddressEntity>]*
|
||||
[([start|starttime <Date>|<Time>] [end|endtime <Date>|<Time>])|(range <Date>|<Time> <Date>|<Time>)]
|
||||
[hasattachment]
|
||||
[fields <ChatMessageFieldNameList>]
|
||||
[orderby createtime|relevance]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
|
||||
* `formatjson` - Display the fields in JSON format.
|
||||
|
||||
By default, when writing CSV files, Gam uses a quote character of double quote `"`. The quote character is used to enclose columns that contain
|
||||
the quote character itself, the column delimiter (comma by default) and new-line characters. Any quote characters within the column are doubled.
|
||||
When using the `formatjson` option, double quotes are used extensively in the data resulting in hard to read/process output.
|
||||
The `quotechar <Character>` option allows you to choose an alternate quote character, single quote for instance, that makes for readable/processable output.
|
||||
`quotechar` defaults to `gam.cfg/csv_output_quote_char`. When uploading CSV files to Google, double quote `"` should be used.
|
||||
|
||||
|
||||
## Display Chat Events
|
||||
Display a specific Chat event.
|
||||
|
||||
@@ -477,12 +477,12 @@ When `matchlabel <LabelName>` is specified, the following characters are replace
|
||||
|
||||
## Forward messages/threads
|
||||
```
|
||||
gam <UserTypeEntity> forward message|messages recipient|to <RecipientEntity>
|
||||
gam <UserTypeEntity> forward message|messages [recipient|to] <RecipientEntity>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <MessageIDEntity>)
|
||||
[subject <String>] [addorigfieldstosubject]
|
||||
gam <UserTypeEntity> forward thread|threads recipient|to <RecipientEntity>
|
||||
gam <UserTypeEntity> forward thread|threads [recipient|to] <RecipientEntity>
|
||||
(((query <QueryGmail> [querytime<String> <Date>]*) (matchlabel <LabelName>) [or|and])+
|
||||
[labelids <LabelIDList>]
|
||||
[quick|notquick] [doit] [max_to_forward <Number>])|(ids <ThreadIDEntity>)
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAM 7.43.06 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.44.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.4 64-bit final
|
||||
macOS Tahoe 26.4.1 arm64
|
||||
Python 3.14.5 64-bit final
|
||||
macOS Tahoe 26.5 arm64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
Time: 2026-02-15T07:51:00-08:00
|
||||
@@ -15,10 +15,10 @@ Time: 2026-02-15T07:51:00-08:00
|
||||
Print the current version of Gam with details and time offset information
|
||||
```
|
||||
gam version timeoffset
|
||||
GAM 7.43.06 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.44.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.4 64-bit final
|
||||
macOS Tahoe 26.4.1 arm64
|
||||
Python 3.14.5 64-bit final
|
||||
macOS Tahoe 26.5 arm64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
Your system time differs from www.googleapis.com by less than 1 second
|
||||
@@ -27,10 +27,10 @@ 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.43.06 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM 7.44.03 - https://github.com/GAM-team/GAM - pyinstaller
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.4 64-bit final
|
||||
macOS Tahoe 26.4.1 arm64
|
||||
Python 3.14.5 64-bit final
|
||||
macOS Tahoe 26.5 arm64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
Time: 2026-02-15T07:51:00-08:00
|
||||
@@ -68,7 +68,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 7.43.06
|
||||
Latest: 7.44.03
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -76,7 +76,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
7.43.06
|
||||
7.44.03
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -86,10 +86,10 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 7.43.06 - https://github.com/GAM-team/GAM
|
||||
GAM 7.44.03 - https://github.com/GAM-team/GAM
|
||||
GAM Team <google-apps-manager@googlegroups.com>
|
||||
Python 3.14.4 64-bit final
|
||||
macOS Tahoe 26.4.1 arm64
|
||||
Python 3.14.5 64-bit final
|
||||
macOS Tahoe 26.5 arm64
|
||||
Path: /Users/gamteam/bin/gam7
|
||||
Config File: /Users/gamteam/GamConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
|
||||
Time: 2026-02-15T07:51:00-08:00
|
||||
|
||||
Reference in New Issue
Block a user