SE の雑記

SQL Server の情報をメインに Microsoft 製品の勉強内容を日々投稿

PowerShell を使用して Azure の REST API を操作する

leave a comment

Azure Reference で API が公開されていますが、サービス管理用の REST API を PowerShell で操作する際の自分メモを。

Azure PowerShell を使用して操作すれば、REST API の直接操作が必要になることは少ないかと思いますが勉強がてら。

 

基本的な情報は以下を参考にしています。

Communicate to Azure via REST from PowerShell
AZURE REST API & PowerShell: Retrieve Cloud Service Configuration
Using the Windows Azure REST APIs with PowerShell
Leveraging the Azure Service Management REST API with Azure Active Directory and PowerShell / List Azure Administrators
Using Azure Resource Management REST API in PowerShell
Certificate-based authentication to Azure Resource Manager using Powershell
Automating Azure Autoscale Rules via PowerShell and REST API
(課金API)をPowerShellから試してみた
How does Azure PowerShell work with username/password based auth?
Azure/azure-iot-remote-monitoring

また、Azure 関連のコマンドレットを 「-debug」を付けて実行して、API へのリクエスト/レスポンスを見ることもできます。
AzureTools から REST API のテストができたりもするようですね。こちらは ASM の証明書を使用した呼び出しに対応しているようです。そのうち、ARM の方も対応してもらえたりするのでしょうか。
# AzureTools ? The Diagnostic Utility used by the Windows Azure Developer Support Team

REST API の呼び出し方法ですが、ASM / ARM の二種類についての呼び出し方法を考慮する必要があるかと思います。

Azure Reference
Service Management REST API Reference
Azure Resource Manager REST API Reference

まずは、ASM の方を見ていきたいと思います。

ASM の REST API の呼び出し


Operations for Azure SQL Databases の SQL Database の API を使ってごにょごにょと。

ASM の場合は、サブスクリプションに登録している「管理証明書」を使用して実行する必要がありますので、証明書を作成して、エクスポートしてポータルから登録しておきます。

$eku = "2.5.29.37={text}1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2"
$expirydate = (Get-Date).AddYears(50)
$subject = "Azure Management Cert"
$cert = Get-ChildItem Cert:\CurrentUser\My | ?{$_.Subject -like "*$subject*"}
if ($cert -eq $null){
    $cert = New-SelfSignedCertificate -Subject $subject -NotAfter $expirydate -TextExtension $eku -CertStoreLocation Cert:\CurrentUser\My
}
$exportfile = Join-Path ([System.IO.Path]::GetTempPath()) "AzureCert.cer"
Write-output $exportfile
Export-Certificate -Cert $cert -FilePath $exportfile


証明書を使用したアクセスでは以下のような形で Azure の PowerShell を実行することができます

$subject = "Azure Management Cert"
$cert = Get-ChildItem Cert:\LocalMachine\My | ?{$_.Subject -like "*$subject*"}
$subscriptionid = "<サブスクリプション ID>"
$subscriptionname = "<>サブスクリプション名>"
Set-AzureSubscription -SubscriptionId $subscriptionid -SubscriptionName $subscriptionname -Certificate $cert
Select-AzureSubscription -SubscriptionId $subscriptionid -Current


ASM の REST API については、証明書を使用してのアクセスとなりますので、以下のような呼び出しができます。

$subject = "Azure Management Cert"
$cert = Get-ChildItem Cert:\CurrentUser\My | ?{$_.Subject -like "*$subject*"}
$method = "GET"
$headers = @{"x-ms-version"="2012-03-01"}
$apiurl = "https://management.core.windows.net:8443/$subscriptionid/services/sqlservers/servers"
$server = Invoke-RestMethod -Verbose -Uri $apiurl -CertificateThumbprint $cert.Thumbprint -Method $method -Headers $headers
Write-Output $server.OuterXml
$method = "GET"
$headers = @{"x-ms-version"="2012-03-01"}
$startdate = ((Get-Date).AddMonths(-3)).ToUniversalTime().ToString("yyyy-MM-dd hh:mm:ss")
$apiurl = "https://management.core.windows.net:8443/$subscriptionid/services/sqlservers/servers/$(($server.Servers.server)[0].Name)/events?startDate=$startdate&intervalSizeInMinutes=60&eventTypes="
$ret = Invoke-RestMethod -Verbose -Uri $apiurl -CertificateThumbprint $cert.Thumbprint -Method $method -Headers $headers
$method = "POST"
$headers = @{"x-ms-version"="2012-03-01"}
$apiurl = "https://management.core.windows.net:8443/$subscriptionid/services/sqlservers/servers/$($server.Servers.Server.name[0])/databases"
[xml]$body = @"
<serviceResource xmlns="http://schemas.microsoft.com/windowsazure">
  <name>TESTDB2</name>
  <edition>Basic</edition>
  <collationName></collationName>
</serviceResource>
"@
$ret = Invoke-RestMethod -Verbose -Uri $apiurl -CertificateThumbprint $cert.Thumbprint -Method $method -Headers $headers -Body $body -ContentType "application/xml"

 

こちらの実行はシンプルですね。

リクエストの BODY として、XML を渡して、REST を呼び出すときに証明書のサムプリントを指定して実行します。

ASM の場合、レスポンスは XML だと思いますので、GET した場合はこちらを利用します。

ARM の REST API の呼び出し


Azure SQL Database REST API Reference でごにょごにょと。

こちらについては、証明書ではなく、Authorization ヘッダーを使用してアクセスを行います。

Authorization ヘッダーを、Azure Active Directory から取得する JSON Web Token に設定します。詳細については、「Azure Resource Manager 要求の認証」を参照してください。

ARM の REST API の呼び出しは AAD のアカウントを使用して実施することになるかと。

そのため、AAD に API 呼び出し用の組織アカウントを作成して、共同管理者として追加をしておきます。

# AAD のユーザー作成時の権限の設定と、サブスクリプションの共同管理者の設定の違いがきちんと理解できていないのですよね…。

 

ADAL を使用するので Azure PowerShell をインストールしておきます。

$azurepowershellurl = "https://github.com/Azure/azure-powershell/releases/download/v0.9.8-September2015/azure-powershell.0.9.8.msi"
if ((Get-Command -Module Azure).Count -gt 0){
    Write-Output "Azure PowerShell のインストール済み"
}else{
    $tempfile = [System.IO.Path]::GetTempFileName()
    Invoke-WebRequest -Uri $azurepowershellurl -OutFile $tempfile
    Start-Process -FilePath msiexec.exe -ArgumentList "/i $tempfile", "/passive"  -Wait
    $ENV:PSModulePath = [System.Environment]::GetEnvironmentVariable("PSModulePath","Machine")
    Remove-Item $tempfile
}

 

これで、ADAL が使用できるようになりましたので、ロードしておきます。

# http://blogs.technet.com/b/keithmayer/archive/2014/12/30/authenticating-to-the-azure-service-management-rest-api-using-azure-active-directory-via-powershell-list-azure-administrators.aspx
# Set well-known client ID for Azure PowerShell
$clientId = "1950a258-227b-4e31-a9cf-717495945fc2"
# Set redirect URI for Azure PowerShell
$redirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceAppIdURI = "https://management.core.windows.net/"
$adTenant = "sqladauth.onmicrosoft.com"
# Set Resource URI to Azure Service Management API
$authority = "https://login.windows.net/$adTenant"
$programDir = ${env:ProgramFiles(x86)}
if(!$programDir)
{
    $programDir = ${env:ProgramFiles}
}
$adal = "$programDir\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalforms = "$programDir\Microsoft SDKs\Azure\PowerShell\ServiceManagement\Azure\Services\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll"
Add-Type -Path $adal
Add-Type -Path $adalforms

 

次に Authorization ヘッダーに指定る情報を作成します。

現状、Add-AzureAccount で Creential を指定した場合は、組織アカウントしか指定できないかと思いますので、サブスクリプションを操作できる組織アカウントの情報を指定します。

REST 呼び出し時には別途資格情報を作成していますが、AcquireToken を呼び出す際に、明示的に指定したアカウントが、組織アカウントでない場合は「"3" 個の引数を指定して "AcquireToken" を呼び出し中に例外が発生しました: "missing_federation_metadata_url: Federation Metadata Url is missing for federated user. This user type is unsupported."」のエラーとなるようですので、REST API についても、現状、組織アカウントを使用する必要が出てくるようですね。

 

$user = "<組織アカウント>"
$password = ConvertTo-SecureString "<パスワード>"-asPlainText -Force
$cred =  New-Object System.Management.Automation.PSCredential $user,$password
Add-AzureAccount -Credential $cred
$subscriptionid = "<サブスクリプション ID>"
# Create Authentication Context tied to Azure AD Tenant
$authContext = New-Object -TypeName "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext"  -ArgumentList $authority
# Acquire Azure AD token
# $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $redirectUri, "Auto") #on-demand
# Automation
$creds = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $user,$password
$authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId, $creds)
# Create Authorization Header
$authHeader = $authResult.CreateAuthorizationHeader()

 

これで、REST API を呼び出す準備が整いましたので呼び出します。

$method = "GET"
$server = "<サーバー名>"
$database = "<db名>"
$resourgegroup = "<リソースグループ名>"
$apiurl = "https://management.azure.com/subscriptions/$subscriptionid/resourceGroups/$resourgegroup/providers/Microsoft.Sql/servers/$server/databases/$database/metrics?api-version=2014-04-01&`$filter=(name.value eq 'cpu_percent' or name.value eq 'log_write_percent' or name.value eq '?data_io_percent' or name.value eq 'DTU_percent' or name.value eq 'storage_in_megabytes') and timeGrain eq duration'PT5M' and startTime eq 2015-10-07T00:00:00Z and endTime eq 2015-10-08T00:00:00Z"
$requestHeader = @{
"x-ms-version" = "2014-04-01";
"Authorization" = $authHeader
"Accept" = "application/json"
}
$contentType = "application/json;charset=utf-8"
$ret = Invoke-RestMethod -Verbose -Uri $apiurl -Method $method -Headers $requestHeader -ContentType $contentType
$method = "PUT"
$resourgegroup = "<リソースグループ名?"
$newserver="<サーバー名>"
$requestHeader = @{
"x-ms-version" = "2014-04-01";
"Authorization" = $authHeader;
"Accept" = "application/json"
}
$json = @"
{
  "properties": {
    "version" : "12.0",
    "
    "administratorLogin": "<管理者ユーザー>",
    "administratorLoginPassword": "<管理者パスワード>"
  },
  "location": "japanwest"
}
"@
[byte[]]$requestBody = [System.Text.Encoding]::UTF8.GetBytes($json)
$apiurl = "https://management.azure.com/subscriptions/$subscriptionid/resourceGroups/$resourgegroup/providers/Microsoft.Sql/servers/$($newserver)?api-version=2014-04-01"
$ret = Invoke-RestMethod -Verbose -Uri $apiurl -Method $method -Headers $requestHeader -ContentType $contentType -Body $requestBody

 

AAD のユーザーを使用してアクセスをし、レスポンスを JSON として受け取り、使用するのが特徴でしょうか。

# JSON で受け取れず、XML で受け取ってしまっていたのを No.1れいさくんに JSON で受け取る方法を教えてもらいました。あざっす!!

Share

Written by Masayuki.Ozawa

10月 12th, 2015 at 10:30 am

Posted in Microsoft Azure

Tagged with ,

Leave a Reply