Creando Google Users ex PowerShell per API

Salvete!

Hic articulus exsecutionem PowerShell commercii cum Google API describet ut G Suite utentes manipulare.

Pluribus officiis internis et nubes per ordinem utimur. Pleraque in eis licentia descendit ad Google vel Directorium activum, inter quod imaginem servare non possumus, ideoque, cum novus operarius relinquit, in his duobus systematibus rationem creare debes. Processus automate decrevimus scribere litteras collectas notitias et ad utrumque officium mittit.

auctoritas

Cum exigentiis conficiendis, decrevimus utendos administratores reales humanos pro concessione, quae simpliciorem facit analysin actionum in eventu mutationum accidentalium vel voluntalium massivarum.

Google APIs OAuth 2.0 protocollo utitur ad authenticas et auctoritates faciendas. Usus causarum et descriptiones accuratiores hic inveniuntur: Usura OAuth 2.0 accedere Google APIs.

Scriptum delegi quod auctoritate usus est in applicationibus desktop. Est etiam optio utendi ratione muneris, quae motus supervacuos ab utore non requirit.

Pictura infra est descriptio schematica missionis selectae ex Google pagina.

Creando Google Users ex PowerShell per API

  1. Primum usorem ad paginam authenticas Google Rationis mittimus, parametris specificans GET:
    • applicationem id
    • locis quod application est aditus ad
    • oratio cui user ut redirected peracta ratio
    • via nos mos update indicium
    • Security Code
    • verificationis tradenda forma

  2. Postquam licentia peracta est, usor ad paginam in qua prima instantia determinatur, cum errore vel licentia codici praetermisso GET parametri
  3. Applicatio (scriptionis) hos parametri recipiendi necesse erit et, si codicem receperit, sequentia petendi signa impetrabit.
  4. Si recta petitio est, Google API redit:
    • Accessum indicium quo petere possumus
    • Validitatem tempus huius indicium
    • Renovare indicium requiritur ad Accessum refice indicium.

Primum opus ad Google API consolandum ire: Documentorum - Google API Consoleelige applicationem desideratam et in sectione Credentialium clientem OAuth identificantem creare. Ibi (vel postea in proprietatibus identificantis creati) opus est inscriptionibus exprimere ad quas rediretio permittitur. In casu nostro, hae plures introitus locales cum diversis portis erunt (vide infra).

Ut commodius fiat algorithmus scriptionem legere, primos gradus in functione separato monstrare potes, qui Obvius redibit et signa ad applicationem refice;

$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 et Client Secretum in OAuth proprietatibus identificantis obtentum constituimus, et codicem uerificatorium filum 43 ad 128 notas, quae ex certis characteribus passim generari debent: [AZ] / [az] / [0-9] / " - " / " " . / "_" / "~".

Hoc signum postea denuo transmittetur. Excludit vulnerabilitatem qua invasor intercipere potuit responsionem redirectam post usorum potestatem reddidit.
Potes codicem verificantem in hodierna petitione in textu perspicuo mittere (quod inane facit - hoc solum ad systemata SHA256 non aptum), vel Nullam algorithmum in SHA256 creando, quod in BASE64Url encoded debet (differre. a Base64 by two table characters) and remove the character line terminations : =.

Deinde necesse est ut in machina locali auscultare incipias ut responsionem recipias post concessionem, quae redirectio reddetur.

Officia administrativa in speciali servo exercentur, facultatem excludere non possumus ut plures administratores scripturam simul currant, passim portum usoris currenti eligent, sed portus praedefinitos designavi quod additae sunt etiam ut confidimus in API console.

access_type = online significat applicationem renovare praeterlapsum signum suum sine usuario commercio cum navigatro;
response_type = codice forma ponit quomodo codicem reddetur (respicitur ad veterem auctoritatem methodi, cum usor codicem e navigatro in scriptionem exscripsit);
scope indicat scopum et genus aditus. Separari debent per spatia vel 20 (secundum URL modum translitterandi). Index arearum accessuum cum speciebus hic videri potest: OAuth 2.0 Scopes pro Google APIs.

Accepta licentia codicis, applicatio propinquum nuntium ad navigatorem reddet, in portu audi desine et petitionem electronicam mitte ut signum obtineat. In ea indicamus praelibatum id et secretum ex console API, oratio ad quam utens redirecta erit et grant_typum secundum protocolli specificationem.

Respondentes Accessum accipiemus indicium, eius validitatem in secundis periodum, ac signum Renovatum, quo Accessum tesseram renovare possumus.

Applicatio signa loco securo cum longa pluteo condere debet, ut donec recepto accessu revocetur, applicationis signum reficiendi non reddet. In fine petitionem ad reuocandum signum addidi: si applicatio non peracta feliciter et signum reficiendi non redditum, ratio rursus incipiet (incolumem esse duxi signa localiter in termino condere, et nos induimus. 't res cum cryptographia inpediunt vel navigatrum frequenter aperiunt).

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
}

Ut iam animadvertit, revocando signum, Invoke-WebRequest adhibetur. Dissimilis Invoke-RestMethod, data recepta in forma utilia non reddit et statum rogationis ostendit.

Deinde, scriptum te rogat ut nomen primum et ultimum utentis ineas, login+inscriptionem generans.

petitiones

Proximae petitiones erunt - ante omnia, debes inspicere utrum usor cum eodem login iam existat ut decisionem de novo creando vel hodiernam efficiendo obtineat.

Omnes petitiones in forma unius functionis cum delectu efficere decrevi, utens 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'])
      }
    }
  }
}

In unaquaque rogatione, debes mittere LICENTIA caput cum signo speciei et tessera Access. In statu, signum generis semper Vexilliferum. Quod Inhibere necesse est signum non exspirasse et renovare post horam a momento prolatam, rogationem pro alio munere constitui quod Accessum reddit indicium. Idem fragmentum codicis est in initio scriptionis cum primo Access signo accepto;

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
}

Reprehendo login existendi:

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
}

Inscriptio:$ quaesitum rogabit API ut quaeram usorem cum exacte illa electronica, inter aliases. Wildcard uti potes: =, :, :{ PREFIX}*.

Ad datam obtinendam, petendi modum GET utere, data inserere (ratio creandi vel membrum globi addendo) - POST, ad datam update existendam - PUT, delere recordum (exempli gratia membrum e coetu) - DELETIS.

Scriptum etiam petet numerum telephonicum (chorda firmata) et inclusionem in coetus regionali distributione. Decernit utra norma unitatis utentis fundari debeat in Directorio Active delectis OU et cum tessera exit:

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"

Et tunc incipit ratiocinari;

$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
}

Munera augendi et creandi rationem similem syntaxin habent, non omnes agri adiective requiruntur, in sectione cum numeris telephonicis, ordinatam denotare debes, qui usque ad unum ingressum cum numero et specie continere potest.

Ne errorem recipiat cum usorem ad globum addens, primum inspiciamus utrum iam membrum sit huius coetus, habendo indicem sodalitatum vel compositionem ab ipso utente.

Quaerens sodalitatem sodalitatis cuiusdam usoris certae non erit recursivus et tantum adscriptionem directam demonstrabit. Comprehendo usorem in coetus parentis quae iam coetus puerilis habet quod usor membrum succedet.

conclusio,

Reliquum est ut tesseram usoris nova ratione mittat. Hoc per SMS facimus, et informationes generales mittimus cum mandatis et login ad personalem electronicam, quae una cum numero telephonico a department cooptatione praebebatur. Ut jocus, pecuniam servare potes et tesseram tuam ad chat occultum telegraphum mitte, quod etiam factor secundus considerari potest (MacBooks exceptio erit).

Gratias ago tibi, quia lectio est in fine. Libenter videre suggestiones pro stilo emendandi articulos scribendi et te velim pauciores errores capere cum scriptorum scripto =)

Index nexuum qui forte thematice utiles vel simpliciter interrogationes respondeant:

Source: www.habr.com