Skip to content

Instantly share code, notes, and snippets.

@dindoliboon
Created April 3, 2018 15:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dindoliboon/6047c842810226a2c8b4ff24c18d91af to your computer and use it in GitHub Desktop.
Save dindoliboon/6047c842810226a2c8b4ff24c18d91af to your computer and use it in GitHub Desktop.
Windows PowerShell library for performing basic requests on Google Apps User resources.
<#
Windows PowerShell library for performing basic requests on Google Apps User resources.
These are general steps and may not follow the Google Dashboard step-by-step.
Requirements:
- .NET Framework 4.5
https://www.microsoft.com/net/download/dotnet-framework-runtime
- .NET Core SDK 2.1.101
https://www.microsoft.com/net/download/windows
- Windows PowerShell 5.1.16299.98
$PSVersionTable.PSVersion
- nuget packages for Google.Apis.Admin.Directory.directory_v1 1.32.2.1170
dotnet new throwaway-app --target-framework-override net471
dotnet add package Newtonsoft.Json --version 10.0.2
dotnet add package System.Net.Http --version 4.3.3
dotnet add package Google.Apis.Auth --version 1.32.2
dotnet add package Google.Apis --version 1.32.2
dotnet add package Google.Apis.Core --version 1.32.2
dotnet add package Google.Apis.Admin.Directory.directory_v1 --version 1.32.2.1170
- Google Admin SDK Directory API access
Create custom administrator roles
https://support.google.com/a/answer/2406043?hl=en
1. Go to Admin roles.
https://admin.google.com/AdminHome#DomainSettings/notab=1&subtab=roles
2. Click CREATE A NEW ROLE.
3 Enter a Name and Description.
4. Under Admin API Privileges, assign Create, Read, and Update for Users.
5. Click Save.
6. Click on Admins tab, click on ASSIGN ADMINS.
7. Enter a user to assign access to, then click CONFIRM ASSIGNMENT.
- Google managed service account with a P12 certificate.
Using OAuth 2.0 for Server to Server Applications
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
1. Go to Service Accounts.
https://console.developers.google.com/permissions/serviceaccounts
2. Either select an existing project or create a new project.
If you are creating a new project, enable Admin SDK API.
3. Click on CREATE SERVICE ACCOUNT.
4. Enter a service account name, check Furnish a new private key, select P12
for key type, and check Enable G Suite Domain-wide Delegation. Remember the
service account ID. Click CREATE.
5. Go to https://admin.google.com, click Security.
Click on Advance settings, Manage API client access.
https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients
6. For Client Name, enter the service account ID (from step 4).
For One or More API Scopes, enter https://www.googleapis.com/auth/admin.directory.user, https://www.googleapis.com/auth/admin.directory.user.readonly
Click Authorize.
#>
New-Module -Name libGoogleAdminDirectoryV1 -ScriptBlock {
<#
.Synopsis
Authenticates PowerShell with Google Apps.
.PARAMETER P12CertificatePath
Complete path to your P12 certificate.
.PARAMETER P12CertificatePassword
P12 certificate password.
.PARAMETER ServiceAccount
Service Account or Client ID.
.PARAMETER ApplicationName
Name of your application.
.PARAMETER AdminUser
Admin with Google Admin SDK Directory API access.
.EXAMPLE
$params = @{
P12CertificatePath = 'C:\myproject-ffffffffffff.p12'
P12CertificatePassword = 'notasecret'
ServiceAccount = '000000000000000000000'
ApplicationName = 'libGoogleAdminDirectoryV1.psm1'
AdminUser = 'myadmin@contoso.com'
}
New-Connection @params
.OUTPUTS
Exceptions are returned to the calling application.
#>
function New-Connection
{
[CmdletBinding()]
Param
(
[ValidateNotNullOrEmpty()]
[String]
$P12CertificatePath,
[ValidateNotNullOrEmpty()]
[String]
$P12CertificatePassword = 'notasecret',
[ValidateNotNullOrEmpty()]
[String]
$ServiceAccount,
[ValidateNotNullOrEmpty()]
[String]
$ApplicationName,
[ValidateNotNullOrEmpty()]
[String]
$AdminUser
)
# If any packages fail to load, check dependencies with $Error[0].Exception.LoaderExceptions
Add-Type -Path "$ENV:USERPROFILE\.nuget\packages\newtonsoft.json\10.0.2\lib\net45\Newtonsoft.Json.dll"
Add-Type -Path "$ENV:USERPROFILE\.nuget\packages\google.apis.core\1.32.2\lib\net45\Google.Apis.Core.dll"
Add-Type -Path "$ENV:USERPROFILE\.nuget\packages\google.apis.auth\1.32.2\lib\net45\Google.Apis.Auth.dll"
Add-Type -Path "$ENV:USERPROFILE\.nuget\packages\google.apis.auth\1.32.2\lib\net45\Google.Apis.Auth.PlatformServices.dll"
Add-Type -Path "$ENV:USERPROFILE\.nuget\packages\google.apis\1.32.2\lib\net45\Google.Apis.dll"
Add-Type -Path "$ENV:USERPROFILE\.nuget\packages\google.apis\1.32.2\lib\net45\Google.Apis.PlatformServices.dll"
Add-Type -Path "$ENV:USERPROFILE\.nuget\packages\google.apis.admin.directory.directory_v1\1.32.2.1170\lib\net45\Google.Apis.Admin.Directory.directory_v1.dll"
# Initializes a new instance of the X509Certificate2 class using a certificate file name, a password used to access the certificate, and a key storage flag.
$keyStorageFlags = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$certificate = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $P12CertificatePath, $P12CertificatePassword, $keyStorageFlags
# Add the minimum scope access to get user information.
# Reference: https://developers.google.com/admin-sdk/directory/v1/reference/users/get#auth
$scopes = New-Object -TypeName System.Collections.Generic.List[string]
$scopes.Add([Google.Apis.Admin.Directory.directory_v1.DirectoryService+Scope]::AdminDirectoryUser)
$scopes.Add([Google.Apis.Admin.Directory.directory_v1.DirectoryService+Scope]::AdminDirectoryUserReadonly)
# Constructs a new service account credential using the given service account id.
# Impersonate an user with Admin SDK Directory API access specified in AdminUser.
# https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth#service-account
$credentialInitializer = New-Object -TypeName Google.Apis.Auth.OAuth2.ServiceAccountCredential+Initializer($ServiceAccount)
$credentialInitializer.Scopes = $scopes
$credentialInitializer.User = $AdminUser
$credential = New-Object -TypeName Google.Apis.Auth.OAuth2.ServiceAccountCredential($credentialInitializer).FromCertificate($certificate)
# Create client service object.
$userServiceInitializer = New-Object -TypeName Google.Apis.Services.BaseClientService+Initializer
$userServiceInitializer.HttpClientInitializer = $credential
$userServiceInitializer.ApplicationName = $ApplicationName
$Script:UserService = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.DirectoryService -ArgumentList $userServiceInitializer
}
<#
.Synopsis
Checks if a user exists in Google Apps.
.PARAMETER UserId
The user's primary email address to look for.
.EXAMPLE
Get-UserExists -UserId 'myuser@contoso.com'
.OUTPUTS
Returns $true if the user exists, otherwise $false.
Exceptions besides user not found are returned to the calling application.
#>
function Get-UserExists
{
[CmdletBinding()]
[OutputType([Boolean])]
Param
(
[ValidateNotNullOrEmpty()]
[String]
$UserId
)
$ret = $false
if ($null -ne $Script:UserService)
{
# Request only the primaryEmail attribute.
$user = $null
$request = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.UsersResource+GetRequest -ArgumentList $Script:UserService, $UserId
$request.Fields = 'primaryEmail'
try
{
$user = $request.Execute()
}
catch [Google.GoogleApiException]
{
# Hide exceptions for user not found.
if ($_ -notlike '*Resource Not Found: userKey*')
{
throw
}
}
if ($null -ne $user -and $user.PrimaryEmail.Length)
{
# We have a valid user.
$ret = $true
}
}
else
{
Write-Error -Message 'New-Connection() must be called first. See Get-Help -Name New-Connection -Full'
}
return $ret
}
<#
.Synopsis
Updates name or password for the user.
.PARAMETER UserId
The user's primary email address of the user to update.
.PARAMETER FirstName
Given name of the user.
.PARAMETER LastName
Surname of the user.
.PARAMETER Password
Password of the user.
.EXAMPLE
# Update the name of the user.
Set-User -UserId 'myuser@contoso.com' -FirstName 'John' -LastName 'Doe'
.EXAMPLE
# Update the password of the user.
Set-User -UserId 'myuser@contoso.com' -Password 'SuperSecur3!'
.OUTPUTS
Returns User Resource JSON string if successful.
https://developers.google.com/admin-sdk/directory/v1/reference/users
Exceptions are returned to the calling application.
#>
function Set-User
{
[CmdletBinding()]
[OutputType([String])]
Param
(
[ValidateNotNullOrEmpty()]
[String]
$UserId,
[String]
$FirstName,
[String]
$LastName,
[String]
$Password
)
$ret = ''
if ($null -ne $Script:UserService)
{
# Create user template.
$gUser = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.Data.User
# Update specific properties if provided.
if ($FirstName.Length -gt 0 -or $FirstName.Length -gt 0)
{
$gUser.Name = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.Data.UserName
$gUser.Name.GivenName = $FirstName
$gUser.Name.FamilyName = $LastName
}
if ($Password.Length -gt 0)
{
# Get the MD5 hash value of the user password.
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([Text.Encoding]::UTF8.GetBytes($Password))) -replace '-', ''
$gUser.Password = $hash
$gUser.HashFunction = 'MD5'
}
# Perform update, requesting primaryEmail and the name.
$request = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.UsersResource+PatchRequest -ArgumentList $Script:UserService, $gUser, $UserId
$request.Fields = 'primaryEmail,name/givenName,name/familyName'
$user = $request.Execute()
$ret = ConvertTo-Json -InputObject $user -Compress
}
else
{
Write-Error -Message 'New-Connection() must be called first. See Get-Help -Name New-Connection -Full'
}
return $ret
}
<#
.Synopsis
Get selected fields of a user.
.PARAMETER UserId
The user's primary email address of the user to look for.
.PARAMETER Field
Comma-separated list of attributes to return.
See Users resource for available attributes.
https://developers.google.com/admin-sdk/directory/v1/reference/users
.EXAMPLE
Get-User -UserId 'myuser@contoso.com' -Field 'organizations,posixAccounts/username,primaryEmail'
.OUTPUTS
Returns User Resource JSON string if successful.
https://developers.google.com/admin-sdk/directory/v1/reference/users
Exceptions are returned to the calling application.
#>
function Get-User
{
[CmdletBinding()]
[OutputType([String])]
Param
(
[ValidateNotNullOrEmpty()]
[String]
$UserId,
[ValidateNotNullOrEmpty()]
[String]
$Field
)
$ret = ''
if ($null -ne $Script:UserService)
{
# Get requested fields.
$request = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.UsersResource+GetRequest -ArgumentList $Script:UserService, $UserId
$request.Fields = $Field
$user = $request.Execute()
$ret = ConvertTo-Json -InputObject $user -Compress
}
else
{
Write-Error -Message 'New-Connection() must be called first. See Get-Help -Name New-Connection -Full'
}
return $ret
}
<#
.Synopsis
Create a new user.
.PARAMETER UserId
The user's primary email address. The primaryEmail must be unique and cannot be an alias of another user.
.PARAMETER Password
Password of the user.
.PARAMETER FirstName
Given name of the user.
.PARAMETER LastName
Surname of the user.
.PARAMETER OrgUnitPath
The full path of the parent organization associated with the user. If the parent organization is the top-level, it is represented as a forward slash (/).
.EXAMPLE
New-User -UserId 'myuser@contoso.com' -Password 'SuperSecur3!' -FirstName 'John' -LastName 'Doe' -OrgUnitPath '/'
.OUTPUTS
Returns User Resource JSON string if successful.
https://developers.google.com/admin-sdk/directory/v1/reference/users
Exceptions are returned to the calling application.
#>
function New-User
{
[CmdletBinding()]
[OutputType([String])]
Param
(
[ValidateNotNullOrEmpty()]
[String]
$UserId,
[ValidateNotNullOrEmpty()]
[String]
$Password,
[ValidateNotNullOrEmpty()]
[String]
$FirstName,
[ValidateNotNullOrEmpty()]
[String]
$LastName,
[ValidateNotNullOrEmpty()]
[String]
$OrgUnitPath
)
$ret = ''
if ($null -ne $Script:UserService)
{
# Get the MD5 hash value of the user password.
$md5 = New-Object -TypeName System.Security.Cryptography.MD5CryptoServiceProvider
$hash = [System.BitConverter]::ToString($md5.ComputeHash([Text.Encoding]::UTF8.GetBytes($Password))) -replace '-', ''
# Create user template.
$gUser = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.Data.User
$gUser.PrimaryEmail = $UserId
$gUser.Name = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.Data.UserName
$gUser.Name.GivenName = $FirstName
$gUser.Name.FamilyName = $LastName
$gUser.Password = $hash
$gUser.HashFunction = 'MD5'
$gUser.OrgUnitPath = $OrgUnitPath
# Perform update, requesting primaryEmail.
$request = New-Object -TypeName Google.Apis.Admin.Directory.directory_v1.UsersResource+InsertRequest -ArgumentList $Script:UserService, $gUser
$request.Fields = 'primaryEmail'
$user = $request.Execute()
$ret = ConvertTo-Json -InputObject $user -Compress
}
else
{
Write-Error -Message 'New-Connection() must be called first. See Get-Help -Name New-Connection -Full'
}
return $ret
}
Export-ModuleMember -Function 'New-Connection', 'Get-UserExists', 'Set-User', 'Get-User', 'New-User'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment