mirror of
https://github.com/GAM-team/GAM.git
synced 2026-06-23 15:41:36 +00:00
Compare commits
2 Commits
20240720.0
...
20240722.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f777ec177c | ||
|
|
19304f95e8 |
@@ -32,6 +32,7 @@ ENTITY_IS_A_USER_ALIAS_RC = 21
|
||||
ENTITY_IS_A_GROUP_RC = 22
|
||||
ENTITY_IS_A_GROUP_ALIAS_RC = 23
|
||||
ENTITY_IS_AN_UNMANAGED_ACCOUNT_RC = 24
|
||||
ORGUNIT_NOT_EMPTY_RC = 25
|
||||
CHECK_USER_GROUPS_ERROR_RC = 29
|
||||
ORPHANS_COLLECTED_RC = 30
|
||||
# Warnings/Errors
|
||||
@@ -61,4 +62,14 @@ TARGET_DRIVE_SPACE_ERROR_RC = 74
|
||||
USER_REQUIRED_TO_CHANGE_PASSWORD_ERROR_RC = 75
|
||||
USER_SUSPENDED_ERROR_RC = 76
|
||||
NO_CSV_DATA_TO_UPLOAD_RC = 77
|
||||
NO_SA_ACCESS_CONTEXT_MANAGER_EDITOR_ROLE_RC = 78
|
||||
ACCESS_POLICY_ERROR_RC = 79
|
||||
YUBIKEY_CONNECTION_ERROR_RC = 80
|
||||
YUBIKEY_INVALID_KEY_TYPE_RC = 81
|
||||
YUBIKEY_INVALID_SLOT_RC = 82
|
||||
YUBIKEY_INVALID_PIN_RC = 83
|
||||
YUBIKEY_APDU_ERROR_RC = 84
|
||||
YUBIKEY_VALUE_ERROR_RC = 85
|
||||
YUBIKEY_MULTIPLE_CONNECTED_RC = 86
|
||||
YUBIKEY_NOT_FOUND_RC = 87
|
||||
```
|
||||
|
||||
@@ -10,9 +10,20 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
|
||||
|
||||
See [Downloads-Installs](https://github.com/taers232c/GAMADV-XTD3/wiki/Downloads-Installs) for Windows or other options, including manual installation
|
||||
|
||||
### 6.79.00
|
||||
|
||||
Updated code to work around a Cryptography library change that caused service account private key creation to fail.
|
||||
|
||||
### 6.78.00
|
||||
|
||||
Added command to check if an OU contains items; this is useful when tryng to delete an OU
|
||||
as it must not contain any items in order to be deleted.
|
||||
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Organizational-Units#check-organizational-unit-for-contained-items
|
||||
|
||||
### 6.77.18
|
||||
|
||||
Added option `showitemcountonly` to `gam print domainaliasess` that causes GAM to display the
|
||||
Added option `showitemcountonly` to `gam print domainaliases` that causes GAM to display the
|
||||
number of domain aliasess on stdout; no CSV file is written.
|
||||
|
||||
### 6.77.17
|
||||
|
||||
@@ -251,7 +251,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
|
||||
GAMADV-XTD3 6.77.18 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.79.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.4 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
@@ -923,7 +923,7 @@ writes the credentials into the file oauth2.txt.
|
||||
C:\>del C:\GAMConfig\oauth2.txt
|
||||
C:\>gam version
|
||||
WARNING: Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, Item: oauth2_txt, Value: C:\GAMConfig\oauth2.txt, Not Found
|
||||
GAMADV-XTD3 6.77.18 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.79.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.4 64-bit final
|
||||
Windows-10-10.0.17134 AMD64
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
- [Print organizational units](#print-organizational-units)
|
||||
- [Display organizational unit counts](#display-organizational-unit-counts)
|
||||
- [Display indented organizational unit tree](#display-indented-organizational-unit-tree)
|
||||
- [Check organizational unit for contained items](#check-organizational-unit-for-contained-items)
|
||||
- [Special case handling for large number of organizational units](#special-case-handling-for-large-number-of-organizational-units)
|
||||
|
||||
## API documentation
|
||||
@@ -270,6 +271,44 @@ gam show orgtree [fromparent <OrgUnitItem>] [batchsuborgs [<Boolean>]]
|
||||
By default, Gam displays the organizational unit tree starting at /.
|
||||
* `fromparent <OrgUnitItem>` - Display the organizational unit tree starting at `<OrgUnitItem>`.
|
||||
|
||||
## Check organizational unit for contained items
|
||||
An organizational unit can be deleted only when it contains no items:
|
||||
* Chrome Browsers
|
||||
* ChromeOS Devices
|
||||
* Shared Drives
|
||||
* Sub Org Units
|
||||
* Users
|
||||
|
||||
This command counts those items and displays a CSV file with the item counts.
|
||||
* All counts are zero - A return code of 0 is returned and the `empty` column is `True`
|
||||
* Some count is greater than 0 - A return code of 25 is returned and the `empty` column is `False`
|
||||
|
||||
Only items directly within the OU are counted, items in sub-OUs are not counted.
|
||||
```
|
||||
<OrgUnitCheckName> ::=
|
||||
browsers|
|
||||
devices|
|
||||
shareddrives|
|
||||
subous|
|
||||
users
|
||||
<OrgUnitCheckNameList> ::= "<OrgUnitCheckName>(,<OrgUnitCheckName>)*"
|
||||
|
||||
gam check org|ou <OrgUnitItem> [todrive <ToDriveAttribute>*]
|
||||
[<OrgUnitCheckName>*|(fields <OrgUnitCheckNameList>)]
|
||||
[formatjson [quotechar <Character>]]
|
||||
```
|
||||
By default, GAM checks each of the five items; you can select specfic fields
|
||||
with `<OrgUnitCheckName>*` or `fields <OrgUnitCheckNameList>`.
|
||||
|
||||
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.
|
||||
|
||||
## Special case handling for large number of organizational units
|
||||
|
||||
By default, the `print orgs` and `show orgtree` commands issue a single API call to get the
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Print the current version of Gam with details
|
||||
```
|
||||
gam version
|
||||
GAMADV-XTD3 6.77.18 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.79.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.4 64-bit final
|
||||
MacOS Sonoma 14.5 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
|
||||
GAMADV-XTD3 6.77.18 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.79.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.4 64-bit final
|
||||
MacOS Sonoma 14.5 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
|
||||
GAMADV-XTD3 6.77.18 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
GAMADV-XTD3 6.79.00 - https://github.com/taers232c/GAMADV-XTD3 - pythonsource
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.4 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
@@ -64,7 +64,7 @@ MacOS High Sierra 10.13.6 x86_64
|
||||
Path: /Users/Admin/bin/gamadv-xtd3
|
||||
Version Check:
|
||||
Current: 5.35.08
|
||||
Latest: 6.77.18
|
||||
Latest: 6.79.00
|
||||
echo $?
|
||||
1
|
||||
```
|
||||
@@ -72,7 +72,7 @@ echo $?
|
||||
Print the current version number without details
|
||||
```
|
||||
gam version simple
|
||||
6.77.18
|
||||
6.79.00
|
||||
```
|
||||
In Linux/MacOS you can do:
|
||||
```
|
||||
@@ -82,7 +82,7 @@ echo $VER
|
||||
Print the current version of Gam and address of this Wiki
|
||||
```
|
||||
gam help
|
||||
GAM 6.77.18 - https://github.com/taers232c/GAMADV-XTD3
|
||||
GAM 6.79.00 - https://github.com/taers232c/GAMADV-XTD3
|
||||
Ross Scroggs <ross.scroggs@gmail.com>
|
||||
Python 3.12.4 64-bit final
|
||||
MacOS Sonoma 14.5 x86_64
|
||||
|
||||
@@ -3275,8 +3275,7 @@ gam delete domain <DomainName>
|
||||
|
||||
gam info domain [<DomainName>]
|
||||
[formatjson]
|
||||
gam print domains
|
||||
[todrive <ToDriveAttribute>*]
|
||||
gam print domains [todrive <ToDriveAttribute>*]
|
||||
[formatjson [quotechar <Character>]]
|
||||
[showitemcountonly]
|
||||
gam show domains
|
||||
@@ -3286,10 +3285,14 @@ gam show domains
|
||||
gam create|add domainalias|aliasdomain <DomainAlias> <DomainName>
|
||||
gam delete domainalias|aliasdomain <DomainAlias>
|
||||
|
||||
gam info domainalias|aliasdomain <DomainAlias> [formatjson]
|
||||
gam info domainalias|aliasdomain <DomainAlias>
|
||||
[formatjson]
|
||||
gam print domainaliases|aliasdomains [todrive <ToDriveAttribute>*]
|
||||
[formatjson [quotechar <Character>]]
|
||||
gam show domainaliases|aliasdomains [formatjson]
|
||||
[showitemcountonly]
|
||||
gam show domainaliases|aliasdomains
|
||||
[formatjson]
|
||||
[showitemcountonly]
|
||||
|
||||
# Domain - Contacts and Global Address List
|
||||
|
||||
@@ -4214,6 +4217,18 @@ gam print orgs|ous [todrive <ToDriveAttribute>*]
|
||||
[showitemcountonly]
|
||||
gam show orgtree [fromparent <OrgUnitItem>] [batchsuborgs [<Boolean>]]
|
||||
|
||||
<OrgUnitCheckName> ::=
|
||||
browsers|
|
||||
devices|
|
||||
shareddrives|
|
||||
subous|
|
||||
users
|
||||
<OrgUnitCheckNameList> ::= "<OrgUnitCheckName>(,<OrgUnitCheckName>)*"
|
||||
|
||||
gam check org|ou <OrgUnitItem> [todrive <ToDriveAttribute>*]
|
||||
[<OrgUnitCheckName>*|(fields <OrgUnitCheckNameList>)]
|
||||
[formatjson [quotechar <Character>]]
|
||||
|
||||
# Printers
|
||||
|
||||
<PrinterAttribute> ::=
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
6.79.00
|
||||
|
||||
Updated code to work around a Cryptography library change that caused service account private key creation to fail.
|
||||
|
||||
7.00.00
|
||||
|
||||
Merged GAM-Team version
|
||||
|
||||
6.78.00
|
||||
|
||||
Added command to check if an OU contains items; this is useful when tryng to delete an OU
|
||||
as it must not contain any items in order to be deleted.
|
||||
|
||||
* See: https://github.com/taers232c/GAMADV-XTD3/wiki/Organizational-Units#check-organizational-unit-for-contained-items
|
||||
|
||||
6.77.18
|
||||
|
||||
Added option `showitemcountonly` to `gam print domainaliases` that causes GAM to display the
|
||||
number of domain aliasess on stdout; no CSV file is written.
|
||||
|
||||
6.77.17
|
||||
|
||||
Added option `showitemcountonly` to `gam print domains` that causes GAM to display the
|
||||
|
||||
@@ -332,6 +332,7 @@ ENTITY_IS_A_USER_ALIAS_RC = 21
|
||||
ENTITY_IS_A_GROUP_RC = 22
|
||||
ENTITY_IS_A_GROUP_ALIAS_RC = 23
|
||||
ENTITY_IS_AN_UNMANAGED_ACCOUNT_RC = 24
|
||||
ORGUNIT_NOT_EMPTY_RC = 25
|
||||
CHECK_USER_GROUPS_ERROR_RC = 29
|
||||
ORPHANS_COLLECTED_RC = 30
|
||||
# Warnings/Errors
|
||||
@@ -8890,14 +8891,6 @@ def getTodriveOnly(csvPF):
|
||||
else:
|
||||
unknownArgumentExit()
|
||||
|
||||
def getTodriveFJQCOnly(csvPF, FJQC, addTitle=False, noExit=False):
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, addTitle, noExit)
|
||||
|
||||
DEFAULT_SKIP_OBJECTS = {'kind', 'etag', 'etags', '@type'}
|
||||
|
||||
# Clean a JSON object
|
||||
@@ -12355,8 +12348,8 @@ def _generatePrivateKeyAndPublicCert(projectId, clientEmail, name, key_size, b64
|
||||
writeStdout(Msg.EXTRACTING_PUBLIC_CERTIFICATE+'\n')
|
||||
public_key = private_key.public_key()
|
||||
builder = x509.CertificateBuilder()
|
||||
builder = builder.subject_name(x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, name)]))
|
||||
builder = builder.issuer_name(x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, name)]))
|
||||
builder = builder.subject_name(x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, name, _validate=False)]))
|
||||
builder = builder.issuer_name(x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, name, _validate=False)]))
|
||||
# Gooogle seems to enforce the not before date strictly. Set the not before
|
||||
# date to be UTC two minutes ago which should cover any clock skew.
|
||||
now = datetime.datetime.utcnow()
|
||||
@@ -15763,18 +15756,33 @@ def _printDomain(domain, csvPF):
|
||||
|
||||
DOMAIN_ALIAS_SORT_TITLES = ['domainAliasName', 'parentDomainName', 'creationTime', 'verified']
|
||||
|
||||
# gam print domainaliases [todrive <ToDriveAttribute>*] [formatjson [quotechar <Character>]]
|
||||
# gam show domainaliases [formatjson]
|
||||
# gam print domainaliases [todrive <ToDriveAttribute>*]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
# [showitemcountonly]
|
||||
# gam show domainaliases
|
||||
# [formatjson]
|
||||
# [showitemcountonly]
|
||||
def doPrintShowDomainAliases():
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
csvPF = CSVPrintFile(['domainAliasName'], DOMAIN_ALIAS_SORT_TITLES) if Act.csvFormat() else None
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
getTodriveFJQCOnly(csvPF, FJQC, True)
|
||||
showItemCountOnly = False
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
elif myarg == 'showitemcountonly':
|
||||
showItemCountOnly = True
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
try:
|
||||
domainAliases = callGAPIitems(cd.domainAliases(), 'list', 'domainAliases',
|
||||
throwReasons=[GAPI.BAD_REQUEST, GAPI.NOT_FOUND, GAPI.FORBIDDEN],
|
||||
customer=GC.Values[GC.CUSTOMER_ID])
|
||||
count = len(domainAliases)
|
||||
if showItemCountOnly:
|
||||
writeStdout(f'{count}\n')
|
||||
return
|
||||
i = 0
|
||||
for domainAlias in domainAliases:
|
||||
i += 1
|
||||
@@ -17477,7 +17485,11 @@ def _getOrgUnits(cd, orgUnitPath, fieldsList, listType, showParent, batchSubOrgs
|
||||
else:
|
||||
fields = ','.join(set(fieldsList))
|
||||
listfields = f'organizationUnits({fields})'
|
||||
printGettingAllAccountEntities(Ent.ORGANIZATIONAL_UNIT)
|
||||
if listType == 'all' and orgUnitPath == '/':
|
||||
printGettingAllAccountEntities(Ent.ORGANIZATIONAL_UNIT)
|
||||
else:
|
||||
printGettingAllEntityItemsForWhom(Ent.CHILD_ORGANIZATIONAL_UNIT, orgUnitPath,
|
||||
qualifier=' (Direct Children)' if listType == 'children' else '', entityType=Ent.ORGANIZATIONAL_UNIT)
|
||||
if listType == 'children':
|
||||
batchSubOrgs = False
|
||||
try:
|
||||
@@ -17515,7 +17527,10 @@ def _getOrgUnits(cd, orgUnitPath, fieldsList, listType, showParent, batchSubOrgs
|
||||
except (GAPI.invalidOrgunit, GAPI.orgunitNotFound, GAPI.backendError,
|
||||
GAPI.badRequest, GAPI.invalidCustomerId, GAPI.loginRequired):
|
||||
pass
|
||||
printGotAccountEntities(len(orgUnits))
|
||||
if listType == 'all' and orgUnitPath == '/':
|
||||
printGotAccountEntities(len(orgUnits))
|
||||
else:
|
||||
printGotEntityItemsForWhom(len(orgUnits))
|
||||
if childSelector is not None:
|
||||
for orgUnit in orgUnits:
|
||||
orgUnit[ORG_UNIT_SELECTOR_FIELD] = childSelector if orgUnit['orgUnitPath'] != orgUnitPath else parentSelector
|
||||
@@ -17748,6 +17763,157 @@ def doShowOrgTree():
|
||||
for org in sorted(orgTree):
|
||||
printOrgUnit(org, orgTree)
|
||||
|
||||
ORG_ITEMS_FIELD_MAP = {
|
||||
'browsers': 'browsers',
|
||||
'devices': 'devices',
|
||||
'shareddrives': 'sharedDrives',
|
||||
'subous': 'subOus',
|
||||
'users': 'users',
|
||||
}
|
||||
|
||||
# gam check org|ou <OrgUnitItem> [todrive <ToDriveAttribute>*]
|
||||
# [<OrgUnitCheckName>*|(fields <OrgUnitCheckNameList>)]
|
||||
# [formatjson [quotechar <Character>]]
|
||||
def doCheckOrgUnit():
|
||||
cd = buildGAPIObject(API.DIRECTORY)
|
||||
csvPF = CSVPrintFile(['orgUnitPath', 'orgUnitId', 'empty'])
|
||||
FJQC = FormatJSONQuoteChar(csvPF)
|
||||
orgUnitPath = None
|
||||
fieldsList = []
|
||||
titlesList = []
|
||||
status, orgUnitPath, orgUnitId = checkOrgUnitPathExists(cd, getOrgUnitItem())
|
||||
orgUnitPathLower = orgUnitPath.lower()
|
||||
if not status:
|
||||
entityDoesNotExistExit(Ent.ORGANIZATIONAL_UNIT, orgUnitPath)
|
||||
while Cmd.ArgumentsRemaining():
|
||||
myarg = getArgument()
|
||||
if csvPF and myarg == 'todrive':
|
||||
csvPF.GetTodriveParameters()
|
||||
elif myarg in ORG_ITEMS_FIELD_MAP:
|
||||
fieldsList.append(myarg)
|
||||
elif myarg == 'fields':
|
||||
for field in _getFieldsList():
|
||||
if field in ORG_ITEMS_FIELD_MAP:
|
||||
fieldsList.append(field)
|
||||
else:
|
||||
invalidChoiceExit(field, list(ORG_ITEMS_FIELD_MAP), True)
|
||||
else:
|
||||
FJQC.GetFormatJSONQuoteChar(myarg, True)
|
||||
if orgUnitPath is None:
|
||||
missingArgumentExit('orgunit <OrgUnitItem>')
|
||||
if not fieldsList:
|
||||
fieldsList = ORG_ITEMS_FIELD_MAP.keys()
|
||||
orgUnitItemCounts = {}
|
||||
for field in sorted(fieldsList):
|
||||
title = ORG_ITEMS_FIELD_MAP[field]
|
||||
orgUnitItemCounts[title] = 0
|
||||
if not FJQC.formatJSON:
|
||||
titlesList.append(title)
|
||||
if 'browsers' in fieldsList:
|
||||
cbcm = buildGAPIObject(API.CBCM)
|
||||
customerId = _getCustomerIdNoC()
|
||||
printGettingAllEntityItemsForWhom(Ent.CHROME_BROWSER, orgUnitPath, entityType=Ent.ORGANIZATIONAL_UNIT)
|
||||
pageMessage = getPageMessage()
|
||||
try:
|
||||
feed = yieldGAPIpages(cbcm.chromebrowsers(), 'list', 'browsers',
|
||||
pageMessage=pageMessage, messageAttribute='deviceId',
|
||||
throwReasons=[GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.INVALID_ORGUNIT, GAPI.FORBIDDEN],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
customer=customerId, orgUnitPath=orgUnitPath, projection='BASIC',
|
||||
fields='nextPageToken,browsers(deviceId)')
|
||||
for browsers in feed:
|
||||
orgUnitItemCounts['browsers'] += len(browsers)
|
||||
except (GAPI.invalidInput, GAPI.forbidden) as e:
|
||||
entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e))
|
||||
except GAPI.invalidOrgunit as e:
|
||||
entityActionFailedExit([Ent.CHROME_BROWSER, None], str(e))
|
||||
except (GAPI.badRequest, GAPI.resourceNotFound):
|
||||
accessErrorExit(None)
|
||||
if 'devices' in fieldsList:
|
||||
printGettingAllEntityItemsForWhom(Ent.CROS_DEVICE, orgUnitPath, entityType=Ent.ORGANIZATIONAL_UNIT)
|
||||
pageMessage = getPageMessageForWhom()
|
||||
pageToken = None
|
||||
totalItems = 0
|
||||
tokenRetries = 0
|
||||
while True:
|
||||
try:
|
||||
feed = callGAPI(cd.chromeosdevices(), 'list',
|
||||
throwReasons=[GAPI.INVALID_INPUT, GAPI.INVALID_ORGUNIT,
|
||||
GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
|
||||
retryReasons=GAPI.SERVICE_NOT_AVAILABLE_RETRY_REASONS,
|
||||
pageToken=pageToken, customerId=GC.Values[GC.CUSTOMER_ID],
|
||||
orgUnitPath=orgUnitPath, fields='nextPageToken,chromeosdevices(deviceId)', maxResults=GC.Values[GC.DEVICE_MAX_RESULTS])
|
||||
tokenRetries = 0
|
||||
pageToken, totalItems = _processGAPIpagesResult(feed, 'chromeosdevices', None, totalItems, pageMessage, None, Ent.CROS_DEVICE)
|
||||
if feed:
|
||||
orgUnitItemCounts['devices'] += len(feed.get('chromeosdevices', []))
|
||||
del feed
|
||||
if not pageToken:
|
||||
_finalizeGAPIpagesResult(pageMessage)
|
||||
printGotAccountEntities(totalItems)
|
||||
break
|
||||
except GAPI.invalidInput as e:
|
||||
message = str(e)
|
||||
# Invalid Input: xyz - Check for invalid pageToken!!
|
||||
# 0123456789012345
|
||||
if message[15:] == pageToken:
|
||||
tokenRetries += 1
|
||||
if tokenRetries <= 2:
|
||||
writeStderr(f'{WARNING_PREFIX}{Msg.LIST_CHROMEOS_INVALID_INPUT_PAGE_TOKEN_RETRY}')
|
||||
time.sleep(tokenRetries*5)
|
||||
continue
|
||||
entityActionFailedWarning([Ent.CROS_DEVICE, None], message)
|
||||
break
|
||||
entityActionFailedWarning([Ent.CROS_DEVICE, None], message)
|
||||
break
|
||||
except GAPI.invalidOrgunit as e:
|
||||
entityActionFailedExit([Ent.CROS_DEVICE, None], str(e))
|
||||
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
|
||||
accessErrorExit(cd)
|
||||
if 'shareddrives' in fieldsList:
|
||||
ci = buildGAPIObject(API.CLOUDIDENTITY_ORGUNITS_BETA)
|
||||
printGettingAllEntityItemsForWhom(Ent.SHAREDDRIVE, orgUnitPath, entityType=Ent.ORGANIZATIONAL_UNIT)
|
||||
sds = callGAPIpages(ci.orgUnits().memberships(), 'list', 'orgMemberships',
|
||||
pageMessage=getPageMessageForWhom(),
|
||||
parent=f'orgUnits/{orgUnitId[3:]}',
|
||||
customer=_getCustomersCustomerIdWithC(),
|
||||
filter="type == 'shared_drive'")
|
||||
orgUnitItemCounts['sharedDrives'] = len(sds)
|
||||
if 'subous' in fieldsList:
|
||||
orgUnitItemCounts['subOus'] = len(_getOrgUnits(cd, orgUnitPath, ['orgUnitPath'], 'children', False, False, None, None))
|
||||
if 'users' in fieldsList:
|
||||
printGettingAllEntityItemsForWhom(Ent.USER, orgUnitPath, entityType=Ent.ORGANIZATIONAL_UNIT)
|
||||
pageMessage = getPageMessageForWhom()
|
||||
try:
|
||||
feed = yieldGAPIpages(cd.users(), 'list', 'users',
|
||||
pageMessage=pageMessage,
|
||||
throwReasons=[GAPI.INVALID_ORGUNIT, GAPI.ORGUNIT_NOT_FOUND,
|
||||
GAPI.INVALID_INPUT, GAPI.BAD_REQUEST, GAPI.RESOURCE_NOT_FOUND, GAPI.FORBIDDEN],
|
||||
customer=GC.Values[GC.CUSTOMER_ID], query=orgUnitPathQuery(orgUnitPath, None),
|
||||
fields='nextPageToken,users(orgUnitPath)', maxResults=GC.Values[GC.USER_MAX_RESULTS])
|
||||
for users in feed:
|
||||
for user in users:
|
||||
if orgUnitPathLower == user.get('orgUnitPath', '').lower():
|
||||
orgUnitItemCounts['users'] += 1
|
||||
except (GAPI.invalidOrgunit, GAPI.orgunitNotFound, GAPI.invalidInput, GAPI.badRequest, GAPI.backendError,
|
||||
GAPI.invalidCustomerId, GAPI.loginRequired, GAPI.resourceNotFound, GAPI.forbidden):
|
||||
checkEntityDNEorAccessErrorExit(cd, Ent.ORGANIZATIONAL_UNIT, orgUnitPath)
|
||||
empty = True
|
||||
for count in orgUnitItemCounts.values():
|
||||
if count > 0:
|
||||
empty = False
|
||||
break
|
||||
baseRow = {'orgUnitPath': orgUnitPath, 'orgUnitId': orgUnitId, 'empty': empty}
|
||||
row = flattenJSON(orgUnitItemCounts, baseRow.copy())
|
||||
if not FJQC.formatJSON:
|
||||
csvPF.WriteRowTitles(row)
|
||||
elif csvPF.CheckRowTitles(row):
|
||||
baseRow['JSON'] = json.dumps(cleanJSON(orgUnitItemCounts), ensure_ascii=False, sort_keys=True)
|
||||
csvPF.WriteRowNoFilter(baseRow)
|
||||
csvPF.writeCSVfile(f'OrgUnit {orgUnitPath} Item Counts')
|
||||
if not empty and GM.Globals[GM.SYSEXITRC] == 0:
|
||||
setSysExitRC(ORGUNIT_NOT_EMPTY_RC)
|
||||
|
||||
ALIAS_TARGET_TYPES = ['user', 'group', 'target']
|
||||
|
||||
# gam create aliases|nicknames <EmailAddressEntity> user|group|target <UniqueID>|<EmailAddress>
|
||||
@@ -25050,10 +25216,10 @@ def doPrintShowBrowsers():
|
||||
else:
|
||||
entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e))
|
||||
return
|
||||
except GAPI.invalidOrgunit as e:
|
||||
except (GAPI.invalidOrgunit, GAPI.forbidden) as e:
|
||||
entityActionFailedWarning([Ent.CHROME_BROWSER, None], str(e))
|
||||
return
|
||||
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
|
||||
except (GAPI.badRequest, GAPI.resourceNotFound):
|
||||
accessErrorExit(None)
|
||||
else:
|
||||
sortRows = True
|
||||
@@ -43806,18 +43972,21 @@ def doPrintUsers(entityList=None):
|
||||
projection=schemaParms['projection'], customFieldMask=schemaParms['customFieldMask'],
|
||||
maxResults=maxResults, **kwargs)
|
||||
for users in feed:
|
||||
if showItemCountOnly:
|
||||
itemCount += len(users)
|
||||
continue
|
||||
if orgUnitPath is None:
|
||||
if not printOptions['countOnly']:
|
||||
if showItemCountOnly:
|
||||
itemCount += len(users)
|
||||
elif not printOptions['countOnly']:
|
||||
for user in users:
|
||||
_printUser(user, 0, 0)
|
||||
else:
|
||||
for user in users:
|
||||
_updateDomainCounts(user['primaryEmail'])
|
||||
else:
|
||||
if not printOptions['countOnly']:
|
||||
if showItemCountOnly:
|
||||
for user in users:
|
||||
if orgUnitPathLower == user.get('orgUnitPath', '').lower():
|
||||
itemCount += 1
|
||||
elif not printOptions['countOnly']:
|
||||
for user in users:
|
||||
if orgUnitPathLower == user.get('orgUnitPath', '').lower():
|
||||
_printUser(user, 0, 0)
|
||||
@@ -63853,7 +64022,9 @@ def doPrintShowOrgunitSharedDrives():
|
||||
if csvPF and FJQC.formatJSON:
|
||||
csvPF.SetJSONTitles(['name', 'JSON'])
|
||||
_, orgUnitId = getOrgUnitId(None, orgUnitPath)
|
||||
printGettingAllEntityItemsForWhom(Ent.SHAREDDRIVE, orgUnitPath, entityType=Ent.ORGANIZATIONAL_UNIT)
|
||||
sds = callGAPIpages(ci.orgUnits().memberships(), 'list', 'orgMemberships',
|
||||
pageMessage=getPageMessageForWhom(),
|
||||
parent=f'orgUnits/{orgUnitId[3:]}',
|
||||
customer=_getCustomersCustomerIdWithC(),
|
||||
filter="type == 'shared_drive'")
|
||||
@@ -73666,6 +73837,7 @@ MAIN_COMMANDS_WITH_OBJECTS = {
|
||||
{Cmd.ARG_SVCACCT: doCheckUpdateSvcAcct,
|
||||
Cmd.ARG_USERINVITATION: doCheckCIUserInvitations,
|
||||
Cmd.ARG_ISINVITABLE: doCheckCIUserInvitations,
|
||||
Cmd.ARG_ORG: doCheckOrgUnit,
|
||||
}
|
||||
),
|
||||
'clear':
|
||||
|
||||
@@ -94,6 +94,7 @@ class GamEntity():
|
||||
CHAT_MESSAGE_ID = 'chmi'
|
||||
CHAT_SPACE = 'chsp'
|
||||
CHAT_THREAD = 'chth'
|
||||
CHILD_ORGANIZATIONAL_UNIT = 'corg'
|
||||
CHROME_APP = 'capp'
|
||||
CHROME_APP_DEVICE = 'capd'
|
||||
CHROME_BROWSER = 'chbr'
|
||||
@@ -435,6 +436,7 @@ class GamEntity():
|
||||
CHAT_MEMBER_USER: ['Chat User Members', 'Chat User Member'],
|
||||
CHAT_SPACE: ['Chat Spaces', 'Chat Space'],
|
||||
CHAT_THREAD: ['Chat Threads', 'Chat Thread'],
|
||||
CHILD_ORGANIZATIONAL_UNIT: ['Child Organizational Units', 'Child Organizational Unit'],
|
||||
CHROME_APP: ['Chrome Applications', 'Chrome Application'],
|
||||
CHROME_APP_DEVICE: ['Chrome Application Devices', 'Chrome Application Device'],
|
||||
CHROME_BROWSER: ['Chrome Browsers', 'Chrome Browser'],
|
||||
|
||||
Reference in New Issue
Block a user