د API له لارې د PowerShell څخه د ګوګل کاروونکي رامینځته کول

سلام!

دا مقاله به د ګوګل API سره د پاور شیل متقابل عمل پلي کول تشریح کړي ترڅو د G Suite کاروونکو اداره کړي.

موږ په ټوله اداره کې ډیری داخلي او کلاوډ خدمات کاروو. د ډیری برخې لپاره ، په دوی کې اختیار د ګوګل یا فعال لارښود ته راځي ، د کوم په مینځ کې موږ نشو کولی نقل وساتو؛ په همدې اساس ، کله چې نوی کارمند پریږدي ، تاسو اړتیا لرئ په دې دوه سیسټمونو کې یو حساب رامینځته / فعال کړئ. د پروسې اتومات کولو لپاره، موږ پریکړه وکړه چې یو سکریپټ ولیکئ چې معلومات راټولوي او دواړه خدماتو ته یې واستوي.

واکمنۍ

کله چې اړتیاوې رسم کړئ، موږ پریکړه وکړه چې د حقیقي بشري مدیرانو څخه د واک لپاره کار واخلو؛ دا د تصادفي یا قصدي لوی بدلونونو په صورت کې د کړنو تحلیل ساده کوي.

ګوګل APIs د تصدیق او اختیار لپاره د OAuth 2.0 پروتوکول کاروي. د قضیې کارول او نور تفصيلي توضیحات دلته موندل کیدی شي: د ګوګل APIs ته د لاسرسي لپاره د OAuth 2.0 کارول.

ما هغه سکریپټ غوره کړ چې د ډیسټاپ غوښتنلیکونو کې د اختیار لپاره کارول کیږي. د خدماتو حساب کارولو لپاره یو اختیار هم شتون لري ، کوم چې د کارونکي غیر ضروري حرکتونو ته اړتیا نلري.

لاندې انځور د ګوګل پاڼې څخه د ټاکل شوي سناریو سکیماتیک تشریح دی.

د API له لارې د PowerShell څخه د ګوګل کاروونکي رامینځته کول

  1. لومړی، موږ کاروونکي د ګوګل حساب تصدیق پاڼې ته لیږو، د GET پیرامیټونه مشخص کول:
    • د غوښتنلیک id
    • هغه سیمې چې غوښتنلیک ورته لاسرسی ته اړتیا لري
    • هغه پته چې کارونکي به د پروسې بشپړولو وروسته بیرته لیږل کیږي
    • هغه طریقه چې موږ به نښه تازه کړو
    • د خونديتوب کوډ
    • د تایید کوډ لیږد بڼه

  2. وروسته له دې چې واک بشپړ شو، کارونکي به په لومړۍ غوښتنه کې مشخص شوي پاڼې ته واستول شي، د GET پیرامیټونو لخوا د یوې تېروتنې یا اختیار ورکولو کوډ سره
  3. غوښتنلیک (سکریپټ) به د دې پیرامیټونو ترلاسه کولو ته اړتیا ولري او که چیرې کوډ ترلاسه کړي ، نو د توکیو ترلاسه کولو لپاره لاندې غوښتنه وکړئ
  4. که غوښتنه سمه وي، د ګوګل API بیرته راګرځي:
    • د لاسرسي نښه چې موږ یې غوښتنه کولی شو
    • د دې نښه د اعتبار موده
    • د لاسرسي نښه تازه کولو لپاره اړین ټوکن تازه کړئ.

لومړی تاسو اړتیا لرئ د ګوګل API کنسول ته لاړ شئ: اسناد - د ګوګل API کنسول، مطلوب غوښتنلیک غوره کړئ او د اعتباراتو برخه کې د پیرودونکي OAuth پیژندونکی رامینځته کړئ. هلته (یا وروسته، د رامینځته شوي پیژندونکي په ملکیتونو کې) تاسو اړتیا لرئ هغه پتې مشخص کړئ چې د بیرته راستنیدو اجازه لري. زموږ په قضیه کې ، دا به د مختلف بندرونو سره ډیری ځایی کوربه ننوتنې وي (لاندې وګورئ).

د سکریپټ الګوریتم لوستلو لپاره د اسانه کولو لپاره، تاسو کولی شئ په جلا فعالیت کې لومړی ګامونه وښایئ چې د غوښتنلیک لپاره د لاسرسي او ریفریش ټکنونه بیرته راولي:

$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

موږ د OAuth پیرودونکي پیژندونکي ملکیتونو کې ترلاسه شوي د پیرودونکي ID او د پیرودونکي راز تنظیم کوو ، او د کوډ تصدیق کونکی د 43 څخه تر 128 حروف پورې تار دی چې باید په تصادفي ډول د غیر محفوظ شوي حروفونو څخه رامینځته شي: [AZ] / [az] / [0-9] / "-" / "." / "_" / "~".

دا کوډ به بیا بیا لیږدول کیږي. دا هغه زیانونه له منځه وړي چې په هغه کې برید کوونکی کولی شي د کارونکي له اجازې وروسته بیرته راستنیدونکي ځواب مخه ونیسي.
تاسو کولی شئ په اوسني غوښتنه کې په واضح متن کې د کوډ تصدیق کونکي واستوئ (کوم چې دا بې معنی کوي - دا یوازې د سیسټمونو لپاره مناسب دی چې د SHA256 ملاتړ نه کوي) ، یا د SHA256 الګوریتم په کارولو سره د هش رامینځته کولو سره ، کوم چې باید په BASE64Url کې کوډ شوی وي (متفاوت د بیس 64 څخه د دوه جدول حروفونو لخوا) او د کریکټ لاین پایونه لرې کول: =.

بیا، موږ اړتیا لرو چې په محلي ماشین کې د HTTP اوریدل پیل کړو ترڅو د واک ورکولو وروسته ځواب ترلاسه کړو، کوم چې به د لارښوونې په توګه بیرته راستانه شي.

اداري دندې په ځانګړي سرور کې ترسره کیږي، موږ نشو کولی دا احتمال رد کړو چې ډیری مدیران به په ورته وخت کې سکریپټ چلوي، نو دا به په تصادفي ډول د اوسني کارونکي لپاره یو بندر غوره کړي، مګر ما مخکې تعریف شوي بندرونه مشخص کړل ځکه چې دوی باید د API کنسول کې د باور په توګه هم اضافه شي.

لاسرسي_ډول = آفلاین پدې معنی چې اپلیکیشن کولی شي د براوزر سره د کارونکي متقابل عمل پرته په خپله یو ختم شوی ټوکن تازه کړي ،
ځواب_ډول = کوډ د دې لپاره فارمیټ ټاکي چې کوډ به څنګه بیرته راستانه شي (د پخوانی اختیار کولو میتود ته مراجعه، کله چې کاروونکي کوډ له براوزر څخه سکریپټ ته کاپي کړي)
دائره د لاسرسي اندازه او ډول په ګوته کوي. دوی باید د ځایونو یا٪ 20 لخوا جلا شي (د URL کوډ کولو سره سم). د ډولونو سره د لاسرسي ساحو لیست دلته لیدل کیدی شي: د ګوګل APIs لپاره OAuth 2.0 سکوپونه.

د اختیار کوډ ترلاسه کولو وروسته ، غوښتنلیک به براوزر ته نږدې پیغام بیرته راولي ، په پورټ کې اوریدل ودروي او د نښه ترلاسه کولو لپاره د POST غوښتنه واستوي. موږ پدې کې د کنسول API څخه مخکینۍ ټاکل شوې ID او پټ په ګوته کوو ، هغه پته چې کارونکي ته به لیږل کیږي او د پروتوکول توضیحاتو سره سم grant_type.

په ځواب کې، موږ به د لاسرسي نښه، په ثانیو کې د اعتبار موده، او د ریفریش نښه ترلاسه کړو، چې ورسره موږ کولی شو د لاسرسي نښه تازه کړو.

غوښتنلیک باید د اوږدې شیلف ژوند سره په خوندي ځای کې ټوکن ذخیره کړي ، نو تر هغه چې موږ ترلاسه شوي لاسرسی لغوه کړو ، غوښتنلیک به د ریفریش نښه بیرته نه راوړي. په پای کې، ما د ټوکن د لغوه کولو غوښتنه اضافه کړه؛ که غوښتنلیک په بریالیتوب سره بشپړ شوی نه و او د ریفریش ټوکن بیرته راستون شوی نه و، نو دا به بیا پروسیجر پیل کړي (موږ په ټرمینل کې په محلي توګه د ټوکن ذخیره کول ناامنه وګڼله، او موږ دا کار کوو. نه غواړئ شیان د کریپټوګرافي سره پیچلي کړئ یا براوزر په مکرر ډول خلاص کړئ).

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 په خلاف، دا ترلاسه شوي ډاټا د کارونې وړ بڼه کې نه راستنوي او د غوښتنې حالت ښیي.

بیا ، سکریپټ له تاسو څخه غوښتنه کوي چې د کارونکي لومړی او وروستی نوم دننه کړئ ، د ننوتلو + بریښنالیک رامینځته کول.

غوښتنې

راتلونکی غوښتنې به وي - لومړی، تاسو اړتیا لرئ وګورئ چې ایا د ورته ننوتلو سره یو کارن شتون لري ترڅو د نوي جوړولو یا اوسني فعالولو په اړه پریکړه ترلاسه کړي.

ما پریکړه وکړه چې ټولې غوښتنې د انتخاب سره د یوې فنکشن په بڼه کې پلي کړم، د سویچ په کارولو سره:

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'])
      }
    }
  }
}

په هره غوښتنه کې، تاسو اړتیا لرئ د اختیار کولو سرلیک واستوئ چې د ټوکن ډول او پخپله د لاسرسي نښه لري. اوس مهال، د نښې ډول تل بییرر دی. ځکه موږ اړتیا لرو چې وګورو چې نښه پای ته نه ده رسیدلې او د هغې شیبې څخه یو ساعت وروسته یې تازه کړئ چې دا خپور شوی و، ما د بل فعالیت لپاره غوښتنه مشخص کړه چې د لاسرسي نښه بیرته راګرځوي. د کوډ ورته ټوټه د سکریپټ په پیل کې ده کله چې د لومړي لاسرسي نښه ترلاسه کول:

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
}

د بریښنالیک: $ پوښتنې غوښتنه به له API څخه وغواړي چې د هغه بریښنالیک سره د یو کارونکي په لټه کې شي چې د عرف په شمول. تاسو کولی شئ وائلډ کارډ هم وکاروئ: =، :، :{PREFIX}*.

د معلوماتو ترلاسه کولو لپاره ، د GET غوښتنې میتود وکاروئ ، د ډیټا دننه کولو لپاره (د حساب رامینځته کول یا ډلې ته د غړي اضافه کول) - POST ، د موجوده معلوماتو تازه کولو لپاره - PUT ، د ریکارډ حذف کولو لپاره (د مثال په توګه ، د یوې ډلې غړی) - ړنګول.

سکریپټ به د تلیفون شمیره (یو نا تایید شوي تار) او د سیمه ایز توزیع ګروپ کې شاملولو غوښتنه وکړي. دا پریکړه کوي چې کوم تنظیمي واحد باید کارونکي د ټاکل شوي فعال لارښود OU پراساس ولري او د پټنوم سره راځي:

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
}

د اکاونټ د تازه کولو او جوړولو لپاره دندې ورته ترکیب لري؛ ټولې اضافي ساحې ته اړتیا نشته؛ د تلیفون شمیرو سره په برخه کې، تاسو اړتیا لرئ یو سري مشخص کړئ چې د شمیرې او د هغې ډول سره یو ریکارډ ولري.

د دې لپاره چې په یوه ګروپ کې د کاروونکي اضافه کولو په وخت کې کومه تېروتنه ونه کړئ، موږ کولی شو لومړی دا وګورو چې ایا هغه دمخه د دې ډلې غړی دی که نه د ګروپ غړو لیست ترلاسه کولو یا پخپله د کارونکي څخه ترکیب.

د یو ځانګړي کارونکي ګروپ غړیتوب پوښتنه به تکراري نه وي او یوازې مستقیم غړیتوب به وښیې. په والدین ګروپ کې د یو کارونکي په شمول چې دمخه یې د ماشومانو ګروپ لري چې کارن یې غړی دی بریالی به شي.

پایلې

ټول هغه څه چې پاتې دي د نوي حساب لپاره کارونکي ته د پټنوم لیږل دي. موږ دا د ایس ایم ایس له لارې کوو، او عمومي معلومات د لارښوونو سره لیږو او شخصي بریښنالیک ته ننوتل، کوم چې د تلیفون شمیرې سره، د استخدام څانګې لخوا چمتو شوی. د بدیل په توګه، تاسو کولی شئ پیسې خوندي کړئ او خپل پټنوم پټ ټیلیګرام چیٹ ته واستوئ، کوم چې دویمه فاکتور هم ګڼل کیدی شي (میک بوکس به یو استثنا وي).

تر پایه د لوستلو لپاره مننه. زه به خوښ شم چې د مقالو لیکلو سټایل ښه کولو لپاره وړاندیزونه وګورم او هیله لرم چې د سکریپټونو لیکلو پرمهال لږې غلطۍ ونیسئ =)

د لینکونو لیست چې ممکن په موضوعي توګه ګټور وي یا په ساده ډول پوښتنو ته ځواب ووایی:

سرچینه: www.habr.com

Add a comment