PowerShell を使用したエラスティック ジョブの作成と管理

適用対象:Azure SQL Database

この記事では、PowerShell を使用してエラスティック ジョブを使い始めるためのシナリオの例を提供します。 エラスティック ジョブを使用すると、複数のデータベースにわたって 1 つまたは複数の Transact-SQL (T-SQL) スクリプトを同時に実行できます。

このエンドツーエンドのチュートリアルでは、複数のデータベースにわたってクエリを実行するために必要な手順を学習します。

  • エラスティック ジョブ エージェントを作成する
  • ジョブによってターゲット上でスクリプトを実行できるようにジョブ認証情報を作成する
  • ジョブを実行するターゲット (サーバー、エラスティック プール、データベース) を定義する
  • エージェントが接続してジョブを実行できるように、ターゲット データベースにデータベース スコープ資格情報を作成する
  • ジョブの作成
  • ジョブにジョブ ステップを追加する
  • ジョブの実行を開始する
  • ジョブを監視する

前提条件

エラスティック データベース ジョブには、一連の PowerShell コマンドレットがあります。

これらのコマンドレットは、2023 年 11 月に更新されました。

最新のエラスティック ジョブ コマンドレットをインストールする

Azure サブスクリプションをお持ちでない場合は、始める前に無料アカウントを作成してください。

まだ存在しない場合は、最新バージョンのAz.Sql モジュールと SqlServer モジュールをインストールします。 管理アクセス権で次の PowerShell コマンドを実行します。

# installs the latest PackageManagement and PowerShellGet packages
Find-Package PackageManagement | Install-Package -Force
Find-Package PowerShellGet | Install-Package -Force

# Restart your powershell session with administrative access

# Install and import the Az.Sql module, then confirm
Install-Module -Name Az.Sql
Import-Module Az.Sql
Install-Module -Name SqlServer
Import-Module SqlServer

詳細については、「SQL Server PowerShell モジュールのインストール」を参照してください。

必要なリソースを作成する

エラスティック ジョブ エージェントを作成するには、エラスティック ジョブ データベースとして使用するデータベース (S1 以上) が必要です。

次のスクリプトを実行すると、エラスティック ジョブ データベースとして使用する新しいリソース グループ、サーバー、およびデータベースが作成されます。 2 番目のスクリプトを実行すると、ジョブを実行する対象の、2 つの空のデータベースを含む 2 番目のサーバーが作成されます。

エラスティック ジョブには特定の命名要件がないため、Azure 要件に準拠している限り、任意の命名規則を使用できます。 エラスティック ジョブ データベースとして機能する空のデータベースをサーバーに既に作成している場合は、[エラスティック ジョブ エージェントの作成] に進みます。

エラスティック ジョブのプライベート エンドポイントを使用する場合、New-AzSqlServerFirewallRule でファイアウォール規則を構成する必要はありません。

# Sign in to your Azure account
Connect-AzAccount

# The SubscriptionId in which to create these objects
$SubscriptionId = '<your subscription id>'
# Set subscription context, important if you have access to more than one subscription.
Set-AzContext -SubscriptionId $subscriptionId 

# Create a resource group
Write-Output "Creating a resource group..."
$resourceGroupName = Read-Host "Please enter a resource group name"
$location = Read-Host "Please enter an Azure Region, for example westus2"
$rg = New-AzResourceGroup -Name $resourceGroupName -Location $location
$rg

# Create an Azure SQL logical server
Write-Output "Creating a server..."
$agentServerName = Read-Host "Please enter an agent server name"
$agentServerName = $agentServerName + "-" + [guid]::NewGuid()
$adminLogin = Read-Host "Please enter the server admin name"
$adminPassword = Read-Host "Please enter the server admin password"
$adminPasswordSecure = ConvertTo-SecureString -String $AdminPassword -AsPlainText -Force
$adminCred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList $adminLogin, $adminPasswordSecure
$parameters = @{
    ResourceGroupName = $resourceGroupName 
    Location = $location
    ServerName = $agentServerName 
    SqlAdministratorCredentials = ($adminCred)    
}
$agentServer = New-AzSqlServer @parameters

# Set server firewall rules to allow all Azure IPs
# Unnecessary if using an elastic jobs private endpoint
Write-Output "Creating a server firewall rule..."
$agentServer | New-AzSqlServerFirewallRule -AllowAllAzureIPs -FirewallRuleName "Allowed IPs"
$agentServer

# Create the job database
Write-Output "Creating a blank database to be used as the Job Database..."
$jobDatabaseName = "JobDatabase"
$parameters = @{
    ResourceGroupName = $resourceGroupName 
    ServerName = $agentServerName 
    DatabaseName = $jobDatabaseName 
    RequestedServiceObjectiveName = "S1"
}
$jobDatabase = New-AzSqlDatabase @parameters
$jobDatabase
# Create a target server and sample databases - uses the same credentials
Write-Output "Creating target server..."
$targetServerName = Read-Host "Please enter a target server name"
$targetServerName = $targetServerName + "-" + [guid]::NewGuid()
$parameters = @{
    ResourceGroupName= $resourceGroupName
    Location= $location 
    ServerName= $targetServerName
    ServerVersion= "12.0"
    SqlAdministratorCredentials= ($adminCred)
}
$targetServer = New-AzSqlServer @parameters

# Set target server firewall rules to allow all Azure IPs
# Unnecessary if using an elastic jobs private endpoint
$targetServer | New-AzSqlServerFirewallRule -AllowAllAzureIPs 

# Set the target firewall to include your desired IP range. 
# Change the following -StartIpAddress and -EndIpAddress values.
$parameters = @{
    StartIpAddress = "0.0.0.0" 
    EndIpAddress = "0.0.0.0"
    FirewallRuleName = "AllowAll"
}
$targetServer | New-AzSqlServerFirewallRule @parameters
$targetServer

# Create two sample databases to execute jobs against
$parameters = @{
    ResourceGroupName = $resourceGroupName 
    ServerName = $targetServerName 
    DatabaseName = "database1"
}
$db1 = New-AzSqlDatabase @parameters
$db1
$parameters = @{
    ResourceGroupName = $resourceGroupName 
    ServerName = $targetServerName 
    DatabaseName = "database2"
}
$db2 = New-AzSqlDatabase @parameters
$db2

エラスティック ジョブ エージェントを作成する

エラスティック ジョブ エージェントは、ジョブを作成、実行、および管理するための Azure リソースです。 エージェントは、スケジュールに基づいて、または 1 回だけのジョブとして、ジョブを実行します。 エラスティック ジョブのすべての日付と時刻には、UTC タイム ゾーンが適用されます。

New-AzSqlElasticJobAgent コマンドレットを実行するには、Azure SQL Database のデータベースが既に存在する必要があるため、resourceGroupNameserverName、および databaseName のすべてのパラメーターが既存のリソースを指している必要があります。 同様に、 Set-AzSqlElasticJobAgent を使用してエラスティック ジョブ エージェントを変更できます。

ユーザー割り当てマネージド ID で Microsoft Entra 認証を使用して新しいエラスティック ジョブ エージェントを作成するには、次の New-AzSqlElasticJobAgentIdentityTypeIdentityID の引数を使用します。

Write-Output "Creating job agent..."
$agentName = Read-Host "Please enter a name for your new elastic job agent"
$parameters = @{
    Name = $agentName 
    IdentityType = "UserAssigned" 
    IdentityID = "/subscriptions/abcd1234-caaf-4ba9-875d-f1234/resourceGroups/contoso-jobDemoRG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/contoso-UMI"
}
$jobAgent = $jobDatabase | New-AzSqlElasticJobAgent @parameters
$jobAgent

データベース スコープの資格情報を使用して新しいエラスティック ジョブ エージェントを作成する場合は、IdentityTypeIdentityID は提供されません。

ジョブ認証を作成する

エラスティック ジョブ エージェントは、各ターゲット サーバーまたはデータベースに対して認証可能である必要があります。

ジョブ エージェント認証の作成」で説明されているように、次の手順を実行します。

ターゲットへの認証に UMI で Microsoft Entra 認証を使用する

ユーザー割り当てマネージド ID (UMI) に対する Microsoft Entra (旧称 Azure Active Directory) 認証の推奨される方法を使用するには、次の手順に従います。 エラスティック ジョブ エージェントは、Entra 認証を介して目的のターゲット論理サーバー/データベースに接続します。

ログイン ユーザーとデータベース ユーザーに加えて、次のスクリプトに GRANT コマンドが追加されていることに注意してください。 これらのアクセス許可は、このサンプル ジョブ用に選択したスクリプトに必要です。 ジョブには、異なるアクセス許可が必要な場合があります。 この例では、ターゲット データベースに新しいテーブルを作成するため、正常に実行するには各ターゲット データベースのデータベース ユーザーに適切なアクセス許可が必要です。

各ターゲット サーバー/データベースで、UMI にマップされた包含ユーザーを作成します。

  • エラスティック ジョブに論理サーバーまたはプール ターゲットがある場合は、ターゲット論理サーバーの master データベース内の UMI にマップされた包含ユーザーを作成する必要があります。
  • たとえば、job-agent-UMI という名前のユーザー割り当てマネージド ID (UMI) に基づいて、包含データベース ログインを master データベースに作成し、ユーザー データベース内のユーザーを作成します。
$targetServer = '<target server name>'
$adminLogin = '<username>'
$adminPassword = '<password>'

# For the target logical server, in the master database
# Create the login named [job-agent-UMI] based on the UMI [job-agent-UMI], and a user
$params = @{
  'database' = 'master'
  'serverInstance' =  $targetServer.ServerName + '.database.windows.net'
  'username' = $adminLogin
  'password' = $adminPassword
  'outputSqlErrors' = $true
  'query' = 'CREATE LOGIN [job-agent-UMI] FROM EXTERNAL PROVIDER;'
}
Invoke-SqlCmd @params
$params.query = "CREATE USER [job-agent-UMI] FROM LOGIN [job-agent-UMI]"
Invoke-SqlCmd @params

# For each target database in the target logical server
# Create a database user from the job-agent-UMI login 
$targetDatabases = @( $db1.DatabaseName, $Db2.DatabaseName )
$createJobUserScript =  "CREATE USER [job-agent-UMI] FROM LOGIN [job-agent-UMI]"

# Grant permissions as necessary. For example ALTER and CREATE TABLE:
$grantAlterSchemaScript = "GRANT ALTER ON SCHEMA::dbo TO [job-agent-UMI]" 
$grantCreateScript = "GRANT CREATE TABLE TO [job-agent-UMI]"

$targetDatabases | % {
  $params.database = $_
  $params.query = $createJobUserScript
  Invoke-SqlCmd @params
  $params.query = $grantAlterSchemaScript
  Invoke-SqlCmd @params
  $params.query = $grantCreateScript
  Invoke-SqlCmd @params
}

ターゲットへの認証にデータベース スコープの資格情報を使用する

ジョブ エージェントは、実行時にターゲット グループによって指定された資格情報を使用してスクリプトを実行します。 これらのデータベース スコープ資格情報は、サーバーまたはエラスティック プールのいずれかがターゲット グループ メンバー タイプとして使用されているときに master データベースに接続してサーバーまたはエラスティック プール内のすべてのデータベースを検出するためにも使用されます。

データベース スコープ資格情報はジョブ データベースに作成する必要があります。 すべてのターゲット データベースには、ジョブが正常に完了するのに十分なアクセス許可を持つログインが必要です。

画像内の資格情報に加えて、次のスクリプトに GRANT コマンドが追加されていることに注意してください。 これらのアクセス許可は、このサンプル ジョブ用に選択したスクリプトに必要です。 ジョブには、異なるアクセス許可が必要な場合があります。 この例では、ターゲット データベースに新しいテーブルを作成するため、正常に実行するには各ターゲット データベースのデータベース ユーザーに適切なアクセス許可が必要です。

各ターゲット サーバー/データベースのログイン/ユーザーには、ジョブ ユーザーのデータベース スコープ資格情報の ID と同じ名前と、ジョブ ユーザーのデータベース スコープ資格情報と同じパスワードが必要です。 PowerShell スクリプトで <strong jobuser password here> を使用する場合は、全体で同じパスワードを使用します。

次の例では、データベース スコープの資格情報を使用します。 必要なジョブ資格情報を (ジョブ データベース内に) 作成するには、SQL 認証を使用してターゲット サーバー/データベースに接続する次のスクリプトを実行します。

# For the target logical server, in the master database
# Create the master user login, master user, and job user login
$targetServer = '<target server name>'
$adminLogin = '<username>'
$adminPassword = '<password>'

$params = @{
  'database' = 'master'
  'serverInstance' =  $targetServer.ServerName + '.database.windows.net'
  'username' = $adminLogin
  'password' = $adminPassword
  'outputSqlErrors' = $true
  'query' = 'CREATE LOGIN adminuser WITH PASSWORD=''<strong adminuser password here>'''
}
Invoke-SqlCmd @params
$params.query = "CREATE USER adminuser FROM LOGIN adminuser"
Invoke-SqlCmd @params
$params.query = 'CREATE LOGIN jobuser WITH PASSWORD=''<strong jobuser password here>'''
Invoke-SqlCmd @params

# For each target database in the target logical server
# Create the jobuser from jobuser login and check permission for script execution
$targetDatabases = @( $db1.DatabaseName, $Db2.DatabaseName )
$createJobUserScript =  "CREATE USER jobuser FROM LOGIN jobuser"

# Grant permissions as necessary. For example ALTER and CREATE TABLE:
$grantAlterSchemaScript = "GRANT ALTER ON SCHEMA::dbo TO jobuser"
$grantCreateScript = "GRANT CREATE TABLE TO jobuser"

$targetDatabases | % {
  $params.database = $_
  $params.query = $createJobUserScript
  Invoke-SqlCmd @params
  $params.query = $grantAlterSchemaScript
  Invoke-SqlCmd @params
  $params.query = $grantCreateScript
  Invoke-SqlCmd @params
}

# Create job credential in job database for admin user
Write-Output "Creating job credentials..."
$loginPasswordSecure = (ConvertTo-SecureString -String '<strong jobuser password here>' -AsPlainText -Force)
$loginadminuserPasswordSecure = (ConvertTo-SecureString -String '<strong adminuser password here>' -AsPlainText -Force)

$adminCred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList "adminuser", $loginadminuserPasswordSecure
$adminCred = $jobAgent | New-AzSqlElasticJobCredential -Name "adminuser" -Credential $adminCred

$jobCred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList "jobuser", $loginPasswordSecure
$jobCred = $jobAgent | New-AzSqlElasticJobCredential -Name "jobuser" -Credential $jobCred

ターゲット サーバーとデータベースを定義する

ターゲット グループは、ジョブ ステップによって実行される 1 つまたは複数のデータベースのセットを定義します。

次のスニペットは、serverGroupserverGroupExcludingDb2 の 2 つのターゲット グループを作成します serverGroup では、実行時にサーバー上に存在するすべてのデータベースがターゲットになります。serverGroupExcludingDb2 では、TargetDb2 を除くサーバー上のすべてのデータベースがターゲットになります。

Write-Output "Creating test target groups..."
# create ServerGroup target group
$serverGroup = $jobAgent | New-AzSqlElasticJobTargetGroup -Name 'ServerGroup'
$serverGroup | Add-AzSqlElasticJobTarget -ServerName $targetServerName -RefreshCredentialName $adminCred.CredentialName

# create ServerGroup with an exclusion of db2
$serverGroupExcludingDb2 = $jobAgent | New-AzSqlElasticJobTargetGroup -Name 'ServerGroupExcludingDb2'
$serverGroupExcludingDb2 | Add-AzSqlElasticJobTarget -ServerName $targetServerName -RefreshCredentialName $adminCred.CredentialName
$serverGroupExcludingDb2 | Add-AzSqlElasticJobTarget -ServerName $targetServerName -Database $db2.DatabaseName -Exclude

ジョブとステップを作成する

この例では、1 つのジョブと、そのジョブを実行するための 2 つのジョブ ステップを定義します。 最初のジョブ ステップ (step1) では、ターゲット グループ Step1Table 内のすべてのデータベースに新しいテーブル (ServerGroup) を作成します。 2 番目のジョブ ステップ (step2) では、TargetDb2 を除くすべてのデータベースに新しいテーブル (Step2Table) を作成します。これは、事前に定義されたターゲット グループがテーブルを除外するように指定されているためです。

Write-Output "Creating a new job..."
$jobName = "Job1"
$job = $jobAgent | New-AzSqlElasticJob -Name $jobName -RunOnce
$job

Write-Output "Creating job steps..."
$sqlText1 = "IF NOT EXISTS (SELECT * FROM sys.tables WHERE object_id = object_id('Step1Table')) CREATE TABLE [dbo].[Step1Table]([TestId] [int] NOT NULL);"
$sqlText2 = "IF NOT EXISTS (SELECT * FROM sys.tables WHERE object_id = object_id('Step2Table')) CREATE TABLE [dbo].[Step2Table]([TestId] [int] NOT NULL);"

$job | Add-AzSqlElasticJobStep -Name "step1" -TargetGroupName $serverGroup.TargetGroupName -CredentialName $jobCred.CredentialName -CommandText $sqlText1
$job | Add-AzSqlElasticJobStep -Name "step2" -TargetGroupName $serverGroupExcludingDb2.TargetGroupName -CredentialName $jobCred.CredentialName -CommandText $sqlText2

ジョブの実行

ジョブをすぐに開始するには、次のコマンドを実行します。

Write-Output "Start a new execution of the job..."
$jobExecution = $job | Start-AzSqlElasticJob
$jobExecution

正常に完了すると、TargetDb1 に新しいテーブルが 2 つ、TargetDb2 に新しいテーブルが 1 つだけ表示されます。

ジョブを後で実行するようにスケジュールすることもできます。

重要

エラスティック ジョブのすべての開始時刻は UTC タイム ゾーンが適用されます。

特定の時刻にジョブを実行するようにスケジュールを設定するには、次のコマンドを実行します。

# run every hour starting from now
$job | Set-AzSqlElasticJob -IntervalType Hour -IntervalCount 1 -StartTime (Get-Date) -Enable

ジョブの実行状態を監視する

次のスニペットを実行すると、ジョブの実行の詳細を取得できます。

# get the latest 10 executions run
$jobAgent | Get-AzSqlElasticJobExecution -Count 10

# get the job step execution details
$jobExecution | Get-AzSqlElasticJobStepExecution

# get the job target execution details
$jobExecution | Get-AzSqlElasticJobTargetExecution -Count 2

可能なジョブの実行状態を次の表に示します。

State 説明
Created ジョブの実行は作成されたばかりで、まだ進行中ではありません。
InProgress ジョブの実行は現在進行中です。
WaitingForRetry ジョブ実行はそのアクションを完了できず、再試行を待機しています。
Succeeded ジョブの実行は正常に完了しました。
SucceededWithSkipped ジョブの実行は正常に完了しましたが、その子の一部がスキップされました。
Failed ジョブの実行は失敗し、再試行回数の上限に達しました。
TimedOut ジョブの実行はタイムアウトしました。
Canceled ジョブの実行は取り消されました。
Skipped 同じジョブ手順の別の実行が同じターゲットに対して既に実行されていたため、ジョブの実行はスキップされました。
WaitingForChildJobExecutions ジョブの実行は、その子の実行が完了するまで待機しています。

リソースをクリーンアップする

リソース グループを削除して、このチュートリアルで作成した Azure リソースを削除します。

ヒント

引き続きこれらのジョブを使用する場合は、この記事で作成したリソースをクリーンアップしないでください。

Remove-AzResourceGroup -ResourceGroupName $resourceGroupName

次のステップ