Compare commits

..

12 Commits

Author SHA1 Message Date
Jay Lee
861279e614 actions: revert filename generated by heat.exe (MSI) 2024-10-16 16:30:36 -04:00
Jay Lee
b80dd15f4b actions: $PYTHON not $python 2024-10-16 15:51:17 -04:00
Jay Lee
ae95c8fdea generate stable Guids for files in lib.wxs to fix MSI issues 2024-10-16 12:44:51 -07:00
Jay Lee
090b5937ab actions: set Wix GUID to * so Wix (hopefully) uses it's own stable Guid. 2024-10-16 11:33:54 -07:00
Ross Scroggs
2323e130b1 Two minor fixes
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-10-14 14:46:29 -07:00
Jay Lee
6ef127f283 actions: re-order
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
2024-10-14 10:22:17 -04:00
Jay Lee
266f00d3a8 actions: rebuild with sqlite3 libraries 2024-10-14 10:17:23 -04:00
Jay Lee
5c61867e1f actions: add 24.04 Ubuntu build. Fixes #1712
thanks to Ross for suggesting.
2024-10-14 09:03:52 -04:00
Jay Lee
0bbe1cc958 actions: scratch build to see if Windows signing still works
Some checks failed
Build and test GAM / build (Win64, build, 7, VC-WIN64A, windows-2022) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 2, linux-aarch64, [self-hosted linux arm64]) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 4, linux-aarch64, [self-hosted linux arm64], yes) (push) Has been cancelled
Build and test GAM / build (aarch64, build, 6, 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, 3, linux-x86_64, ubuntu-22.04, yes) (push) Has been cancelled
Build and test GAM / build (x86_64, build, 5, darwin64-x86_64, macos-13) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.11) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.12) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 8, ubuntu-24.04, 3.9) (push) Has been cancelled
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.10) (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-10-12 10:02:08 -04:00
Ross Scroggs
d1e02e4695 Updated gam create project to use a default project name of gam-project-a1b2c
Some checks are pending
Build and test GAM / build (Win64, build, 7, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 2, linux-aarch64, [self-hosted linux arm64]) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, [self-hosted linux arm64], yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, 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, 3, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / build (x86_64, test, 8, ubuntu-24.04, 3.9) (push) Waiting to run
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.10) (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
2024-10-11 12:04:35 -07:00
Ross Scroggs
f707c83e1a Update all user calendar commands to disable falling back to client access if service account authorization has never been performed.
Some checks are pending
Build and test GAM / build (Win64, build, 7, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 2, linux-aarch64, [self-hosted linux arm64]) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, [self-hosted linux arm64], yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, 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, 3, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / build (x86_64, test, 8, ubuntu-24.04, 3.9) (push) Waiting to run
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.10) (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
2024-10-10 20:21:28 -07:00
Ross Scroggs
ae67319975 Two updates
Some checks are pending
Build and test GAM / build (Win64, build, 7, VC-WIN64A, windows-2022) (push) Waiting to run
Build and test GAM / build (aarch64, build, 2, linux-aarch64, [self-hosted linux arm64]) (push) Waiting to run
Build and test GAM / build (aarch64, build, 4, linux-aarch64, [self-hosted linux arm64], yes) (push) Waiting to run
Build and test GAM / build (aarch64, build, 6, 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, 3, linux-x86_64, ubuntu-22.04, yes) (push) Waiting to run
Build and test GAM / build (x86_64, build, 5, darwin64-x86_64, macos-13) (push) Waiting to run
Build and test GAM / build (x86_64, test, 10, ubuntu-24.04, 3.11) (push) Waiting to run
Build and test GAM / build (x86_64, test, 11, ubuntu-24.04, 3.12) (push) Waiting to run
Build and test GAM / build (x86_64, test, 8, ubuntu-24.04, 3.9) (push) Waiting to run
Build and test GAM / build (x86_64, test, 9, ubuntu-24.04, 3.10) (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 <UserTypeEntity> claim|transfer ownership` to show `Got N Drive Files/Folders that matched query` messages
as files/folders are being identified for processing.

Added option `<JSONData>` to `gam create|update caalevel`.
2024-10-09 20:34:51 -07:00
12 changed files with 231 additions and 168 deletions

View File

@@ -17,7 +17,7 @@ defaults:
working-directory: src
env:
SCRATCH_COUNTER: 2
SCRATCH_COUNTER: 3
OPENSSL_CONFIG_OPTS: no-fips --api=3.0.0
OPENSSL_INSTALL_PATH: ${{ github.workspace }}/bin/ssl
OPENSSL_SOURCE_PATH: ${{ github.workspace }}/src/openssl
@@ -36,58 +36,63 @@ jobs:
goal: build
arch: x86_64
openssl_archs: linux-x86_64
- os: [self-hosted, linux, arm64]
- os: ubuntu-24.04
jid: 2
goal: build
arch: x86_64
openssl_archs: linux-x86_64
- os: [self-hosted, linux, arm64]
jid: 3
goal: build
arch: aarch64
openssl_archs: linux-aarch64
- os: ubuntu-22.04
jid: 3
jid: 4
goal: build
arch: x86_64
openssl_archs: linux-x86_64
staticx: yes
- os: [self-hosted, linux, arm64]
jid: 4
jid: 5
goal: build
arch: aarch64
openssl_archs: linux-aarch64
staticx: yes
- os: macos-13
jid: 5
jid: 6
goal: build
arch: x86_64
openssl_archs: darwin64-x86_64
- os: macos-14
jid: 6
jid: 7
goal: build
arch: aarch64
openssl_archs: darwin64-arm64
- os: windows-2022
jid: 7
jid: 8
goal: build
arch: Win64
openssl_archs: VC-WIN64A
- os: ubuntu-24.04
goal: test
python: "3.9"
jid: 8
arch: x86_64
- os: ubuntu-24.04
goal: test
python: "3.10"
jid: 9
arch: x86_64
- os: ubuntu-24.04
goal: test
python: "3.11"
python: "3.10"
jid: 10
arch: x86_64
- os: ubuntu-24.04
goal: test
python: "3.12"
python: "3.11"
jid: 11
arch: x86_64
- os: ubuntu-24.04
goal: test
python: "3.12"
jid: 12
arch: x86_64
steps:
@@ -110,7 +115,7 @@ jobs:
with:
path: |
cache.tar.xz
key: gam-${{ matrix.jid }}-20241008
key: gam-${{ matrix.jid }}-20241014
- name: Untar Cache archive
if: matrix.goal == 'build' && steps.cache-python-ssl.outputs.cache-hit == 'true'
@@ -181,7 +186,7 @@ jobs:
run: |
echo "RUNNING: apt update..."
sudo apt-get -qq --yes update
sudo apt-get -qq --yes install swig libpcsclite-dev libxslt1-dev
sudo apt-get -qq --yes install swig libpcsclite-dev libxslt1-dev libsqlite3-dev
- name: MacOS install tools
if: runner.os == 'macOS'
@@ -697,6 +702,7 @@ jobs:
export MSI_FILENAME="${GITHUB_WORKSPACE}/gam-${GAMVERSION}-windows-${GAM_ARCHIVE_ARCH}.msi"
# auto-generate a lib.wxs based on the files PyInstaller created for the lib/ directory
/c/Program\ Files\ \(x86\)/WiX\ Toolset\ v3.14/bin/heat.exe dir "${gampath}/lib" -ke -srd -cg Lib -gg -dr lib -directoryid lib -out lib.wxs
$PYTHON tools/gen-wix-xml-filelist.py lib.wxs
echo "-- begin lib.wxs --"
cat lib.wxs
echo "-- end lib.wxs --"

View File

@@ -1,7 +1,6 @@
# Authorization
- [Introduction](#introduction)
- [Headless computers and Cloud Shells](#headless-computers-and-cloud-shells)
- [Version 5 Update](#version-5-update)
- [API documentation](#api-documentation)
- [Python Regular Expressions](Python-Regular-Expressions)
- [Definitions](#definitions)
@@ -127,25 +126,6 @@ as required by Google for headless computers/cloud shells; this is required as o
* See: https://developers.googleblog.com/2022/02/making-oauth-flows-safer.html
* OAuth out-of-band (oob) flow will be deprecated
## Version 5 Update
GAM version `5.00.00` replaced the deprecated `oauth2client` library with the `google-auth` library.
This change requires a one-time update of the client access file `oauth2.txt`; GAM will continue
to use the old version of `oauth2.txt` until you perform the update. There is a small performance
impact until the update is performed. However, you can't use the updated version of `oauth2.txt`
in prior versions of GAM; if you want to run GAM `5.00.00` and prior versions of GAM,
do not perform the update until you no longer need to run the prior versions of GAM.
If you are running any GAM version `4.85.00` or later, perform the following command
after installing `5.00.00` to perform the update.
```
gam oauth refresh
```
If you are running any GAM version before `4.85.00`, perform the following command
after installing `5.00.00` to perform the update.
```
gam oauth update
```
## API documentation
* https://cloud.google.com/resource-manager/docs/creating-managing-organization#adding_an_organization_administrator
* https://cloud.google.com/service-usage/docs/reference/rest
@@ -213,7 +193,7 @@ perform these steps and then retry the create project command.
## Authorize Service Account Key Uploads
If you try to create a project and get an error saying that Constraint `constraints/iam.disableServiceAccountKeyUpload violated for service account projects/gam-project-xxx`,
If you try to create a project and get an error saying that Constraint `constraints/iam.disableServiceAccountKeyUpload violated for service account projects/gam-project-xxxxx`,
perform these steps and then you should be able to authorize and use your project.
* Login as an existing super admin at console.cloud.google.com
@@ -293,7 +273,7 @@ You can skip these steps if you know that untrusted third-party apps are allowed
### Default values
* `<AppName>` - "GAM"
* `<ProjectID>` - "gam-project-abc-def-jki" where "abc-def-ghi" are randomly generated
* `<ProjectID>` - "gam-project-a1b2c" where "a1b2c" are randomly generated
* `<ProjectName>` - "GAM Project"
* `<ServiceAccountName>` - `<ProjectID>`
* `<ServiceAccountDisplayName>` - `<ProjectName>`

View File

@@ -8,6 +8,7 @@
- [Parameters for Basic Levels](#parameters-for-basic-levels)
- [Create an Access Level](#create-an-access-level)
- [Update an Access Level](#update-an-access-level)
- [Update Access Levels with JSON](#update-access-levels-with-json)
- [Delete an Access Level](#delete-an-access-level)
- [Display all Access Levels](#display-all-access-levels)
- [CAA Region Codes](#caa-region-codes)
@@ -41,6 +42,8 @@ In order for GAM to manage CAA access levels, you need to grant your service acc
## Definitions
```
<JSONData> ::= (json [charset <Charset>] <String>) | (json file <FileName> [charset <Charset>]) |
<QueryCEL> ::= <String>
See: https://cloud.google.com/access-context-manager/docs/custom-access-level-spec
@@ -144,7 +147,7 @@ basic
## Create an Access Level
Create a new access level. CAA supports basic and custom conditions.
```
gam create caalevel <String> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)
gam create caalevel <String> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)|<JSONData>
```
## Example
@@ -166,7 +169,7 @@ gam create caalevel CORP_IPS basic condition ipsubnetworks 1.2.3.0/24,4.5.6.0/24
## Update an Access Level
Updates an existing access level. CAA supports basic and custom conditions.
```
gam update caalevel <CAALevelName> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)
gam update caalevel <CAALevelName> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)|<JSONData>
```
## Examples
@@ -175,6 +178,27 @@ This example adds UK to the allowed regions for CORP_COUNTRIES
gam update caalevel CORP_COUNTRIES basic condition regions US,CA,UK endcondition
```
## Update Access Levels with JSON
Update existing CAA levels via their JSON data; create a CSV file of CAA levels.
```
gam redirect csv ./CAAlevels.csv print caalevels formatjson quotechar "'"
```
Edit the JSON column for the desired CAA level(s) in CAAlevels.csv.
Update the desired CAA level by selecting the row by it's title; repeat for each title to update.
```
gam config csv_input_row_filter "title:text='Example Title'" csv CAAlevels.csv quotechar "'" gam update caalevel "~name" json "~JSON"
```
## Example
Edit CAAlevels.csv and add UK to the allowed regions for CORP_COUNTRIES
```
{"regions": ["US", "CA", "UK"]}
```
Do the update.
```
gam config csv_input_row_filter "title:text='CORP_COUNTRIES'" csv CAAlevels.csv quotechar "'" gam update caalevel "~name" json "~JSON"
```
## Delete an Access Level
Deletes the specified access level.
```

View File

@@ -10,6 +10,39 @@ 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.19
Updated `gam update shareddrive <SharedDriveEntity> ou <OrgUnitItem>` to handle the following error
that occurs when an invalid `<SharedDriveEntity>` is specified.
```
ERROR: 400: invalidArgument - Invalid org membership name 0AJ3b2FTPakToUk9PVAxx.~
```
Updated `gam print browsers` to properly format the time field `deviceIdentifiersHistory.records.0.firstRecordTime`.
### 7.00.18
Updated `gam create project` to use a default project name of `gam-project-a1b2c` (`a1b2c` is a random string of 5 characters)
instead of `gam-project-abc-123-xyz` to avoid the following warning:
```
Project: gam-project-abc-123-xyz, Service Account: gam-project-abc-123-xyz@gam-project-abc-123-xyz.iam.gserviceaccount.com, Extracting public certificate
init.py:12382: UserWarning: Attribute's length must be >= 1 and <= 64, but it was 70
init.py:12383: UserWarning: Attribute's length must be >= 1 and <= 64, but it was 70
Project: gam-project-abc-123-xyz, Service Account: gam-project-abc-123-xyz@gam-project-abc-123-xyz.iam.gserviceaccount.com, Done generating private key and public certificate
```
### 7.00.17
Update all user calendar commands to disable falling back to client access if service account
authorization has never been performed.
### 7.00.16
Updated `gam <UserTypeEntity> claim|transfer ownership` to show `Got N Drive Files/Folders that matched query` messages
as files/folders are being identified for processing.
Added option `<JSONData>` to `gam create|update caalevel`.
### 7.00.15
Added options `timestamp [<Boolean>]` and `timeformat <String>` to `gam <UserTypeEntity> create|update drivefile` that allow

View File

@@ -251,9 +251,9 @@ 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.15 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.19 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.12.7 64-bit final
Python 3.13.0 64-bit final
MacOS Sonoma 14.5 x86_64
Path: /Users/admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -923,9 +923,9 @@ 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.15 - https://github.com/GAM-team/GAM - pythonsource
GAM7 7.00.19 - https://github.com/GAM-team/GAM - pythonsource
GAM Team <google-apps-manager@googlegroups.com>
Python 3.12.7 64-bit final
Python 3.13.0 64-bit final
Windows-10-10.0.17134 AMD64
Path: C:\GAM7
Config File: C:\GAMConfig\gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com

View File

@@ -427,6 +427,15 @@ gam info ou <OrgUnitPath> nousers
gam show teamdrives query "orgUnitId='03ph8a2z21rexy'" fields id,name,orgunit,createdtime
gam print teamdrives query "orgUnitId='03ph8a2z21rexy'" fields id,name,orgunit,createdtime
```
Alternative method; `<OrgUnitPath>` defaults to `/`.
```
gam show oushareddrives
[ou|org|orgunit <OrgUnitPath>]
[formatjson]
gam print oushareddrives [todrive <ToDriveAttribute>*]
[ou|org|orgunit <OrgUnitPath>]
[formatjson [quotechar <Character>]]
```
## Manage Shared Drive access
These commands are used to manage the ACLs on Shared Drives themselves, not the files/folders on the Shared Drives.

View File

@@ -37,7 +37,7 @@
- [Print user domain counts](#print-user-domain-counts)
- [Print domain counts for users in a specific domain and/or selected by a query](#print-domain-counts-for-users-in-a-specific-domain-and-or-selected-by-a-query)
- [Print domain counts for users specified by `<UserTypeEntity>`](#print-domain-counts-for-users-specified-by-usertypeentity)
- [Print user counts by OrgUnit](print-user-counts-by-orgunit)
- [Print user counts by OrgUnit](#print-user-counts-by-orgunit)
- [Print user list](#print-user-list)
- [Display user counts](#display-user-counts)
- [Verify domain membership]($verify-domain-membership)

View File

@@ -3,9 +3,9 @@
Print the current version of Gam with details
```
gam version
GAM 7.00.15 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.19 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.12.7 64-bit final
Python 3.13.0 64-bit final
MacOS Sonoma 14.5 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -15,9 +15,9 @@ 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.15 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.19 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.12.7 64-bit final
Python 3.13.0 64-bit final
MacOS Sonoma 14.5 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -27,9 +27,9 @@ 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.15 - https://github.com/GAM-team/GAM - pyinstaller
GAM 7.00.19 - https://github.com/GAM-team/GAM - pyinstaller
GAM Team <google-apps-manager@googlegroups.com>
Python 3.12.7 64-bit final
Python 3.13.0 64-bit final
MacOS Sonoma 14.5 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com
@@ -37,7 +37,7 @@ Time: 2023-06-02T21:10:00-07:00
Your system time differs from admin.googleapis.com by less than 1 second
OpenSSL 3.1.1 30 May 2023
cryptography 41.0.1
filelock 3.12.7
filelock 3.13.0
google-api-python-client 2.88.0
google-auth-httplib2 0.1.0
google-auth-oauthlib 1.0.0
@@ -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.15
Latest: 7.00.19
echo $?
1
```
@@ -72,7 +72,7 @@ echo $?
Print the current version number without details
```
gam version simple
7.00.15
7.00.19
```
In Linux/MacOS you can do:
```
@@ -82,9 +82,9 @@ echo $VER
Print the current version of Gam and address of this Wiki
```
gam help
GAM 7.00.15 - https://github.com/GAM-team/GAM
GAM 7.00.19 - https://github.com/GAM-team/GAM
GAM Team <google-apps-manager@googlegroups.com>
Python 3.12.7 64-bit final
Python 3.13.0 64-bit final
MacOS Sonoma 14.5 x86_64
Path: /Users/Admin/bin/gam7
Config File: /Users/admin/GAMConfig/gam.cfg, Section: DEFAULT, customer_id: my_customer, domain: domain.com

View File

@@ -2770,8 +2770,8 @@ gam print chromesnvalidity [todrive <ToDriveAttribute>*]
(combiningfunction <CAACombiningFunction>) |
(condition <CAAConditionAttribute>+ endcondition)
gam create caalevel <String> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)
gam update caalevel <CAALevelName> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)
gam create caalevel <String> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)|<JSONData>
gam update caalevel <CAALevelName> [description <String>] (basic <CAABasicAttribute>+)|(custom <QueryCEL>)|<JSONData>
gam delete caalevel <CAALevelName>
gam show caalevels
[formatjson]

View File

@@ -1,3 +1,37 @@
7.00.19
Updated `gam update shareddrive <SharedDriveEntity> ou <OrgUnitItem>` to handle the following error
that occurs when an invalid `<SharedDriveEntity>` is specified.
```
ERROR: 400: invalidArgument - Invalid org membership name 0AJ3b2FTPakToUk9PVAxx.~
```
Updated `gam print browsers` to properly format the time field `deviceIdentifiersHistory.records.0.firstRecordTime`.
7.00.18
Updated `gam create project` to use a default project name of `gam-project-a1b2c` (`a1b2c` is a random string of 5 characters)
instead of `gam-project-abc-123-xyz` to avoid the following warning:
```
Project: gam-project-abc-123-xyz, Service Account: gam-project-abc-123-xyz@gam-project-abc-123-xyz.iam.gserviceaccount.com, Extracting public certificate
init.py:12382: UserWarning: Attribute's length must be >= 1 and <= 64, but it was 70
init.py:12383: UserWarning: Attribute's length must be >= 1 and <= 64, but it was 70
Project: gam-project-abc-123-xyz, Service Account: gam-project-abc-123-xyz@gam-project-abc-123-xyz.iam.gserviceaccount.com, Done generating private key and public certificate
```
7.00.17
Update all user calendar commands to disable falling back to client access if service account
authorization has never been performed. Previously, in this circumstance, the admin's calendars
rather than the user's calendars were processed.
7.00.16
Updated `gam <UserTypeEntity> claim|transfer ownership` to show `Got N Drive Files/Folders that matched query` messages
as files/folders are being identified for processing.
Added option `<JSONData>` to `gam create|update caalevel`.
7.00.15
Added options `timestamp [<Boolean>]` and `timeformat <String>` to `gam <UserTypeEntity> create|update drivefile` that allow

View File

@@ -25,7 +25,7 @@ https://github.com/GAM-team/GAM/wiki
"""
__author__ = 'GAM Team <google-apps-manager@googlegroups.com>'
__version__ = '7.00.15'
__version__ = '7.00.19'
__license__ = 'Apache License 2.0 (http://www.apache.org/licenses/LICENSE-2.0)'
#pylint: disable=wrong-import-position
@@ -6056,7 +6056,7 @@ def checkGroupExists(cd, ci, ciGroupsAPI, group, i=0, count=0):
# Turn the entity into a list of Users/CrOS devices
def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isArchived=None,
groupMemberType=Ent.TYPE_USER, noListConversion=False):
groupMemberType=Ent.TYPE_USER, noListConversion=False, recursive=False, noCLArgs=False):
def _incrEntityDoesNotExist(entityType):
entityError['entityType'] = entityType
entityError[ENTITY_ERROR_DNE] += 1
@@ -6227,32 +6227,33 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
isSuspended = True
cd = buildGAPIObject(API.DIRECTORY)
groups = convertEntityToList(entity)
includeDerivedMembership = recursive = False
includeDerivedMembership = False
domains = []
rolesSet = set()
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg in GROUP_ROLES_MAP:
rolesSet.add(GROUP_ROLES_MAP[myarg])
elif myarg == 'primarydomain':
domains.append(GC.Values[GC.DOMAIN])
elif myarg == 'domains':
domains.extend(getEntityList(Cmd.OB_DOMAIN_NAME_ENTITY))
elif myarg == 'recursive':
recursive = True
includeDerivedMembership = False
elif myarg == 'includederivedmembership':
includeDerivedMembership = True
recursive = False
elif entityType == Cmd.ENTITY_GROUP_USERS_SELECT and myarg in SUSPENDED_ARGUMENTS:
isSuspended = _getIsSuspended(myarg)
elif entityType == Cmd.ENTITY_GROUP_USERS_SELECT and myarg in ARCHIVED_ARGUMENTS:
isArchived = _getIsArchived(myarg)
elif myarg == 'end':
break
else:
Cmd.Backup()
missingArgumentExit('end')
if not noCLArgs:
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg in GROUP_ROLES_MAP:
rolesSet.add(GROUP_ROLES_MAP[myarg])
elif myarg == 'primarydomain':
domains.append(GC.Values[GC.DOMAIN])
elif myarg == 'domains':
domains.extend(getEntityList(Cmd.OB_DOMAIN_NAME_ENTITY))
elif myarg == 'recursive':
recursive = True
includeDerivedMembership = False
elif myarg == 'includederivedmembership':
includeDerivedMembership = True
recursive = False
elif entityType == Cmd.ENTITY_GROUP_USERS_SELECT and myarg in SUSPENDED_ARGUMENTS:
isSuspended = _getIsSuspended(myarg)
elif entityType == Cmd.ENTITY_GROUP_USERS_SELECT and myarg in ARCHIVED_ARGUMENTS:
isArchived = _getIsArchived(myarg)
elif myarg == 'end':
break
else:
Cmd.Backup()
missingArgumentExit('end')
if rolesSet:
memberRoles = ','.join(sorted(rolesSet))
for group in groups:
@@ -6293,19 +6294,19 @@ def getItemsToModify(entityType, entity, memberRoles=None, isSuspended=None, isA
elif entityType in {Cmd.ENTITY_CIGROUP_USERS}:
ci = buildGAPIObject(API.CLOUDIDENTITY_GROUPS)
groups = convertEntityToList(entity)
recursive = False
rolesSet = set()
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg in GROUP_ROLES_MAP:
rolesSet.add(GROUP_ROLES_MAP[myarg])
elif myarg == 'recursive':
recursive = True
elif myarg == 'end':
break
else:
Cmd.Backup()
missingArgumentExit('end')
if not noCLArgs:
while Cmd.ArgumentsRemaining():
myarg = getArgument()
if myarg in GROUP_ROLES_MAP:
rolesSet.add(GROUP_ROLES_MAP[myarg])
elif myarg == 'recursive':
recursive = True
elif myarg == 'end':
break
else:
Cmd.Backup()
missingArgumentExit('end')
if rolesSet:
memberRoles = ','.join(sorted(rolesSet))
for group in groups:
@@ -11428,10 +11429,7 @@ def _getAppInfo(myarg, appInfo):
return True
def _generateProjectSvcAcctId(prefix):
psaId = prefix
for _ in range(3):
psaId += f'-{"".join(random.choice(LOWERNUMERIC_CHARS) for _ in range(3))}'
return psaId
return f'{prefix}-{"".join(random.choice(LOWERNUMERIC_CHARS) for _ in range(5))}'
def _getLoginHintProjectInfo(createCmd):
login_hint = None
@@ -24995,7 +24993,7 @@ def doDeleteBrowsers():
except (GAPI.badRequest, GAPI.resourceNotFound, GAPI.forbidden):
checkEntityAFDNEorAccessErrorExit(None, Ent.CHROME_BROWSER, deviceId)
BROWSER_TIME_OBJECTS = {'lastActivityTime', 'lastPolicyFetchTime', 'lastRegistrationTime', 'lastStatusReportTime', 'safeBrowsingWarningsResetTime'}
BROWSER_TIME_OBJECTS = {'firstRecordTime', 'lastActivityTime', 'lastPolicyFetchTime', 'lastRegistrationTime', 'lastStatusReportTime', 'safeBrowsingWarningsResetTime'}
def _showBrowser(browser, FJQC, i=0, count=0):
if FJQC.formatJSON:
@@ -37028,11 +37026,13 @@ def checkCalendarExists(cal, calId, showMessage=False):
entityActionFailedWarning([Ent.CALENDAR, calId], str(e))
return None
def validateCalendar(calId, i=0, count=0):
def validateCalendar(calId, i=0, count=0, noClientAccess=False):
cal = None
if not calId.endswith('.calendar.google.com'):
calId, cal = buildGAPIServiceObject(API.CALENDAR, calId, i, count, displayError=False)
calId, cal = buildGAPIServiceObject(API.CALENDAR, calId, i, count, displayError=noClientAccess)
if not cal:
if noClientAccess:
return (calId, None)
cal = buildGAPIObject(API.CALENDAR)
try:
callGAPI(cal.calendars(), 'get',
@@ -49759,7 +49759,7 @@ def _validateUserGetCalendarIds(user, i, count, calendarEntity,
calIds = calendarEntity['dict'][user][:]
else:
calIds = calendarEntity['list'][:]
user, cal = validateCalendar(user, i, count)
user, cal = validateCalendar(user, i, count, noClientAccess=True)
if not cal:
return (user, None, None, 0)
if calendarEntity['resourceIds']:
@@ -50178,7 +50178,7 @@ def printShowCalendars(users):
i, count, users = getEntityArgument(users)
for user in users:
i += 1
user, cal = validateCalendar(user, i, count)
user, cal = validateCalendar(user, i, count, noClientAccess=True)
if not cal:
continue
if csvPF:
@@ -50278,7 +50278,7 @@ def printShowCalSettings(users):
i, count, users = getEntityArgument(users)
for user in users:
i += 1
user, cal = validateCalendar(user, i, count)
user, cal = validateCalendar(user, i, count, noClientAccess=True)
if not cal:
continue
try:
@@ -50438,7 +50438,7 @@ def transferCalendars(users):
_getCalendarAttributes(targetListBody, returnOnUnknownArgument=True)
else:
unknownArgumentExit()
targetUser, targetCal = validateCalendar(targetUser)
targetUser, targetCal = validateCalendar(targetUser, noClientAccess=True)
if not targetCal:
return
colorRgbFormat = 'backgroundColor' in targetListBody or 'foregroundColor' in targetListBody
@@ -61687,11 +61687,15 @@ def transferOwnership(users):
_identifyFilesToTransfer(childEntry)
def _identifyChildrenToTransfer(fileEntry, user, i, count):
q = WITH_PARENTS.format(fileEntry['id'])
setGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, user, query=q)
pageMessage = getPageMessageForWhom(clearLastGotMsgLen=False)
try:
children = callGAPIpages(drive.files(), 'list', 'files',
pageMessage=pageMessage, noFinalize=True,
throwReasons=GAPI.DRIVE_USER_THROW_REASONS,
retryReasons=[GAPI.UNKNOWN_ERROR],
orderBy=OBY.orderBy, q=WITH_PARENTS.format(fileEntry['id']),
orderBy=OBY.orderBy, q=q,
fields='nextPageToken,files(id,name,parents,mimeType,ownedByMe,trashed)',
pageSize=GC.Values[GC.DRIVE_MAX_RESULTS])
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
@@ -61972,11 +61976,15 @@ def claimOwnership(users):
_identifyFilesToClaim(childEntry)
def _identifyChildrenToClaim(fileEntry, user, i, count):
q = WITH_PARENTS.format(fileEntry['id'])
setGettingAllEntityItemsForWhom(Ent.DRIVE_FILE_OR_FOLDER, user, query=q)
pageMessage = getPageMessageForWhom(clearLastGotMsgLen=False)
try:
children = callGAPIpages(drive.files(), 'list', 'files',
pageMessage=pageMessage, noFinalize=True,
throwReasons=GAPI.DRIVE_USER_THROW_REASONS,
retryReasons=[GAPI.UNKNOWN_ERROR],
orderBy=OBY.orderBy, q=WITH_PARENTS.format(fileEntry['id']),
orderBy=OBY.orderBy, q=q,
fields='nextPageToken,files(id,name,parents,mimeType,ownedByMe,trashed,owners(emailAddress,permissionId))',
pageSize=GC.Values[GC.DRIVE_MAX_RESULTS])
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
@@ -64277,13 +64285,15 @@ def _moveSharedDriveToOU(orgUnit, orgUnitId, driveId, user, i, count, ci, return
'destinationOrgUnit': f'orgUnits/{orgUnitId[3:]}'}
try:
callGAPI(ci.orgUnits().memberships(), 'move',
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN, GAPI.ABORTED],
throwReasons=GAPI.DRIVE_USER_THROW_REASONS+[GAPI.NOT_FOUND, GAPI.FORBIDDEN,
GAPI.INVALID_ARGUMENT, GAPI.ABORTED],
name=name, body=cibody)
if not returnIdOnly:
Act.Set(Act.MOVE)
entityModifierNewValueActionPerformed([Ent.SHAREDDRIVE, driveId], Act.MODIFIER_TO, f'{Ent.Singular(Ent.ORGANIZATIONAL_UNIT)}: {orgUnit}', i, count)
entityModifierNewValueActionPerformed([Ent.USER, user, Ent.SHAREDDRIVE, driveId], Act.MODIFIER_TO,
f'{Ent.Singular(Ent.ORGANIZATIONAL_UNIT)}: {orgUnit}', i, count)
except (GAPI.notFound, GAPI.forbidden, GAPI.aborted, GAPI.badRequest, GAPI.internalError,
GAPI.noManageTeamDriveAdministratorPrivilege) as e:
GAPI.noManageTeamDriveAdministratorPrivilege, GAPI.invalidArgument) as e:
entityActionFailedWarning([Ent.USER, user, Ent.SHAREDDRIVE_ID, driveId], str(e), i, count)
except (GAPI.serviceNotAvailable, GAPI.authError, GAPI.domainPolicy) as e:
userSvcNotApplicableOrDriveDisabled(user, str(e), i, count)
@@ -74629,10 +74639,12 @@ def CAABuildLevel(body):
body['custom'] = {'expr': {'expression': getString(Cmd.OB_STRING), 'title': 'expr'}}
elif myarg == 'description':
body['description'] = getString(Cmd.OB_STRING, minLen=0)
elif myarg == 'json':
body.update(getJSON(['name']))
else:
unknownArgumentExit()
# gam create caalevel <String> [description <String>] (basic <CAABasicAttribute>+)|(custom <String>)
# gam create caalevel <String> [description <String>] (basic <CAABasicAttribute>+)|(custom <String>)|<JSONData>
def doCreateCAALevel():
caa = buildCAAServiceObject()
ap_name = getAccessPolicy(caa)
@@ -74652,7 +74664,7 @@ def doCreateCAALevel():
except GAPI.permissionDenied:
CAARoleErrorExit(caa)
# gam update caalevel <CAALevelName> [description <String>] (basic <CAABasicAttribute>+)|(custom <String>)
# gam update caalevel <CAALevelName> [description <String>] (basic <CAABasicAttribute>+)|(custom <String>)|<JSONData>
def doUpdateCAALevel():
caa = buildCAAServiceObject()
name = normalizeCAALevelName(caa, getString(Cmd.OB_ACCESS_LEVEL_NAME))

View File

@@ -1,58 +1,23 @@
import os
import sys
import uuid
from lxml import etree
import sys
source_dir = sys.argv[1]
template_file = sys.argv[2]
target_file = sys.argv[3]
# Hacky solution to create a Guid for all files
# so Wix is happy and Guid is stable every time.
# uuid5 is used for the Guid and the input is the
# source filename so the Guid will be the same
# every time as long as the source file name is
# the same.
existing_components = {
'gam.exe': ''' <Component Id="gam_exe" Guid="d046ea24-c9f8-40ca-84db-70b0119933ff">
<File Name="gam.exe" KeyPath="yes" />
<Environment Id="PATH" Name="PATH" Value="[INSTALLFOLDER]" Permanent="yes" Part="last" Action="set" System="yes" />
</Component>
''',
'LICENSE': ''' <Component Id="license" Guid="c76864c5-d005-44d5-bb7c-a27e5923792d">
<File Name="LICENSE" KeyPath="yes" />
</Component>
''',
'gam-setup.bat': ''' <Component Id="gam_setup_bat" Guid="5e6bbacb-d86f-4d80-a10b-89b81ee63fcb">
<File Name="gam-setup.bat" KeyPath="yes" />
</Component>
''',
'GamCommands.txt': ''' <Component Id="GamCommands_txt" Guid="a2dca862-b222-469e-a637-95ea2a1c53e7">
<File Name="GamCommands.txt" KeyPath="yes" />
</Component>
''',
'GamUpdate.txt': ''' <Component Id="GamUpdate_txt" Guid="1b7cdd48-0fff-4943-a219-102fcd14c755">
<File Name="GamUpdate.txt" KeyPath="yes" />
</Component>
''',
'cacerts.pem': ''' <Component Id="cacerts_pem" Guid="61fe2b2d-1646-4bed-b844-193965e97727">
<File Name="cacerts.pem" KeyPath="yes" />
</Component>
''',
}
component_xml = ''
all_files = []
for root, dirs, files in os.walk(source_dir):
for filename in files:
relpath = os.path.relpath(root, source_dir)
if relpath == '.':
all_files.append(filename)
else:
all_files.append(os.path.join(relpath, filename))
all_files.sort()
for filename in all_files:
component_xml += existing_components.get(filename,
f' <Component>\n <File Name="{filename}" KeyPath="yes"/>\n </Component>\n')
with open(template_file, 'r') as f:
template = f.read()
full_xml = template.replace('REPLACE_ME_WITH_FILE_COMPONENTS', component_xml)
with open(target_file, 'w') as f:
f.write(full_xml)
rewrite_file = sys.argv[1]
with open(rewrite_file, 'rb') as f:
input_xml = f.read()
root = etree.fromstring(input_xml)
for elem in root.getiterator():
if 'Guid' in elem.attrib:
source = elem.getchildren()[0].attrib['Source']
stable_uuid = str(uuid.uuid5(uuid.NAMESPACE_URL, source))
elem.attrib['Guid'] = stable_uuid
with open(rewrite_file, 'w') as f:
f.write(etree.tostring(root).decode())