Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Google ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΈΠ· PowerShell Ρ‡Π΅Ρ€Π΅Π· API

ΠŸΡ€ΠΈΠ²Π΅Ρ‚!

Π’ этой ΡΡ‚Π°Ρ‚ΡŒΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ описана рСализация взаимодСйствия PowerShell с Google API для провСдСния манипуляций с ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡΠΌΠΈ G Suite.

Π’ ΠΎΡ€Π³Π°Π½ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ нСсколько Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΡ… ΠΈ ΠΎΠ±Π»Π°Ρ‡Π½Ρ‹Ρ… сСрвисов. По большСй части авторизация Π² Π½ΠΈΡ… сводится ΠΊ Google ΠΈΠ»ΠΈ Active Directory, ΠΌΠ΅ΠΆΠ΄Ρƒ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ Ρ€Π΅ΠΏΠ»ΠΈΠΊΡƒ, соотвСтствСнно, ΠΏΡ€ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π΅ Π½ΠΎΠ²ΠΎΠ³ΠΎ сотрудника Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ/Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Π² этих Π΄Π²ΡƒΡ… систСмах. Для Π°Π²Ρ‚ΠΎΠΌΠ°Ρ‚ΠΈΠ·Π°Ρ†ΠΈΠΈ процСсса ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ скрипт, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ собираСт ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ ΠΈ отправляСт Π² ΠΎΠ±Π° сСрвиса.

Авторизация

Боставляя трСбования, ΠΌΡ‹ Ρ€Π΅ΡˆΠΈΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Ρ… людСй-администраторов, это ΡƒΠΏΡ€ΠΎΡ‰Π°Π΅Ρ‚ Ρ€Π°Π·Π±ΠΎΡ€ дСйствий ΠΏΡ€ΠΈ случайных ΠΈΠ»ΠΈ Π½Π°ΠΌΠ΅Ρ€Π΅Π½Π½Ρ‹Ρ… массивных измСнСниях.

Для Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΈ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ Google API ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ» OAuth 2.0. Π‘Ρ†Π΅Π½Π°Ρ€ΠΈΠΈ использования ΠΈ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠ΅ описаниС ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ‚ΡƒΡ‚: Using OAuth 2.0 to Access Google APIs.

Π― Π²Ρ‹Π±Ρ€Π°Π» сцСнарий, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΏΡ€ΠΈ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ Π² desktop-прилоТСниях. Π’Π°ΠΊ ΠΆΠ΅ Π΅ΡΡ‚ΡŒ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ сСрвисный Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚, Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΡŽΡ‰ΠΈΠΉ Π»ΠΈΡˆΠ½ΠΈΡ… Π΄Π²ΠΈΠΆΠ΅Π½ΠΈΠΉ ΠΎΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.

ΠšΠ°Ρ€Ρ‚ΠΈΠ½ΠΊΠ° Π½ΠΈΠΆΠ΅ – это схСматичноС описаниС Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ сцСнария со странички Google.

Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Google ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ ΠΈΠ· PowerShell Ρ‡Π΅Ρ€Π΅Π· API

  1. Π‘Π½Π°Ρ‡Π°Π»Π° ΠΌΡ‹ отправляСм ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π½Π° страницу Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ Π² Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ Google, указывая GET ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ:
    • ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ прилоТСния
    • области, ΠΊ ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌ доступ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ
    • адрСс, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ послС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Ρ‹
    • способ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ Ρ‚ΠΎΠΊΠ΅Π½
    • ΠΊΠΎΠ΄ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ
    • Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡ΠΈ ΠΊΠΎΠ΄Π° ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ

  2. ПослС Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΈΡ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ, ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ Π½Π° ΡƒΠΊΠ°Π·Π°Π½Π½ΡƒΡŽ Π² ΠΏΠ΅Ρ€Π²ΠΎΠΌ запросС страницу, с ошибкой ΠΈΠ»ΠΈ ΠΊΠΎΠ΄ΠΎΠΌ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ, ΠΏΠ΅Ρ€Π΅Π΄Π°Π½Π½Ρ‹ΠΌΠΈ GET ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π°ΠΌΠΈ
  3. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ (скрипту) Π½ΡƒΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ эти ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹ ΠΈ, Π² случаС получСния ΠΊΠΎΠ΄Π°, Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ запрос Π½Π° ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Ρ‚ΠΎΠΊΠ΅Π½ΠΎΠ²
  4. ΠŸΡ€ΠΈ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎΠΌ запросС Google API Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚:
    • Access Ρ‚ΠΎΠΊΠ΅Π½, с ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ Π΄Π΅Π»Π°Ρ‚ΡŒ запросы
    • CΡ€ΠΎΠΊ дСйствия этого Ρ‚ΠΎΠΊΠ΅Π½Π°
    • Refresh Ρ‚ΠΎΠΊΠ΅Π½, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΉ для обновлСния Access Ρ‚ΠΎΠΊΠ΅Π½Π°.

Π‘Π½Π°Ρ‡Π°Π»Π° Π½ΡƒΠΆΠ½ΠΎ ΡΡ…ΠΎΠ΄ΠΈΡ‚ΡŒ Π² консоль Google API: Credentials β€” Google API Console, Π²Ρ‹Π±Ρ€Π°Ρ‚ΡŒ Π½ΡƒΠΆΠ½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ Credentials ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ OAuth ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°. Π’Π°ΠΌ ΠΆΠ΅ (ΠΈΠ»ΠΈ ΠΏΠΎΠ·ΠΆΠ΅, Π² свойствах созданного ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Π°) Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ адрСса, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΎ ΠΏΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅. Π’ нашСм случаС это Π±ΡƒΠ΄Π΅Ρ‚ нСсколько записСй localhost с Ρ€Π°Π·Π½Ρ‹ΠΌΠΈ ΠΏΠΎΡ€Ρ‚Π°ΠΌΠΈ (см. дальшС).

Π§Ρ‚ΠΎΠ±Ρ‹ Π±Ρ‹Π»ΠΎ ΡƒΠ΄ΠΎΠ±Π½Π΅Π΅ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌ скрипта, ΠΌΠΎΠΆΠ½ΠΎ вывСсти ΠΏΠ΅Ρ€Π²Ρ‹Π΅ шаги Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π²Π΅Ρ€Π½Π΅Ρ‚ Access ΠΈ refresh Ρ‚ΠΎΠΊΠ΅Π½Ρ‹ для прилоТСния:

$client_secret = 'Our Client Secret'
$client_id = 'Our Client ID'
function Get-GoogleAuthToken {
  if (-not [System.Net.HttpListener]::IsSupported) {
    "HttpListener is not supported."
    exit 1
  }
  $codeverifier = -join ((65..90) + (97..122) + (48..57) + 45 + 46 + 95 + 126 |Get-Random -Count 60| % {[char]$_})
  $hasher = new-object System.Security.Cryptography.SHA256Managed
  $hashByteArray = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($codeverifier))
  $base64 = ((([System.Convert]::ToBase64String($hashByteArray)).replace('=','')).replace('+','-')).replace('/','_')
  $ports = @(10600,15084,39700,42847,65387,32079)
  $port = $ports[(get-random -Minimum 0 -maximum 5)]
  Write-Host "Start browser..."
  Start-Process "https://accounts.google.com/o/oauth2/v2/auth?code_challenge_method=S256&code_challenge=$base64&access_type=offline&client_id=$client_id&redirect_uri=http://localhost:$port&response_type=code&scope=https://www.googleapis.com/auth/admin.directory.user https://www.googleapis.com/auth/admin.directory.group"
  $listener = New-Object System.Net.HttpListener
  $listener.Prefixes.Add("http://localhost:"+$port+'/')
  try {$listener.Start()} catch {
    "Unable to start listener."
    exit 1
  }
  while (($code -eq $null)) {
    $context = $listener.GetContext()
    Write-Host "Connection accepted" -f 'mag'
    $url = $context.Request.RawUrl
    $code = $url.split('?')[1].split('=')[1].split('&')[0]
    if ($url.split('?')[1].split('=')[0] -eq 'error') {
      Write-Host "Error!"$code -f 'red'
      $buffer = [System.Text.Encoding]::UTF8.GetBytes("Error!"+$code)
      $context.Response.ContentLength64 = $buffer.Length
      $context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
      $context.Response.OutputStream.Close()
      $listener.Stop()
      exit 1
    }
    $buffer = [System.Text.Encoding]::UTF8.GetBytes("Now you can close this browser tab.")
    $context.Response.ContentLength64 = $buffer.Length
    $context.Response.OutputStream.Write($buffer, 0, $buffer.Length)
    $context.Response.OutputStream.Close()
    $listener.Stop()
  }
  Return Invoke-RestMethod -Method Post -Uri "https://www.googleapis.com/oauth2/v4/token" -Body @{
    code = $code
    client_id = $client_id
    client_secret = $client_secret
    redirect_uri = 'http://localhost:'+$port
    grant_type = 'authorization_code'
    code_verifier   = $codeverifier
  }
  $code = $null

ΠœΡ‹ Π·Π°Π΄Π°Π΅ΠΌ Client ID ΠΈ Client Secret, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Π΅ Π² свойствах ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° OAuth, ΠΈ code verifier – это строка Π΄Π»ΠΈΠ½ΠΎΠΉ ΠΎΡ‚ 43 Π΄ΠΎ 128 символов, которая Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ сгСнСрирована случайным ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ ΠΈΠ· Π½Π΅Π·Π°Ρ€Π΅Π·Π΅Ρ€Π²ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Ρ… символов: [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~".

Π”Π°Π»Π΅Π΅ этот ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ. Он ΠΈΡΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ ΡƒΡΠ·Π²ΠΈΠΌΠΎΡΡ‚ΡŒ, ΠΏΡ€ΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ Π·Π»ΠΎΡƒΠΌΡ‹ΡˆΠ»Π΅Π½Π½ΠΈΠΊ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠ΅Ρ€Π΅Ρ…Π²Π°Ρ‚ΠΈΡ‚ΡŒ ΠΎΡ‚Π²Π΅Ρ‚, Π²Π΅Ρ€Π½ΡƒΠ²ΡˆΠΈΠΉΡΡ Ρ€Π΅Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΠΌ послС Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.
ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ code verifier Π² Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΌ запросС ΠΌΠΎΠΆΠ½ΠΎ Π² ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΎΠΌ Π²ΠΈΠ΄Π΅ (Ρ‡Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅Ρ‚ Π΅Π³ΠΎ бСссмыслСнным – это ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для систСм, Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°ΡŽΡ‰ΠΈΡ… SHA256), ΠΈΠ»ΠΈ создав Ρ…Π΅Ρˆ ΠΏΠΎ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡƒ SHA256, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π² BASE64Url (отличаСтся ΠΎΡ‚ Base64 двумя символами Ρ‚Π°Π±Π»ΠΈΡ†Ρ‹) ΠΈ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ символ окончания строки: =.

Π”Π°Π»Π΅Π΅ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ Π½Π°Ρ‡Π°Ρ‚ΡŒ ΠΏΡ€ΠΎΡΠ»ΡƒΡˆΠΈΠ²Π°Ρ‚ΡŒ http Π½Π° локальной машинС, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΎΡ‚Π²Π΅Ρ‚ послС Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ вСрнСтся Ρ€Π΅Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΠΌ.

АдминистративныС Π·Π°Π΄Π°Ρ‡ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ Π½Π° ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎΠΌ сСрвСрС, ΠΌΡ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ Π²Π΅Ρ€ΠΎΡΡ‚Π½ΠΎΡΡ‚ΡŒ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ нСсколько администраторов ΠΎΠ΄Π½ΠΎΠ²Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎ запустят скрипт, поэтому ΠΎΠ½ Π½Π°ΡƒΠ³Π°Π΄ Π²Ρ‹Π±Π΅Ρ€Π΅Ρ‚ ΠΏΠΎΡ€Ρ‚ для Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, Π½ΠΎ я ΡƒΠΊΠ°Π·Π°Π» Π·Π°Ρ€Π°Π½Π΅Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ ΠΏΠΎΡ€Ρ‚Ρ‹, Ρ‚.ΠΊ. ΠΈΡ… Π½ΡƒΠΆΠ½ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠ°ΠΊ Π΄ΠΎΠ²Π΅Ρ€Π΅Π½Π½Ρ‹Π΅ Π² консоли API.

access_type=offline ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠ±Π½ΠΎΠ²Π»ΡΡ‚ΡŒ ΠΈΡΡ‚Π΅ΠΊΡˆΠΈΠΉ Ρ‚ΠΎΠΊΠ΅Π½ ΡΠ°ΠΌΠΎΡΡ‚ΠΎΡΡ‚Π΅Π»ΡŒΠ½ΠΎ Π±Π΅Π· взаимодСйствия ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ с Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ΠΎΠΌ,
response_type=code Π·Π°Π΄Π°Π΅Ρ‚ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ Ρ‚ΠΎΠ³ΠΎ, ΠΊΠ°ΠΊ вСрнСтся ΠΊΠΎΠ΄ (отсылка ΠΊ старому способу Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ, ΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ копипастил ΠΊΠΎΠ΄ ΠΈΠ· Π±Ρ€Π°ΡƒΠ·Π΅Ρ€Π° Π² скрипт),
scope ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ области ΠΈ Ρ‚ΠΈΠΏ доступа. Они Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ€Π°Π·Π΄Π΅Π»ΡΡ‚ΡŒΡΡ ΠΏΡ€ΠΎΠ±Π΅Π»Π°ΠΌΠΈ ΠΈΠ»ΠΈ %20 (Π² соотвСтствии с URL Encoding). Бписок областСй доступа с Ρ‚ΠΈΠΏΠ°ΠΌΠΈ ΠΌΠΎΠΆΠ½ΠΎ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ Ρ‚ΡƒΡ‚: OAuth 2.0 Scopes for Google APIs.

ПослС получСния ΠΊΠΎΠ΄Π° Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ, ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π²Π΅Ρ€Π½Π΅Ρ‚ Π² Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ сообщСниС ΠΎ Π·Π°ΠΊΡ€Ρ‹Ρ‚ΠΈΠΈ, ΠΏΡ€Π΅ΠΊΡ€Π°Ρ‚ΠΈΡ‚ ΡΠ»ΡƒΡˆΠ°Ρ‚ΡŒ ΠΏΠΎΡ€Ρ‚ ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ POST запрос для получСния Ρ‚ΠΎΠΊΠ΅Π½Π°. ΠœΡ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ Π² Π½Π΅ΠΌ Π·Π°Π΄Π°Π½Π½Ρ‹Π΅ Ρ€Π°Π½Π΅Π΅ id ΠΈ secret ΠΈΠ· API консоли, адрСс, Π½Π° ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π½Π°ΠΏΡ€Π°Π²Π»Π΅Π½ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΈ grant_type Π² соотвСтствии спСцификации ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»Π°.

Π’ ΠΎΡ‚Π²Π΅Ρ‚ ΠΌΡ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠΌ Access Ρ‚ΠΎΠΊΠ΅Π½, Π΅Π³ΠΎ врСмя дСйствия Π² сСкундах ΠΈ Refresh Ρ‚ΠΎΠΊΠ΅Π½, с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Access Ρ‚ΠΎΠΊΠ΅Π½.

ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Ρ‚ΠΎΠΊΠ΅Π½Ρ‹ Π² бСзопасном мСстС с Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌ сроком хранСния, поэтому, ΠΏΠΎΠΊΠ° ΠΌΡ‹ Π½Π΅ ΠΎΡ‚Π·ΠΎΠ²Π΅ΠΌ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹ΠΉ доступ, ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ Π½Π΅ вСрнСтся refresh Ρ‚ΠΎΠΊΠ΅Π½. Π’ ΠΊΠΎΠ½Ρ†Π΅ я Π΄ΠΎΠ±Π°Π²ΠΈΠ» запрос Π½Π° ΠΎΡ‚Π·Ρ‹Π² Ρ‚ΠΎΠΊΠ΅Π½Π°, Ссли ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π±Ρ‹Π»ΠΎ Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½ΠΎ Π½Π΅ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ ΠΈ refresh Ρ‚ΠΎΠΊΠ΅Π½ Π½Π΅ вСрнулся, ΠΎΠ½ΠΎ Π½Π°Ρ‡Π½Π΅Ρ‚ ΠΏΡ€ΠΎΡ†Π΅Π΄ΡƒΡ€Ρƒ Π·Π°Π½ΠΎΠ²ΠΎ (ΠΌΡ‹ посчитали нСбСзопасным Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Ρ‚ΠΎΠΊΠ΅Π½Ρ‹ локально Π½Π° Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅, Π° ΡƒΡΠ»ΠΎΠΆΠ½ΡΡ‚ΡŒ ΠΊΡ€ΠΈΠΏΡ‚ΠΎΠ³Ρ€Π°Ρ„ΠΈΠ΅ΠΉ ΠΈΠ»ΠΈ часто ΠΎΡ‚ΠΊΡ€Ρ‹Π²Π°Ρ‚ΡŒ Π±Ρ€Π°ΡƒΠ·Π΅Ρ€ Π½Π΅ хочСтся).

do {
  $token_result = Get-GoogleAuthToken
  $token = $token_result.access_token
  if ($token_result.refresh_token -eq $null) {
    Write-Host ("Session is not destroyed. Revoking token...")
    Invoke-WebRequest -Uri ("https://accounts.google.com/o/oauth2/revoke?token="+$token)
  }
} while ($token_result.refresh_token -eq $null)
$refresh_token = $token_result.refresh_token
$minute = ([int]("{0:mm}" -f ([timespan]::fromseconds($token_result.expires_in))))+((Get-date).Minute)-2
if ($minute -lt 0) {$minute += 60}
elseif ($minute -gt 59) {$minute -=60}
$token_expire = @{
  hour = ([int]("{0:hh}" -f ([timespan]::fromseconds($token_result.expires_in))))+((Get-date).Hour)
  minute = $minute
}

Как Π²Ρ‹ ΡƒΠΆΠ΅ Π·Π°ΠΌΠ΅Ρ‚ΠΈΠ»ΠΈ, ΠΏΡ€ΠΈ ΠΎΡ‚Π·Ρ‹Π²Π΅ Ρ‚ΠΎΠΊΠ΅Π½Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Invoke-WebRequest. Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠΈ ΠΎΡ‚ Invoke-RestMethod, ΠΎΠ½ Π½Π΅ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ Π² ΡƒΠ΄ΠΎΠ±Π½ΠΎΠΌ для использования Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ ΠΈ ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚ статус запроса.

Π”Π°Π»Π΅Π΅ скрипт ΠΏΡ€ΠΎΡΠΈΡ‚ΡŒ ввСсти имя ΠΈ Ρ„Π°ΠΌΠΈΠ»ΠΈΡŽ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ, гСнСрируя Π»ΠΎΠ³ΠΈΠ½ + email.

Запросы

Π‘Π»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌΠΈ Π±ΡƒΠ΄ΡƒΡ‚ запросы – Π² ΠΏΠ΅Ρ€Π²ΡƒΡŽ ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ Π½ΡƒΠΆΠ½ΠΎ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ сущСствуСт Π»ΠΈ ΡƒΠΆΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ с Ρ‚Π°ΠΊΠΈΠΌ Π»ΠΎΠ³ΠΈΠ½ΠΎΠΌ для получСния Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ΠΎ Ρ„ΠΎΡ€ΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠΈ Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΈΠ»ΠΈ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ Ρ‚Π΅ΠΊΡƒΡ‰Π΅Π³ΠΎ.

Π― Ρ€Π΅ΡˆΠΈΠ» Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ всС запросы Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ ΠΎΠ΄Π½ΠΎΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ с Π²Ρ‹Π±ΠΎΡ€ΠΊΠΎΠΉ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ switch:

function GoogleQuery {
  param (
    $type,
    $query
  )
  switch ($type) {
    "SearchAccount" {
      Return Invoke-RestMethod -Method Get -Uri "https://www.googleapis.com/admin/directory/v1/users" -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body @{
        domain = 'rocketguys.com'
        query  = "email:$query"
      }
    }
    "UpdateAccount" {
      $body = @{
        name  = @{
          givenName = $query['givenName']
          familyName = $query['familyName']
        }
        suspended = 'false'
        password = $query['password']
        changePasswordAtNextLogin = 'true'
        phones = @(@{
          primary = 'true'
          value = $query['phone']
          type = "mobile"
        })
        orgUnitPath = $query['orgunit']
      }
      Return Invoke-RestMethod -Method Put -Uri ("https://www.googleapis.com/admin/directory/v1/users/"+$query['email']) -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body (ConvertTo-Json $body) -ContentType 'application/json; charset=utf-8'
    }
    
    "CreateAccount" {
      $body = @{
        primaryEmail = $query['email']
        name  = @{
          givenName = $query['givenName']
          familyName = $query['familyName']
        }
        suspended = 'false'
        password = $query['password']
        changePasswordAtNextLogin = 'true'
        phones = @(@{
          primary = 'true'
          value = $query['phone']
          type = "mobile"
        })
        orgUnitPath = $query['orgunit']
      }
      Return Invoke-RestMethod -Method Post -Uri "https://www.googleapis.com/admin/directory/v1/users" -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body (ConvertTo-Json $body) -ContentType 'application/json; charset=utf-8'
    }
    "AddMember" {
      $body = @{
        userKey = $query['email']
      }
      $ifrequest = Invoke-RestMethod -Method Get -Uri "https://www.googleapis.com/admin/directory/v1/groups" -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body $body
      $array = @()
      foreach ($group in $ifrequest.groups) {$array += $group.email}
      if ($array -notcontains $query['groupkey']) {
        $body = @{
          email = $query['email']
          role = "MEMBER"
        }
        Return Invoke-RestMethod -Method Post -Uri ("https://www.googleapis.com/admin/directory/v1/groups/"+$query['groupkey']+"/members") -Headers @{Authorization = "Bearer "+(Get-GoogleToken)} -Body (ConvertTo-Json $body) -ContentType 'application/json; charset=utf-8'
      } else {
        Return ($query['email']+" now is a member of "+$query['groupkey'])
      }
    }
  }
}

Π’ ΠΊΠ°ΠΆΠ΄ΠΎΠΌ запросС Π½ΡƒΠΆΠ½ΠΎ ΠΎΡ‚ΠΏΡ€Π°Π²Π»ΡΡ‚ΡŒ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Authorization, содСрТащий Ρ‚ΠΈΠΏ Ρ‚ΠΎΠΊΠ΅Π½Π° ΠΈ сам Access Ρ‚ΠΎΠΊΠ΅Π½. На Ρ‚Π΅ΠΊΡƒΡ‰ΠΈΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ‚ Ρ‚ΠΈΠΏ Ρ‚ΠΎΠΊΠ΅Π½Π° всСгда Bearer. Π’.ΠΊ. Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ Ρ‡Ρ‚ΠΎ Ρ‚ΠΎΠΊΠ΅Π½ Π½Π΅ просрочСн ΠΈ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π΅Π³ΠΎ ΠΏΠΎ истСчСнии часа с ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° Π²Ρ‹Π΄Π°Ρ‡ΠΈ, я ΡƒΠΊΠ°Π·Π°Π» запрос Π½Π° Π΄Ρ€ΡƒΠ³ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ, которая Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Access Ρ‚ΠΎΠΊΠ΅Π½. Π­Ρ‚ΠΎΡ‚ ΠΆΠ΅ кусочСк ΠΊΠΎΠ΄Π° Π΅ΡΡ‚ΡŒ Π² Π½Π°Ρ‡Π°Π»Π΅ скрипта ΠΏΡ€ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ Access Ρ‚ΠΎΠΊΠ΅Π½Π°:

function Get-GoogleToken {
  if (((Get-date).Hour -gt $token_expire.hour) -or (((Get-date).Hour -ge $token_expire.hour) -and ((Get-date).Minute -gt $token_expire.minute))) {
  Write-Host "Token Expired. Refreshing..."
    $request = (Invoke-RestMethod -Method Post -Uri "https://www.googleapis.com/oauth2/v4/token" -ContentType 'application/x-www-form-urlencoded' -Body @{
      client_id = $client_id
      client_secret = $client_secret
      refresh_token = $refresh_token
      grant_type = 'refresh_token'
    })
    $token = $request.access_token
    $minute = ([int]("{0:mm}" -f ([timespan]::fromseconds($request.expires_in))))+((Get-date).Minute)-2
    if ($minute -lt 0) {$minute += 60}
    elseif ($minute -gt 59) {$minute -=60}
    $script:token_expire = @{
      hour = ([int]("{0:hh}" -f ([timespan]::fromseconds($request.expires_in))))+((Get-date).Hour)
      minute = $minute
    }
  }
  return $token
}

ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° Π»ΠΎΠ³ΠΈΠ½Π° Π½Π° сущСствованиС:

function Check_Google {
  $query = (GoogleQuery 'SearchAccount' $username)
  if ($query.users -ne $null) {
    $user = $query.users[0]
    Write-Host $user.name.fullName' - '$user.PrimaryEmail' - suspended: '$user.Suspended
    $GAresult = $user
  }
  if ($GAresult) {
      $return = $GAresult
  } else {$return = 'gg'}
  return $return
}

Запрос email:$query попросит API ΠΏΠΎΠΈΡΠΊΠ°Ρ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ ΠΈΠΌΠ΅Π½Π½ΠΎ с Ρ‚Π°ΠΊΠΈΠΌ email, Π² Ρ‚ΠΎΠΌ числС Π±ΡƒΠ΄ΡƒΡ‚ Π½Π°ΠΉΠ΄Π΅Π½Ρ‹ алиасы. Π’Π°ΠΊ ΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ wildcard: =, :, :{PREFIX}*.

Для получСния Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΌΠ΅Ρ‚ΠΎΠ΄ запроса GET, для вставки Π΄Π°Π½Π½Ρ‹Ρ… (созданиС Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° ΠΈΠ»ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ участника Π² Π³Ρ€ΡƒΠΏΠΏΡƒ) – POST, для обновлСния ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΡ… Π΄Π°Π½Π½Ρ‹Ρ… – PUT, для удалСния записи (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, участника ΠΈΠ· Π³Ρ€ΡƒΠΏΠΏΡ‹) – DELETE.

Π‘ΠΊΡ€ΠΈΠΏΡ‚ Ρ‚Π°ΠΊ ΠΆΠ΅ спросит Π½ΠΎΠΌΠ΅Ρ€ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π° (нСвалидируСмая строка) ΠΈ ΠΎ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠΈ Π² Ρ€Π΅Π³ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΡƒΡŽ Π³Ρ€ΡƒΠΏΠΏΡƒ рассылки. Он Ρ€Π΅ΡˆΠ°Π΅Ρ‚ какая организационная Π΅Π΄ΠΈΠ½ΠΈΡ†Π° Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π±Ρ‹Ρ‚ΡŒ Ρƒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π½Π° основС Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠΉ OU Active Directory ΠΈ ΠΏΡ€ΠΈΠ΄ΡƒΠΌΠ°Π΅Ρ‚ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ:

do {
  $phone = Read-Host "Π’Π΅Π»Π΅Ρ„ΠΎΠ½ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ +7Ρ…Ρ…Ρ…Ρ…Ρ…Ρ…Ρ…Ρ…"
} while (-not $phone)
do {
    $moscow = Read-Host "Π’ Московский офис? (y/n) "
} while (-not (($moscow -eq 'y') -or ($moscow -eq 'n')))
$orgunit = '/'
if ($OU -like "*OU=Delivery,OU=Users,OU=ROOT,DC=rocket,DC=local") {
    Write-host "Π‘ΡƒΠ΄Π΅Ρ‚ создана Π² /Team delivery"
    $orgunit = "/Team delivery"
}
$Password =  -join ( 48..57 + 65..90 + 97..122 | Get-Random -Count 12 | % {[char]$_})+"*Ba"

И Π΄Π°Π»Π΅Π΅ Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ манипуляции с Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚ΠΎΠΌ:

$query = @{
  email = $email
  givenName = $firstname
  familyName = $lastname
  password = $password
  phone = $phone
  orgunit = $orgunit
}
if ($GMailExist) {
  Write-Host "ЗапускаСм ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°" -f mag
  (GoogleQuery 'UpdateAccount' $query) | fl
  write-host "НС Π·Π°Π±ΡƒΠ΄ΡŒ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ Π³Ρ€ΡƒΠΏΠΏΡ‹ Ρƒ Π²ΠΊΠ»ΡŽΡ‡Π΅Π½Π½ΠΎΠ³ΠΎ $Username Π² Google."
} else {
  Write-Host "ЗапускаСм созданиС Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°" -f mag
  (GoogleQuery 'CreateAccount' $query) | fl
}
if ($moscow -eq "y"){
  write-host "ДобавляСм Π² Π³Ρ€ΡƒΠΏΠΏΡƒ moscowoffice"
  $query = @{
    groupkey = '[email protected]'
    email = $email
  }
  (GoogleQuery 'AddMember' $query) | fl
}

Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ обновлСния ΠΈ создания Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π° ΠΈΠΌΠ΅ΡŽΡ‚ Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹ΠΉ синтаксис, Π½Π΅ всС Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ поля ΠΎΠ±ΡΠ·Π°Ρ‚Π΅Π»ΡŒΠ½Ρ‹, Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ с Π½ΠΎΠΌΠ΅Ρ€Π°ΠΌΠΈ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½ΠΎΠ² Π½ΡƒΠΆΠ½ΠΎ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ массив, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΠΎΡ‚ ΠΎΠ΄Π½ΠΎΠΉ записи с Π½ΠΎΠΌΠ΅Ρ€ΠΎΠΌ ΠΈ Π΅Π³ΠΎ Ρ‚ΠΈΠΏΠΎΠΌ.

Π§Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΎΡˆΠΈΠ±ΠΊΡƒ ΠΏΡ€ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π² Π³Ρ€ΡƒΠΏΠΏΡƒ, ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ, состоит Π»ΠΈ ΠΎΠ½ ΡƒΠΆΠ΅ Π² этой Π³Ρ€ΡƒΠΏΠΏΠ΅, ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ² список Ρ‡Π»Π΅Π½ΠΎΠ² Π³Ρ€ΡƒΠΏΠΏΡ‹ ΠΈΠ»ΠΈ состав Ρƒ самого ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ.

Запрос состава Π³Ρ€ΡƒΠΏΠΏ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅ рСкурсивным ΠΈ ΠΏΠΎΠΊΠ°ΠΆΠ΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ нСпосрСдствСнноС члСнство. Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ Π² Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΡƒΡŽ Π³Ρ€ΡƒΠΏΠΏΡƒ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ ΡƒΠΆΠ΅ состоит дочСрняя Π³Ρ€ΡƒΠΏΠΏΠ°, участником ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ являСтся ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ, Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΡΠΏΠ΅ΡˆΠ½Ρ‹ΠΌ.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

ΠžΡΡ‚Π°Π»ΠΎΡΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ ΠΎΡ‚ Π½ΠΎΠ²ΠΎΠ³ΠΎ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚Π°. ΠœΡ‹ Π΄Π΅Π»Π°Π΅ΠΌ это Ρ‡Π΅Ρ€Π΅Π· БМБ, Π° ΠΎΠ±Ρ‰ΡƒΡŽ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡŽ с инструкциСй ΠΈ Π»ΠΎΠ³ΠΈΠ½ΠΎΠΌ отправляСм Π½Π° Π»ΠΈΡ‡Π½ΡƒΡŽ ΠΏΠΎΡ‡Ρ‚Ρƒ, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ, вмСстС с Π½ΠΎΠΌΠ΅Ρ€ΠΎΠΌ Ρ‚Π΅Π»Π΅Ρ„ΠΎΠ½Π°, прСдоставил ΠΎΡ‚Π΄Π΅Π» ΠΏΠΎΠ΄Π±ΠΎΡ€Π° пСрсонала. Как Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΉ Π²Π°Ρ€ΠΈΠ°Π½Ρ‚, ΠΌΠΎΠΆΠ½ΠΎ ΡΡΠΊΠΎΠ½ΠΎΠΌΠΈΡ‚ΡŒ Π΄Π΅Π½Π΅ΠΆΠΊΡƒ ΠΈ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ ΠΏΠ°Ρ€ΠΎΠ»ΡŒ Π² сСкрСтный Ρ‡Π°Ρ‚ Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌΠ°, Ρ‡Ρ‚ΠΎ Ρ‚ΠΎΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Π²Ρ‚ΠΎΡ€Ρ‹ΠΌ Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΎΠΌ (ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ Π±ΡƒΠ΄ΡƒΡ‚ ΠΌΠ°ΠΊΠ±ΡƒΠΊΠΈ).

Бпасибо, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π»ΠΈ Π΄ΠΎ ΠΊΠΎΠ½Ρ†Π°. Π‘ΡƒΠ΄Ρƒ Ρ€Π°Π΄ ΡƒΠ²ΠΈΠ΄Π΅Ρ‚ΡŒ прСдлоТСния ΠΏΠΎ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡŽ стиля написания статСй ΠΈ ТСлаю Π²Π°ΠΌ ΡΠ»ΠΎΠ²ΠΈΡ‚ΡŒ помСньшС ошибок ΠΏΡ€ΠΈ написании скриптов =)

Бписок ссылочСк, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ тСматичСски ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ ΠΈΠ»ΠΈ просто ΠΎΡ‚Π²Π΅Ρ‚ΠΈΡ‚ΡŒ Π½Π° возникшиС вопросы:

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊ: habr.com

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ