Compare commits

..

4 Commits

Author SHA1 Message Date
Ross Scroggs
98ef879a34 Fixed logic flaw in gam print|show policies where non-matching policies were displayed.
Some checks failed
Build and test GAM / build (Win64, build, 8, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.9) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2024-11-10 18:57:22 -08:00
Ross Scroggs
95b3a97925 Added group/ou filtering to print|show policies
Some checks are pending
Build and test GAM / build (Win64, build, 8, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Waiting to run
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Waiting to run
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Waiting to run
Build and test GAM / build (x86_64, build, 4, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.10) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.9) (push) Waiting to run
Build and test GAM / merge (push) Blocked by required conditions
Build and test GAM / publish (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Check for Google Root CA Updates / check-apis (push) Waiting to run
Updated `gam get|update|delete contactphotos` to use the People API
2024-11-10 08:18:43 -08:00
Ross Scroggs
f24629602c Updated gam print chromeapps to correct a trap caused by an API change.
Some checks failed
Build and test GAM / build (Win64, build, 8, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.9) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2024-11-05 12:34:20 -08:00
Ross Scroggs
e5125b6853 Update Users-Classification-Labels.md
Some checks failed
Build and test GAM / build (Win64, build, 8, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 3, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 5, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 7, darwin64-arm64, macos-14) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 1, linux-x86_64, ubuntu-22.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 2, linux-x86_64, ubuntu-24.04) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 4, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 6, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.10) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 12, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.9) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Check for Google Root CA Updates / check-apis (push) Has been cancelled
Build and test GAM / merge (push) Has been cancelled
Build and test GAM / publish (push) Has been cancelled
2024-11-02 15:03:40 -07:00
11 changed files with 245 additions and 228 deletions

View File

@@ -66,9 +66,12 @@ Client access works when accessing Resource calendars.
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
<DomainName> ::= <String>(.<String>)+
<EmailAddress> ::= <String>@<DomainName>
<EmailAddressList> ::= "<EmailAddess>(,<EmailAddress>)*"
<EmailAddressEntity> ::= <EmailAddressList> | <FileSelector> | <CSVFileSelector> | <CSVkmdSelector> | <CSVDataSelector>
<EmailAddressList> ::= "<EmailAddress>(,<EmailAddress>)*"
<EmailAddressEntity> ::=
<EmailAddressList> | <FileSelector> | <CSVFileSelector> |
<CSVkmdSelector> | <CSVDataSelector>
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
<iCalUID> ::= <String>
<EventAttachmentsSubfieldName> ::=
attachments.fileid|

View File

@@ -1,6 +1,7 @@
# Cloud Identity Policies
- [API documentation](#api-documentation)
- [Notes](#notes)
- [Python Regular Expressions](Python-Regular-Expressions) Match function
- [Definitions](#definitions)
- [Policies](#policies)
- [Display Cloud Identity Policies](#display-cloud-identity-policies)
@@ -322,8 +323,8 @@ gam info policies <CIPolicyEntity>
Select policies::
* `polices/<String>` - A policy name, `policies/ahv4hg7qc24kvaghb7zihwf4riid4`
* `settings/<String>` - A policy setting type, `settings/workspace_marketplace.apps_allowlist'
* `<String>` - A policy setting type, `workspace_marketplace.apps_allowlist'
* `settings/<String>` - A policy setting type, `settings/workspace_marketplace.apps_allowlist`
* `<String>` - A policy setting type, `workspace_marketplace.apps_allowlist`
By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display.
@@ -337,10 +338,13 @@ Display all or filtered policies.
```
gam show policies
[filter <String>] [nowarnings] [noappnames]
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
[formatjson]
```
By default, all policies are displayed.
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1beta1/policies/list
* `group <RegularExpression>` - Only display policies whose group email address matches the `<RegularExpression>`
* `ou|org|orgunit <RegularExpression> - Only display policies whose OU path matches the `<RegularExpression>`
By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display.
@@ -353,10 +357,13 @@ By default, Gam displays the information as an indented list of keys and values.
```
gam print policies [todrive <ToDriveAttribute>*]
[filter <String>] [nowarnings] [noappnames]
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
[formatjson [quotechar <Character>]]
```
By default, all policies are displayed:
* `filter <String>` - Display filtered policies, See https://cloud.google.com/identity/docs/reference/rest/v1beta1/policies/list
* `group <RegularExpression>` - Only display policies whose group email address matches the `<RegularExpression>`
* `ou|org|orgunit <RegularExpression> - Only display policies whose OU path matches the `<RegularExpression>`
By default, policy warnings are displayed, use the 'nowarnings` option to suppress their display.
@@ -371,3 +378,9 @@ the quote character itself, the column delimiter (comma by default) and new-line
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.
### Examples
Print all service status policies.
```
gam redirect csv ./ServiceStatusPolicies.csv print policies filter "setting.type.matches('.*service_status')"
```

View File

@@ -10,6 +10,24 @@ Add the `-s` option to the end of the above commands to suppress creating the `g
See [Downloads-Installs-GAM7](https://github.com/GAM-team/GAM/wiki/Downloads-Installs) for Windows or other options, including manual installation
### 7.00.38
Fixed logic flaw in `gam print|show policies` where non-matching policies were displayed.
### 7.00.37
Added options `group <RegularExpression>` and `ou|org|orgunit <RegularExpression>`
to `gam print|show policies` that causes GAM to only display policies whose group email address
or OU path match the `<RegularExpression>`.
Updated `gam get|update|delete contactphotos` to use the People API for domain shared contact photos
as Google has deprecated the Domain Shared Contacts API for these commands. Unfortunately,
the People API fails with `gam update|delete contactphotos`.
### 7.00.36
Updated `gam print chromeapps` to correct a trap caused by an API change.
### 7.00.35
Classification labels are now available for Gmail in addition to Drive.

View File

@@ -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
GAM 7.00.35 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.0 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
GAM7 7.00.35 - https://github.com/GAM-team/GAM - pythonsource
GAM7 7.00.38 - https://github.com/GAM-team/GAM - pythonsource
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.0 64-bit final
Windows-10-10.0.17134 AMD64

View File

@@ -91,20 +91,23 @@
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
<CalendarItem> ::= <EmailAddress>
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
<CalendarEntity> ::= <CalendarList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Items
<DomainName> ::= <String>(.<String>)+
<EmailAddress> ::= <String>@<DomainName>
<EmailAddressList> ::= "<EmailAddress>(,<EmailAddress>)*"
<EmailAddressEntity> ::=
<EmailAddressList> | <FileSelector> | <CSVFileSelector> |
<EmailAddressList> | <FileSelector> | <CSVFileSelector> |
<CSVkmdSelector> | <CSVDataSelector>
See: https://github.com/GAM-team/GAM/wiki/Collections-of-Users
<CalendarItem> ::= <EmailAddress>
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
<CourseAlias> ::= <String>
<CourseID> ::= <Number>|d:<CourseAlias>
<CourseIDList> ::= "<CourseID>(,<CourseID>)*"
<CourseState> ::= active|archived|provisioned|declined
<CourseStateList> ::= all|"<CourseState>(,<CourseState>)*"
<iCalUID> ::= <String>
<ResourceID> ::= <String>
<ResourceIDList> ::= "<ResourceID>(,<ResourceID>)*"
<UniqueID> ::= id:<String>
@@ -122,7 +125,7 @@
allcalendars|
primary|
<EmailAddress>|
<UniqueUD>|
<UniqueID>|
(courses <CourseIDList>)|
((courses_with_teacher <UserItem>)|my_courses_as_teacher
[coursestates <CourseStateList>])|

View File

@@ -6,8 +6,8 @@
- [Display calendar UI settings](#display-calendar-ui-settings)
- [Manage calendars](#manage-calendars)
- [Create and remove calendars](#create-and-remove-calendars)
- [Display calendar settings](#display-calendar-settings)
- [Modify calendar settings](#modify-calendar-settings)
- [Display calendar settings](#display-calendar-settings)
- [Manage calendar lists](#manage-calendar-lists)
- [Display specific calendars from list](#display-specific-calendars-from-list)
- [Display calendar lists](#display-calendar-lists)
@@ -23,6 +23,8 @@
<EmailAddress> ::= <String>@<DomainName>
<CalendarItem> ::= <EmailAddress>
<CalendarList> ::= "<CalendarItem>(,<CalendarItem>)*"
<CalendarEntity> ::= <CalendarList> | <FileSelector> | <CSVkmdSelector> | <CSVDataSelector>
See: https://github.com/taers232c/GAMADV-XTD3/wiki/Collections-of-Items
<CourseAlias> ::= <String>
<CourseID> ::= <Number>|d:<CourseAlias>
<CourseIDList> ::= "<CourseID>(,<CourseID>)*"
@@ -38,6 +40,21 @@
<CalendarACLRole> ::=
editor|freebusy|freebusyreader|owner|reader|writer
<CalendarSettings> ::=
(description <String>)|
(location <String>)|
(summary <String>)|
(timezone <TimeZone>)
<CalendarSettingsField> ::=
conferenceproperties|
description|
id|
location|
summary|
timezone
<CalendarSettingsFieldList> ::= "<CalendarSettingsField>(,<CalendarSettingsField>)*"
<CalendarSelectProperty> ::=
minaccessrole <CalendarACLRole>|
showdeleted|
@@ -111,12 +128,6 @@
(selected <Boolean>)|
(summary <String>)
<CalendarSettings> ::=
(description <String>)|
(location <String>)|
(summary <String>)|
(timezone <TimeZone>)
<CalendarListField> ::=
accessrole|
backgroundcolor|
@@ -189,18 +200,30 @@ gam <UserTypeEntity> create calendar <CalendarSettings>
gam <UserTypeEntity> remove calendars <UserCalendarEntity>
```
### Display calendar settings
```
gam <UserTypeEntity> info calendars <UserCalendarEntity> [formatjson]
```
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
### Modify calendar settings
```
gam <UserTypeEntity> modify calendars <UserCalendarEntity> <CalendarSettings>
```
### Display calendar settings
```
gam calendar <CalendarEntity> show settings
[fields <CalendarSettingsFieldList>]
[formatjson]
```
By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
```
gam calendar <CalendarEntity> print settings [todrive <ToDriveAttribute>*]
[fields <CalendarSettingsFieldList>]
[formatjson [quotechar <Character>]]
```
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.
## Manage calendar lists
These commands manage a user's list of calendars.
```

View File

@@ -4,10 +4,10 @@
- [Notes](#notes)
- [Definitions](#definitions)
- [Introduction](#introduction)
- [Display Drive Labels](#display-drive-labels)
- [Process File Drive Labels](#process-file-drive-labels)
- [Manage Drive Label Permissions](#manage-drive-label-permissions)
- [Display Drive Label Permissions](#display-drive-label-permissions)
- [Display Classification Labels](#display-classification-labels)
- [Manage Classification Label Permissions](#manage-classification-label-permissions)
- [Display Classification Label Permissions](#display-classification-label-permissions)
- [Process Drive File Classification Labels](#process-drive-file-classification-labels)
## API documentation
* https://support.google.com/a/answer/9292382
@@ -24,31 +24,39 @@ To use these commands you must add the 'Drive Labels API' to your project and up
gam update project
gam user user@domain.com update serviceaccount
```
Supported editions for this feature: Business Standard and Business Plus; Enterprise; Education Standard and Education Plus; G Suite Business; Essentials.
Supported editions for this feature:
```
Frontline Starter and Frontline Standard
Business Standard and Business Plus
Enterprise Standard and Enterprise Plus
Education Standard and Education Plus
Essentials, Enterprise Essentials, and Enterprise Essentials Plus
G Suite Business
```
## Definitions
* [`<DriveFileEntity>`](Drive-File-Selection)
* [`<UserTypeEntity>`](Collections-of-Users)
* [`<DriveLabelNameEntity>`, `<DriveLabelPermissionNameEntity'](Collections-of-Items)
* [`<ClassificationLabelNameEntity>`, `<ClassificationLabelPermissionNameEntity`](Collections-of-Items)
* [`<UserTypeEntity>`](Collections-of-Items)
```
<DriveLabelID> ::= <String>
<DriveLabelIDList> ::= "<DriveLabelID>(,<DriveLabelID)*"
<ClassificationLabelID> ::= <String>
<ClassificationLabelIDList> ::= "<ClassificationLabelID>(,<ClassificationLabelID)*"
<DriveLabelName> ::= labels/<DriveLabelID>[@latest|@published|@<Number>]
<DriveLabelNameList> ::= "<DriveLabelName>(,<DriveLabelName)*"
<DriveLabelNameEntity> ::=
<DriveLabelNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<ClassificationLabelName> ::= labels/<ClassificationLabelID>[@latest|@published|@<Number>]
<ClassificationLabelNameList> ::= "<ClassificationLabelName>(,<ClassificationLabelName)*"
<ClassificationLabelNameEntity> ::=
<ClassificationLabelNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<DriveLabelPermissionName> ::= labels/<DriveLabelID>[@latest|@published|@<Number>]/permissions/(audiences|groups|people)/<String>
<DriveLabelPermissionNameList> ::= "<DriveLabelPermissionName>(,<DriveLabelPermissionName>)*"
<DriveLabelPermissionNameEntity> ::=
<DriveLabelPermissionNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<ClassificationLabelPermissionName> ::= labels/<ClassificationLabelID>[@latest|@published|@<Number>]/permissions/(audiences|groups|people)/<String>
<ClassificationLabelPermissionNameList> ::= "<ClassificationLabelPermissionName>(,<ClassificationLabelPermissionName>)*"
<ClassificationLabelPermissionNameEntity> ::=
<ClassificationLabelPermissionNameList> | <FileSelector> | <CSVFileSelector> | <CSVDataSelector>
<DriveLabelFieldID> ::= <String>
<DriveLabelSelectionID> ::= <String>
<DriveLabelSelectionIDList> ::= "<DriveLabelSelectionID>(,<DriveLabelSelectionID)*"
<ClassificationLabelFieldID> ::= <String>
<ClassificationLabelSelectionID> ::= <String>
<ClassificationLabelSelectionIDList> ::= "<ClassificationLabelSelectionID>(,<ClassificationLabelSelectionID)*"
<BCP47LanguageCode> ::=
ar-sa| # Arabic Saudi Arabia
@@ -99,10 +107,10 @@ Three forms of the commands are available:
* `gam <UserTypeEntity> action ... adminaccess` - The user named in `<UserTypeEntty>` is used, adminaccess indicates that labels of type `SHARED` and `ADMIN`can be processed
* `gam <UserTypeEntity> action ...` - The user named in `<UserTypeEntty>` is used, access is limited, onlylabels of type `SHARED` can be processed
## Display Drive Labels
## Display Classification Labels
```
gam [<UserTypeEntity>] info drivelabels <DriveLabelNameEntity>
gam [<UserTypeEntity>] info classificationlabels <ClassificationLabelNameEntity>
[[basic|full] [languagecode <BCP47LanguageCode>]
[formatjson] [adminaccess|asadmin]
```
@@ -115,7 +123,7 @@ By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
```
gam [<UserTypeEntity>] show drivelabels
gam [<UserTypeEntity>] show classificationlabels
[basic|full] [languagecode <BCP47LanguageCode>]
[publishedonly [<Boolean>]] [minimumrole applier|editor|organizer|reader]
[formatjson] [adminaccess|asadmin]
@@ -130,7 +138,7 @@ By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
```
gam [<UserTypeEntity>] print drivelabels [todrive <ToDriveAttribute>*]
gam [<UserTypeEntity>] print classificationlabels [todrive <ToDriveAttribute>*]
[basic|full] [languagecode <BCP47LanguageCode>]
[publishedonly [<Boolean>]] [minimumrole applier|editor|organizer|reader]
[formatjson [quotechar <Character>]] [adminaccess|asadmin]
@@ -150,25 +158,10 @@ When using the `formatjson` option, double quotes are used extensively in the da
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.
## Process File Drive Labels
`<DriveLabelID>`, `<DriveLabelFieldID>` and `<DriveLabelSelectionID>` values are obtained from the commands above.
## Manage Classification Label Permissions
Create a permission for a Classification Label by specifying the label name and the principal.
```
gam <UserTypeEntity> process filedrivelabels <DriveFileEntity>
(addlabel <DriveLabelIDList>)*
(deletelabel <DriveLabelIDList>)*
(addlabelfield <DriveLabelID> <DriveLabelFieldID>
(text <String>)|selection <DriveLabelSelectionIDList>)|
(integer <Number>)|(date <Date>)|(user <EmailAddressList>))*
(deletelabelfield <DriveLabelID> <DriveLabelFieldID>)*
[nodetails]
```
By default, details of the process labels are displayed, use `nodetails` to suppress this display.
## Manage Drive Label Permissions
Create a permission for a Drive Label by specifying the label name and the principal.
```
gam [<UserTypeEntity>] create drivelabelpermission <DriveLabelNameEntity>
gam [<UserTypeEntity>] create classificationlabelpermission <ClassificationLabelNameEntity>
(user <UserItem>) | (group <GroupItem) | (audience <String>)
role applier|editor|organizer|reader
[nodetails|formatjson] [adminaccess|asadmin]
@@ -178,22 +171,22 @@ By default, when a permission is created, GAM outputs details of the permission
* `nodetails` - Suppress the details output.
* `formatjson` - Output the details in JSON format.
Delete a Drive Label permission by specifying the label name and the principal.
Delete a Classification Label permission by specifying the label name and the principal.
```
gam [<UserTypeEntity>] delete drivelabelpermission <DriveLabelNameEntity>
gam [<UserTypeEntity>] delete classificationlabelpermission <ClassificationLabelNameEntity>
(user <UserItem>) | (group <GroupItem) | (audience <String>)
[adminaccess|asadmin]
```
Delete a Drive Label permission by specifying the label permission name.
Delete a Classification Label permission by specifying the label permission name.
```
gam [<UserTypeEntity>] remove drivelabelpermission <DriveLabelPermissionNameEntity>
gam [<UserTypeEntity>] remove classificationlabelpermission <ClassificationLabelPermissionNameEntity>
[adminaccess|asadmin]
```
## Display Drive Label Permissions
Display permissions for a collection of Drive Label permission names.
## Display Classification Label Permissions
Display permissions for a collection of Classification Label permission names.
```
gam [<UserTypeEntity>] show drivelabelpermissions <DriveLabelNameEntity>
gam [<UserTypeEntity>] show classificationlabelpermissions <ClassificationLabelNameEntity>
[formatjson] [adminaccess|asadmin]
```
@@ -201,7 +194,7 @@ By default, Gam displays the information as an indented list of keys and values.
* `formatjson` - Display the fields in JSON format.
```
gam [<UserTypeEntity>] print drivelabelpermissions <DriveLabelNameEntity> [todrive <ToDriveAttribute>*]
gam [<UserTypeEntity>] print classificationlabelpermissions <ClassificationLabelNameEntity> [todrive <ToDriveAttribute>*]
[formatjson [quotechar <Character>]] [adminaccess|asadmin]
```
By default, Gam displays the information as columns of fields; the following option causes the output to be in JSON format,
@@ -213,3 +206,17 @@ When using the `formatjson` option, double quotes are used extensively in the da
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.
## Process Drive File Classification Labels
`<ClassificationLabelID>`, `<ClassificationLabelFieldID>` and `<ClassificationLabelSelectionID>` values are obtained from the commands above.
```
gam <UserTypeEntity> process filedrivelabels <DriveFileEntity>
(addlabel <ClassificationLabelIDList>)*
(deletelabel <ClassificationLabelIDList>)*
(addlabelfield <ClassificationLabelID> <ClassificationLabelFieldID>
(text <String>)|selection <ClassificationLabelSelectionIDList>)|
(integer <Number>)|(date <Date>)|(user <EmailAddressList>))*
(deletelabelfield <ClassificationLabelID> <ClassificationLabelFieldID>)*
[nodetails]
```
By default, details of the process labels are displayed, use `nodetails` to suppress this display.

View File

@@ -3,7 +3,7 @@
Print the current version of Gam with details
```
gam version
GAM 7.00.35 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.0 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
GAM 7.00.35 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.0 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
GAM 7.00.35 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.38 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.0 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/gam7
Version Check:
Current: 5.35.08
Latest: 7.00.35
Latest: 7.00.38
echo $?
1
```
@@ -72,7 +72,7 @@ echo $?
Print the current version number without details
```
gam version simple
7.00.35
7.00.38
```
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 7.00.35 - https://github.com/GAM-team/GAM
GAM 7.00.38 - https://github.com/GAM-team/GAM
GAM Team <google-apps-manager@googlegroups.com>
Python 3.13.0 64-bit final
MacOS Sonoma 14.5 x86_64

View File

@@ -4075,9 +4075,11 @@ gam info policies <CIPolicyNameEntity>
[formatjson]
gam print policies [todrive <ToDriveAttribute>*]
[filter <String>] [nowarnings] [noappnames]
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
[formatjson [quotechar <Character>]]
gam show policies
[filter <String>] [nowarnings] [noappnames]
[group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
[formatjson]
# Inbound SSO

View File

@@ -1,3 +1,21 @@
7.00.38
Fixed logic flaw in `gam print|show policies` where non-matching policies were displayed.
7.00.37
Added options `group <RegularExpression>` and `ou|org|orgunit <RegularExpression>`
to `gam print|show policies` that causes GAM to only display policies whose group email address
or OU path match the `<RegularExpression>`.
Updated `gam get|update|delete contactphotos` to use the People API for domain shared contact photos
as Google has deprecated the Domain Shared Contacts API for these commands. Unfortunately,
the People API fails with `gam update|delete contactphotos`.
7.00.36
Updated `gam print chromeapps` to correct a trap caused by an API change.
7.00.35
Classification labels are now available for Gmail in addition to Drive.

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
"""
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.00.35'
__version__ = '7.00.38'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position
@@ -2693,6 +2693,11 @@ def performActionNumItems(itemCount, itemType, i=0, count=0):
[f'{Act.ToPerform()} {itemCount} {Ent.Choose(itemType, itemCount)}'],
currentCountNL(i, count)))
def performActionModifierNumItems(modifier, itemCount, itemType, i=0, count=0):
writeStdout(formatKeyValueList(Ind.Spaces(),
[f'{Act.ToPerform()} {modifier} {itemCount} {Ent.Choose(itemType, itemCount)}'],
currentCountNL(i, count)))
def actionPerformedNumItems(itemCount, itemType, i=0, count=0):
writeStderr(formatKeyValueList(Ind.Spaces(),
[f'{itemCount} {Ent.Choose(itemType, itemCount)} {Act.Performed()} '],
@@ -20287,137 +20292,6 @@ def doPrintShowDomainContacts():
def doPrintShowGAL():
_printShowContacts(False)
def _processContactPhotos(function):
def _makeFilenameFromPattern():
filename = filenamePattern[:]
if subForContactId:
filename = filename.replace('#contactid#', contactId)
if subForEmail:
for email in fields.get('Emails', []):
if email.get('primary', 'false') == 'true':
filename = filename.replace('#email#', email['value'])
break
else:
filename = filename.replace('#email#', contactId)
return filename
entityType = Ent.DOMAIN
contactsManager = ContactsManager()
entityList, contactQuery, queriedContacts = _getContactEntityList(1, False)
if function in {'ChangePhoto', 'GetPhoto'}:
targetFolder = os.getcwd()
filenamePattern = '#contactid#.jpg'
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg == 'drivedir':
targetFolder = GC.Values[GC.DRIVE_DIR]
elif myarg in {'sourcefolder', 'targetfolder'}:
targetFolder = os.path.expanduser(getString(Cmd.OB_FILE_PATH))
if function == 'GetPhoto' and not os.path.isdir(targetFolder):
os.makedirs(targetFolder)
elif myarg == 'filename':
filenamePattern = getString(Cmd.OB_PHOTO_FILENAME_PATTERN)
else:
unknownArgumentExit()
subForContactId = filenamePattern.find('#contactid#') != -1
subForEmail = filenamePattern.find('#email#') != -1
if not subForContactId and not subForEmail:
filename = filenamePattern
else: #elif function == 'DeletePhoto':
checkForExtraneousArguments()
user, contactsObject = getContactsObject(True)
if queriedContacts:
entityList = queryContacts(contactsObject, contactQuery)
if entityList is None:
return
j = 0
jcount = len(entityList)
entityPerformActionModifierNumItems([entityType, user], Msg.MAXIMUM_OF, jcount, Ent.PHOTO)
if jcount == 0:
setSysExitRC(NO_ENTITIES_FOUND_RC)
return
Ind.Increment()
for contact in entityList:
j += 1
try:
if not queriedContacts:
contactId = normalizeContactId(contact)
contact = callGData(contactsObject, 'GetContact',
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
uri=contactsObject.GetContactFeedUri(contact_list=user, contactId=contactId))
fields = contactsManager.ContactToFields(contact)
else:
contactId = contactsManager.GetContactShortId(contact)
fields = contactsManager.ContactToFields(contact)
if not localContactSelects(contactsManager, contactQuery, fields):
continue
except (GDATA.notFound, GDATA.badRequest) as e:
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId], str(e), j, jcount)
break
except (GDATA.forbidden, GDATA.notImplemented):
entityServiceNotApplicableWarning(entityType, user)
break
except GDATA.serviceNotApplicable:
entityUnknownWarning(entityType, user)
break
try:
if function == 'ChangePhoto':
if subForContactId or subForEmail:
filename = _makeFilenameFromPattern()
filename = os.path.join(targetFolder, filename)
callGData(contactsObject, function,
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
media=filename, contact_entry_or_url=contact,
content_type='image/*', content_length=os.path.getsize(filename), extra_headers={'If-Match': '*'})
entityActionPerformed([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename])
elif function == 'GetPhoto':
if subForContactId or subForEmail:
filename = _makeFilenameFromPattern()
filename = os.path.join(targetFolder, filename)
photo_data = callGData(contactsObject, function,
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
contact_entry_or_url=contact)
if photo_data:
status, e = writeFileReturnError(filename, eval(photo_data), mode='wb') #pylint: disable=eval-used
if status:
entityActionPerformed([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename])
else:
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename], str(e))
else:
entityDoesNotHaveItemWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, ''])
else: #elif function == 'DeletePhoto':
filename = ''
callGData(contactsObject, function,
throwErrors=[GDATA.NOT_FOUND, GDATA.BAD_REQUEST, GDATA.SERVICE_NOT_APPLICABLE, GDATA.FORBIDDEN, GDATA.NOT_IMPLEMENTED],
retryErrors=[GDATA.INTERNAL_SERVER_ERROR],
contact_entry_or_url=contact, extra_headers={'If-Match': '*'})
entityActionPerformed([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename])
except GDATA.notFound as e:
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename], str(e), j, jcount)
except (GDATA.badRequest, OSError, IOError) as e:
entityActionFailedWarning([entityType, user, Ent.CONTACT, contactId, Ent.PHOTO, filename], str(e), j, jcount)
except (GDATA.forbidden, GDATA.notImplemented):
entityServiceNotApplicableWarning(entityType, user)
break
Ind.Decrement()
# gam update contactphotos <ContactEntity>|<ContactSelection>
# [drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>]
def doUpdateDomainContactPhoto():
_processContactPhotos('ChangePhoto')
# gam get contactphotos <ContactEntity>|<ContactSelection>
# [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>]
def doGetDomainContactPhoto():
_processContactPhotos('GetPhoto')
# gam delete contactphotos <ContactEntity>|<ContactSelection>
def doDeleteDomainContactPhoto():
_processContactPhotos('DeletePhoto')
# Prople commands utilities
#
def normalizePeopleResourceName(resourceName):
@@ -22634,9 +22508,16 @@ def _processPeopleContactPhotos(users, function):
filename = filename.replace('#email#', resourceName.split('/')[1])
return filename
entityType = Ent.USER
peopleEntityType = Ent.PEOPLE_CONTACT
sources = [PEOPLE_READ_SOURCES_CHOICE_MAP['contact']]
if users is not None:
entityType = Ent.USER
peopleEntityType = Ent.PEOPLE_CONTACT
sources = [PEOPLE_READ_SOURCES_CHOICE_MAP['contact']]
else:
users = [None]
people = buildGAPIObject(API.PEOPLE_DIRECTORY)
entityType = Ent.DOMAIN
peopleEntityType = Ent.PEOPLE_CONTACT
sources = [PEOPLE_READ_SOURCES_CHOICE_MAP['domaincontact']]
entityList, resourceNameLists, contactQuery, queriedContacts = _getPeopleContactEntityList(entityType, 1)
if function in {'updateContactPhoto', 'getContactPhoto'}:
targetFolder = os.getcwd()
@@ -22665,9 +22546,12 @@ def _processPeopleContactPhotos(users, function):
i += 1
if resourceNameLists:
entityList = resourceNameLists[user]
user, people = buildGAPIServiceObject(API.PEOPLE, user, i, count)
if not people:
continue
if user is not None:
user, people = buildGAPIServiceObject(API.PEOPLE, user, i, count)
if not people:
continue
else:
user = Ent.Singular(entityType)
if contactQuery['contactGroupSelect']:
groupId, _, contactGroupNames = validatePeopleContactGroup(people, contactQuery['contactGroupSelect'],
None, None, entityType, user, i, count)
@@ -22774,6 +22658,20 @@ def getUserPeopleContactPhoto(users):
def deleteUserPeopleContactPhoto(users):
_processPeopleContactPhotos(users, 'deleteContactPhoto')
# gam update contactphotos <PeopleResourceNameEntity>|<PeopleUserContactSelection>
# [drivedir|(sourcefolder <FilePath>)] [filename <FileNamePattern>]
def doUpdateDomainContactPhoto():
_processPeopleContactPhotos(None, 'updateContactPhoto')
# gam get contactphotos <PeopleResourceNameEntity>|<PeopleUserContactSelection>
# [drivedir|(targetfolder <FilePath>)] [filename <FileNamePattern>]
def doGetDomainContactPhoto():
_processPeopleContactPhotos(None, 'getContactPhoto')
# gam delete contactphoto <PeopleResourceNameEntity>|<PeopleUserContactSelection>
def doDeleteDomainContactPhoto():
_processPeopleContactPhotos(None, 'deleteContactPhoto')
# gam <UserTypeEntity> create contactgroup <ContactGroupAttribute>+
# [(csv [todrive <ToDriveAttribute>*] (addcsvdata <FieldName> <String>)*))| returnidonly]
def createUserPeopleContactGroup(users):
@@ -29839,7 +29737,7 @@ def doPrintShowChromeApps():
app['orgUnitPath'] = orgUnitPath
row = flattenJSON(app, simpleLists=['permissions'], delimiter=delimiter)
if not FJQC.formatJSON:
csvPF.WriteRow(row)
csvPF.WriteRowTitles(row)
elif csvPF.CheckRowTitles(row):
csvPF.WriteRowNoFilter({'appId': app['appId'],
'JSON': json.dumps(cleanJSON(app), ensure_ascii=False, sort_keys=True)})
@@ -32648,6 +32546,8 @@ def infoGroups(entityList):
getCloudIdentity = True
cifields = getFieldsFromFieldsList(groupFieldsLists['ci'])
ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS)
else:
cifields = None
i = 0
count = len(entityList)
for group in entityList:
@@ -35131,7 +35031,9 @@ def _getPolicyAppNameFromId(httpObj, app):
if a:
app['applicationName'] = a.group(1)
def _cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci):
def _cleanPolicy(policy, add_warnings, no_appnames,
groupEmailPattern, orgUnitPathPattern,
cd, groups_ci):
# convert any wordlists into spaced strings to reduce output complexity
if policy['setting']['type'] == 'settings/detector.word_list':
policy['setting']['value']['wordList'] = ' '.join(policy['setting']['value']['wordList']['words'])
@@ -35147,8 +35049,17 @@ def _cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci):
_, _, policy['policyQuery']['groupEmail'] = convertGroupCloudIDToEmail(groups_ci, groupId)
# all groups are in the root OU so the orgUnit attribute is useless
policy['policyQuery'].pop('orgUnit', None)
if groupEmailPattern is not None:
return groupEmailPattern.match(policy['policyQuery']['groupEmail'])
if orgUnitPathPattern is not None:
return False
elif orgId := policy['policyQuery'].get('orgUnit'):
policy['policyQuery']['orgUnitPath'] = convertOrgUnitIDtoPath(cd, orgId)
if orgUnitPathPattern is not None:
return orgUnitPathPattern.match(policy['policyQuery']['orgUnitPath'])
if groupEmailPattern is not None:
return False
return True
def _showPolicy(policy, FJQC, i=0, count=0):
if FJQC is not None and FJQC.formatJSON:
@@ -35163,15 +35074,22 @@ def _showPolicy(policy, FJQC, i=0, count=0):
printBlankLine()
Ind.Decrement()
def _showPolicies(policies, FJQC, add_warnings, no_appnames, cd, groups_ci):
def _showPolicies(policies, FJQC, add_warnings, no_appnames,
groupEmailPattern, orgUnitPathPattern,
cd, groups_ci):
count = len(policies)
performActionNumItems(count, Ent.POLICY)
if groupEmailPattern is None and orgUnitPathPattern is None:
performActionNumItems(count, Ent.POLICY)
else:
performActionModifierNumItems(Msg.MAXIMUM_OF, count, Ent.POLICY)
Ind.Increment()
i = 0
for policy in policies:
i += 1
_cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci)
_showPolicy(policy, FJQC, i, count)
if _cleanPolicy(policy, add_warnings, no_appnames,
groupEmailPattern, orgUnitPathPattern,
cd, groups_ci):
_showPolicy(policy, FJQC, i, count)
Ind.Decrement()
# gam info policies <CIPolicyNameEntity>
@@ -35213,13 +35131,16 @@ def doInfoCIPolicies():
ifilter = f"setting.type.matches('{pname}')"
printGettingAllAccountEntities(Ent.POLICY, ifilter)
policies = _filterPolicies(ci, getPageMessage(), ifilter)
_showPolicies(policies, FJQC, add_warnings, no_appnames, cd, groups_ci)
_showPolicies(policies, FJQC, add_warnings, no_appnames,
None, None, cd, groups_ci)
# gam print policies [todrive <ToDriveAttribute>*]
# [filter <String>] [nowarnings] [noappnames]
# [group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
# [formatjson [quotechar <Character>]]
# gam show policies
# [filter <String>] [nowarnings] [noappnames]
# [group <RegularExpression>] [ou|org|orgunit <RegularExpression>]
# [formatjson]
def doPrintShowCIPolicies():
@@ -35241,6 +35162,7 @@ def doPrintShowCIPolicies():
ifilter = None
add_warnings = True
no_appnames = False
groupEmailPattern = orgUnitPathPattern = None
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if csvPF and myarg == 'todrive':
@@ -35250,17 +35172,25 @@ def doPrintShowCIPolicies():
elif myarg == 'nowarnings':
add_warnings = False
elif myarg == 'noappnames':
no_appnames=True
no_appnames = True
elif myarg == 'group':
groupEmailPattern = getREPattern(re.IGNORECASE)
elif myarg in {'ou', 'org', 'orgunit'}:
orgUnitPathPattern = getREPattern(re.IGNORECASE)
else:
FJQC.GetFormatJSONQuoteChar(myarg, True)
printGettingAllAccountEntities(Ent.POLICY, ifilter)
policies = _filterPolicies(ci, getPageMessage(), ifilter)
if not csvPF:
_showPolicies(policies, FJQC, add_warnings, no_appnames, cd, groups_ci)
_showPolicies(policies, FJQC, add_warnings, no_appnames,
groupEmailPattern, orgUnitPathPattern,
cd, groups_ci)
else:
for policy in policies:
_cleanPolicy(policy, add_warnings, no_appnames, cd, groups_ci)
_printPolicy(policy)
if _cleanPolicy(policy, add_warnings, no_appnames,
groupEmailPattern, orgUnitPathPattern,
cd, groups_ci):
_printPolicy(policy)
if csvPF:
csvPF.writeCSVfile('Policies')