Dataverse Web API で PowerShell と Visual Studio Code を使う

この記事は、PowerShell を使ったクイックスタート Web API 記事を展開し、 Dataverse Web API を持つ PowerShell と Visual Studio Code を使った詳細期のを説明します。

注意

この記事の手順は Windows、Linux、macOS で機能するはずですが、これらの手順は Windows でのみテストされています。 変更が必要な場合は、この記事の下部にある フィードバック セクションを使用してお知らせください。

前提条件

この記事の内容は、PowerShell を使用した Web API クイック スタート の記事と同じ前提条件があります。

以下をインストールするか、インストールされていることを確認する

インストールを検証する

  1. Visual Studio Code を開きます。

  2. ターミナル メニューで、新規ターミナル を選択します。

  3. Visual Studio Code ナビゲーション ウィンドウで、PowerShell 拡張子の アイコンを選択します。

  4. Visual Studio Code ターミナル ウィンドウで、次のスクリプトをコピーして貼り付けます。

    Write-Host 'PowerShell Version:'$PSVersionTable.PSVersion.ToString()
    Write-Host 'PowerShell Az version:'(Get-InstalledModule Az).Version
    
  5. Enter キーを押します。 出力は、次の例のようになります。

    PowerShell Version: 7.4.0
    PowerShell Az version: 11.1.0
    

このような結果が表示されない場合は、前提条件をインストールまたは更新してください。

さらに必要なこと

  • Dataverse 環境に有効なユーザー アカウント
  • 接続に使用したい Dataverse 環境への URL。 検索方法については、開発者向けリソースを表示 をご覧ください。 次のようになります: https://yourorg.crm.dynamics.com/、これは yourorg.crm が異なります。
  • PowerShell スクリプト言語の基本的な解釈

再利用可能な関数を作成する

PowerShell を使用したクイック スタート Web API では、コードを使用して WhoAmI関数 Visual Studio を認証して呼び出す方法を紹介しました。 1 つ以上の操作のアドホック テストに必要なのは、このアプローチだけである可能性があります。 ただし、スクリプトが複雑になると、同じコードを何度も入力することになる場合があります。

このセクションでは、ドット ソーシング を使用してアクセスできる個別のファイルに再利用可能な関数のセットの作成を開始します。 ドット ソーシングを使用して、ローカル スクリプト スコープの一部となる関数と変数を含むことができる PowerShell スクリプトを含むファイルを読み込みます。

ヒント

これらの関数の完全に文書化された定義などは、PowerApps-Samples/dataverse/webapi/PS/GitHub PowerApps-Samples リポジトリ

接続機能の作成

Dataverse を認証するコードを、Connect という名前のファイル内の Core.ps1 という関数に配置して、1 行のコードで再利用できるようにしましょう。

  1. フォルダーを作成します。 この例では、C:\scripts というフォルダーを作成します。

  2. Visual Studio Code を使ってスクリプト フォルダーを開く.

  3. Core.ps1という名前のスクリプト フォルダーにテキスト ファイルを作成します。

  4. 以下の Connect 関数を Core.ps1 ファイルにコピーし貼り付けます。

    function Connect {
       param (
          [Parameter(Mandatory)] 
          [String] 
          $uri
       )
    
       ## Login interactively if not already logged in
       if ($null -eq (Get-AzTenant -ErrorAction SilentlyContinue)) {
          Connect-AzAccount | Out-Null
       }
    
       # Get an access token
       $token = (Get-AzAccessToken -ResourceUrl $uri).Token
    
       # Define common set of headers
       $global:baseHeaders = @{
          'Authorization'    = 'Bearer ' + $token
          'Accept'           = 'application/json'
          'OData-MaxVersion' = '4.0'
          'OData-Version'    = '4.0'
       }
    
       # Set baseURI
       $global:baseURI = $uri + 'api/data/v9.2/'
    }
    

    注意

    このスクリプトは、baseURIbaseHeaders 変数を $global スコープ修飾子 ウィtyじゃってグローバル コンテキストに追加し、同じセッション内で他のスクリプトで使用できるようにします。

  5. 自分の scripts フォルダーで test.ps1 という名前の Visual Studio Code を使用して、フォルダに別のテキスト ファイルを作成します。

  6. 以下のスクリプトを test.ps1 ファイルにコピーし貼り付けます。

    . $PSScriptRoot\Core.ps1
    
    Connect 'https://yourorg.crm.dynamics.com/' # change this
    # Invoke WhoAmI Function
    Invoke-RestMethod -Uri ($baseURI + 'WhoAmI') -Method Get -Headers $baseHeaders
    | ConvertTo-Json
    

    ファイルの先頭にある . $PSScriptRoot\Core.ps1 は、ドット ソースを使ってスクリプトにそのファイルの内容を読み込ませることを示しています。

    環境の URL に一致するように https://yourorg.crm.dynamics.com/ 値を変更してください。

  7. F5 キーを押してスクリプトを実行します。

    出力は次のようになります。

    PS C:\scripts> . 'C:\scripts\test.ps1'
    {
    "@odata.context": "https://yourorg.crm.dynamics.com/api/data/v9.2/$metadata#Microsoft.Dynamics.CRM.WhoAmIResponse",
    "BusinessUnitId": "3a277578-5996-ee11-be36-002248227994",
    "UserId": "2c2e7578-5996-ee11-be36-002248227994",
    "OrganizationId": "97bf0e8b-aa99-ee11-be32-000d3a106c3a"
    }
    

WhoAmI 関数の作成

WhoAmI 関数 を呼び出すコードを、Get-WhoAmI という名前のファイル内の CommonFunctions.ps1 という関数に配置して、WhoAmI 関数 を使用する場合は、毎回 100 文字ではなく 11 文字を使用します。

  1. CommonFunctions.ps1 という名前の scripts フォルダーに新規テキスト ファイルを作成します。

  2. CommonFunctions.ps1 で次の関数定義をコピーして貼り付けます。

    function Get-WhoAmI{
    
       $WhoAmIRequest = @{
          Uri = $baseURI + 'WhoAmI'
          Method = 'Get'
          Headers = $baseHeaders
       }
    
       Invoke-RestMethod @WhoAmIRequest
    }
    

    注意

    この関数定義では、スプラッティング と呼ばれる手法を使用します。 スプラッティングにより、パラメーター値のコレクションが 1 つの単位としてコマンドに渡されるため、コマンドが短くなり、読みやすくなります。

  3. CommonFunctions.ps1 ファイルを保存します。

  4. test.ps1 ファイルを編集し、内容を次のスクリプトのように変更します。

    . $PSScriptRoot\Core.ps1
    . $PSScriptRoot\CommonFunctions.ps1
    
    Connect 'https://yourorg.crm.dynamics.com/' # change this
    # Invoke WhoAmI Function
    Get-WhoAmI | ConvertTo-Json
    

    環境の URL に一致するように https://yourorg.crm.dynamics.com/ 値を変更してください。

  5. F5 キーを押してスクリプトを実行します。

    出力は以前とまったく同じになるはずです。

テーブル操作関数の作成

共通のテーブル操作を実行する関数を TableOperations.ps1 という名前のファイルに配置して、再利用できるようにしましょう。

  1. TableOperations.ps1 という名前の scripts フォルダーに新規テキスト ファイルを作成します。

  2. TableOperations.ps1 で次の関数定義をコピーして貼り付けます。

    function Get-Records {
       param (
          [Parameter(Mandatory)] 
          [String] 
          $setName,
          [Parameter(Mandatory)] 
          [String] 
          $query
       )
       $uri = $baseURI + $setName + $query
       # Header for GET operations that have annotations
       $getHeaders = $baseHeaders.Clone()
       $getHeaders.Add('If-None-Match', $null)
       $getHeaders.Add('Prefer', 'odata.include-annotations="*"')
       $RetrieveMultipleRequest = @{
          Uri     = $uri
          Method  = 'Get'
          Headers = $getHeaders
       }
       Invoke-RestMethod @RetrieveMultipleRequest
    }
    
    function New-Record {
       param (
          [Parameter(Mandatory)] 
          [String] 
          $setName,
          [Parameter(Mandatory)] 
          [hashtable]
          $body
       )
       $postHeaders = $baseHeaders.Clone()
       $postHeaders.Add('Content-Type', 'application/json')
    
       $CreateRequest = @{
          Uri     = $baseURI + $setName
          Method  = 'Post'
          Headers = $postHeaders
          Body    = ConvertTo-Json $body
       }
       Invoke-RestMethod @CreateRequest -ResponseHeadersVariable rh | Out-Null
       $url = $rh['OData-EntityId']
       $selectedString = Select-String -InputObject $url -Pattern '(?<=\().*?(?=\))'
       return [System.Guid]::New($selectedString.Matches.Value.ToString())
    }
    
    function Get-Record {
       param (
          [Parameter(Mandatory)] 
          [String] 
          $setName,
          [Parameter(Mandatory)] 
          [Guid] 
          $id,
          [String] 
          $query
       )
       $uri = $baseURI + $setName
       $uri = $uri + '(' + $id.Guid + ')' + $query
       $getHeaders = $baseHeaders.Clone()
       $getHeaders.Add('If-None-Match', $null)
       $getHeaders.Add('Prefer', 'odata.include-annotations="*"')
       $RetrieveRequest = @{
          Uri     = $uri
          Method  = 'Get'
          Headers = $getHeaders
       }
       Invoke-RestMethod @RetrieveRequest
    }
    
    function Update-Record {
       param (
          [Parameter(Mandatory)] 
          [String] 
          $setName,
          [Parameter(Mandatory)] 
          [Guid] 
          $id,
          [Parameter(Mandatory)] 
          [hashtable]
          $body
       )
       $uri = $baseURI + $setName
       $uri = $uri + '(' + $id.Guid + ')'
       # Header for Update operations
       $updateHeaders = $baseHeaders.Clone()
       $updateHeaders.Add('Content-Type', 'application/json')
       $updateHeaders.Add('If-Match', '*') # Prevent Create
       $UpdateRequest = @{
          Uri     = $uri
          Method  = 'Patch'
          Headers = $updateHeaders
          Body    = ConvertTo-Json $body
       }
       Invoke-RestMethod @UpdateRequest
    }
    
    function Remove-Record {
       param (
          [Parameter(Mandatory)] 
          [String]
          $setName,
          [Parameter(Mandatory)] 
          [Guid] 
          $id
       )
       $uri = $baseURI + $setName
       $uri = $uri + '(' + $id.Guid + ')'
       $DeleteRequest = @{
          Uri     = $uri
          Method  = 'Delete'
          Headers = $baseHeaders
       }
       Invoke-RestMethod @DeleteRequest
    }
    
    

    これらのリクエストの作成方法の詳細については、次の記事にアクセスしてください。

  3. TableOperations.ps1 ファイルを保存します。

  4. 次のコードをコピーして、test.ps1 ファイルに貼り付けます。

    . $PSScriptRoot\Core.ps1
    . $PSScriptRoot\CommonFunctions.ps1
    . $PSScriptRoot\TableOperations.ps1
    
    Connect 'https://yourorg.crm.dynamics.com/' # change this
    
    # Retrieve Records
    Write-Host 'Retrieve first three account records:'
    (Get-Records `
       -setName accounts `
       -query '?$select=name&$top=3').value | 
    Format-Table -Property name, accountid
    
    # Create a record
    Write-Host 'Create an account record:'
    $newAccountID = New-Record `
       -setName accounts `
       -body @{
          name                = 'Example Account'; 
          accountcategorycode = 1 # Preferred
       }
    Write-Host "Account with ID $newAccountID created"
    
    # Retrieve a record
    Write-Host 'Retrieve the created record:'
    Get-Record `
       -setName  accounts `
       -id $newAccountID.Guid '?$select=name,accountcategorycode' |
    Format-List -Property name,
    accountid,
    accountcategorycode,
    accountcategorycode@OData.Community.Display.V1.FormattedValue
    
    # Update a record
    Write-Host 'Update the record:'
    $updateAccountData = @{
       name                = 'Updated Example account';
       accountcategorycode = 2; #Standard
    }
    Update-Record `
       -setName accounts `
       -id $newAccountID.Guid `
       -body $updateAccountData
    Write-Host 'Retrieve the updated the record:'
    Get-Record `
       -setName accounts `
       -id  $newAccountID.Guid `
       -query '?$select=name,accountcategorycode' |
    Format-List -Property name,
    accountid,
    accountcategorycode,
    accountcategorycode@OData.Community.Display.V1.FormattedValue
    
    # Delete a record
    Write-Host 'Delete the record:'
    Remove-Record `
       -setName accounts `
       -id $newAccountID.Guid
    Write-Host "The account with ID $newAccountID was deleted"
    

    環境の URL に一致するように https://yourorg.crm.dynamics.com/ 値を変更してください。

  5. F5 キーを押してスクリプトを実行します。

    出力は次のようになります。

    PS C:\scripts> . 'C:\scripts\test.ps1'
    Retrieve first three account records:
    
    name                     accountid
    ----                     ---------
    Fourth Coffee (sample)   d2382248-cd99-ee11-be37-000d3a9b7981
    Litware, Inc. (sample)   d4382248-cd99-ee11-be37-000d3a9b7981
    Adventure Works (sample) d6382248-cd99-ee11-be37-000d3a9b7981
    
    Create an account record:
    Account with ID  a2c3ebc2-39a8-ee11-be37-000d3a8e8e07 created
    Retrieve the created record:
    
    name                                                          : Example Account
    accountid                                                     : a2c3ebc2-39a8-ee11-be37-000d3a8e8e07
    accountcategorycode                                           : 1
    accountcategorycode@OData.Community.Display.V1.FormattedValue : Preferred Customer
    
    Update the record:
    
    Retrieve the updated the record:
    
    name                                                          : Updated Example account
    accountid                                                     : a2c3ebc2-39a8-ee11-be37-000d3a8e8e07
    accountcategorycode                                           : 2
    accountcategorycode@OData.Community.Display.V1.FormattedValue : Standard
    
    Delete the record:
    
    The account with ID  a2c3ebc2-39a8-ee11-be37-000d3a8e8e07 was deleted
    

例外処理

この記事ではこれまで、提供されたコードをコピーして貼り付けてきました。 しかし、独自の関数を作成して使用し始めると、エラーが発生します。 これらのエラーが発生した場合、Dataverse が原因であるか、スクリプトが原因である可能性があります。

エラーの原因を検出し、Dataverse によって返されたエラーから関連する詳細を抽出するのに役立つヘルパー関数を追加しましょう。

  1. Core.ps1 ファイルを編集して、次の Invoke-DataverseCommands 関数に追加します。

    function Invoke-DataverseCommands {
       param (
          [Parameter(Mandatory)] 
          $commands
       )
       try {
          Invoke-Command $commands
       }
       catch [Microsoft.PowerShell.Commands.HttpResponseException] {
          Write-Host "An error occurred calling Dataverse:" -ForegroundColor Red
          $statuscode = [int]$_.Exception.StatusCode;
          $statusText = $_.Exception.StatusCode
          Write-Host "StatusCode: $statuscode ($statusText)"
          # Replaces escaped characters in the JSON
          [Regex]::Replace($_.ErrorDetails.Message, "\\[Uu]([0-9A-Fa-f]{4})", 
             {[char]::ToString([Convert]::ToInt32($args[0].Groups[1].Value, 16))} )
    
       }
       catch {
          Write-Host "An error occurred in the script:" -ForegroundColor Red
          $_
       }
    }
    

    Invoke-DataverseCommands 関数は、Invoke-Command コマンドレット を使用して、try/catch ブロック 内の一連のコマンドを処理します。 Dataverse から返されるエラーはすべて HttpResponseException エラーであるため、最初の catch ブロックはJSONエラー データを含む An error occurred calling Dataverse: メッセージを端末に書き込みます。

    $_.ErrorDetails.Message の JSON データには、エスケープされた Unicode 文字が含まれています。 たとえば、& の代わりに \u0026' の代わりに \u0027。 この関数には、他の場所で発生するエラーと正確に一致するように、これらの文字をエスケープされていない文字に置き換えるコードが含まれています。

    それ以外の場合、エラーは次のメッセージとともに端末ウィンドウに書き戻されます: An error occurred in the script:

  2. Core.ps1 ファイルを保存します。

  3. 無効な test.ps1 パラメータ値を使用する次のスクリプトを使用するように setName ファイルを編集します。 accountaccounts である必要があります。 これは共通エラーです。

    . $PSScriptRoot\Core.ps1
    . $PSScriptRoot\CommonFunctions.ps1
    . $PSScriptRoot\TableOperations.ps1
    
    Connect 'https://yourorg.crm.dynamics.com/' # change this
    
    Invoke-DataverseCommands {
    
       # Retrieve Records
       Write-Host 'Retrieve first three account records:'
          (Get-Records `
          -setName account `
          -query '?$select=name&$top=3').value | 
       Format-Table -Property name, accountid
    
    }
    

    環境の URL に一致するように https://yourorg.crm.dynamics.com/ 値を変更してください。

  4. F5 キーを押してスクリプトを実行します。

    出力は次のようになります。

    PS C:\scripts> . 'C:\scripts\test.ps1'
    Retrieve first three account records:
    An error occurred calling Dataverse:
    StatusCode: 404 (NotFound)
    
    {
    "error": {
       "code": "0x80060888",
       "message": "Resource not found for the segment 'account'."
       }
    }
    
  5. test.ps1 ファイルを編集して、Invoke-DataverseCommands ブロック内でスクリプト エラーをスローします。

    Invoke-DataverseCommands {
    
       throw 'A script error'
    
    }
    
  6. F5 キーを押してスクリプトを実行します。

    出力は、Invoke-DataverseCommands ブロックに含まれていない場合とほぼ同じになるはずです。

    PS C:\scripts> . 'C:\scripts\test.ps1'
    An error occurred in the script:
    Exception: C:\scripts\test.ps1:8:4
    Line |
       8 |     throw 'A script error'
         |     ~~~~~~~~~~~~~~~~~~~~~~
         | A script error
    

Dataverse サービス保護の制限を管理する

Dataverse サービス保護APIの制限 により、Dataverse は一貫した可用性とパフォーマンスを提供することが確保されます。 クライアント アプリケーションが Web API を使用してサーバー リソースに対して異例の要求を行うと、Dataverse 429 リクエストが多すぎます エラーが返され、Retry-After ヘッダー で指定された クライアント アプリケーションはその間操作を一時停止する必要があります。

PowerShell Invoke-RestMethod コマンドレット MinimumRetryCount パラメータ は、失敗コードが 400 ~ 599 または 304 が受信されえた場合に PowerShell がリクエストを再試行する回数を指定します。 これは、このパラメーターの値を含めると、PowerShell が Dataverse サービス保護 429 エラーを再試行することを意味します。 MaximumRetryCount パラメータは、再試行間隔秒 を使用して待機する秒数を指定します。 既定値は 5 秒です。 エラー応答に次のものが含まれる場合、 429 エラーの Retry-After ヘッダー: Dataverse サービス保護エラーが発生した場合は、その値が代わりに使用されます。

PowerShell を使用した Dataverse Web API。の使用方法を学習している間は、サービス保護制限エラーが発生しない可能性があります。 作成したスクリプトは、これらのエラーの発生に必要な多数のリクエストを送信するために使用される可能性があるため、エラーが発生する可能性があることと、PowerShell を使用してエラーを管理する方法を知っておく必要があります。

MaximumRetryCount パラメータを Invoke-RestMethod を使用して各 Dataverse 通話に追加すると、PowerShell は広範囲のエラーを再試行します。 エラーが発生するたびに再試行すると、特に開発時やテスト時にスクリプトが遅くなります。 指定した再試行回数に応じて、エラーが発生するたびに 10 ~ 15 秒待つ必要があります。 別のアプローチは、特定のエラーに対する再試行を管理する独自のメソッドで Invoke-RestMethod をカプセル化します。

次の Invoke-ResilientRestMethod 関数は、必須パラメータおよびブール値 returnHeader フラグとしての request hashtableオブジェクトを取って応答ヘッダーを返すかどうかを示します。 $returnHeader が true の場合、Invoke-RestMethod コマンドと ResponseHeadersVariable パラメータを使用してリクエストを送信し、返されたヘッダーをキャプチャします。また、Out-Null を使用して、空のレスポンス本文を表す出力が関数で返されないようにします。 それ以外の場合、関数は Invoke-RestMethod オブジェクトを使用して request リクエストを送信し、レスポンス本文を返します。

Invoke-RestMethod が 429 エラーで失敗した場合は、request オブジェクトに MaximumRetryCount プロパティがあるかどうかを確認します。 ない場合は、3 の値で追加します。 次に、リクエスト オブジェクトと Retry-After の応答ヘッダー値を使って Invoke-RestMethod を再試行 します。 returnHeader フラグが true の場合、応答ヘッダーを返します。 Invoke-RestMethod がその他のエラーで失敗した場合は、例外が再スローされます。

function Invoke-ResilientRestMethod {
   param (
      [Parameter(Mandatory)] 
      $request,
      [bool]
      $returnHeader
   )
   try {
      if ($returnHeader) {
         Invoke-RestMethod @request -ResponseHeadersVariable rhv | Out-Null
         return $rhv
      }
      Invoke-RestMethod @request
   }
   catch [Microsoft.PowerShell.Commands.HttpResponseException] {
      $statuscode = $_.Exception.Response.StatusCode
      # 429 errors only
      if ($statuscode -eq 'TooManyRequests') {
         if (!$request.ContainsKey('MaximumRetryCount')) {
            $request.Add('MaximumRetryCount', 3)
            # Don't need - RetryIntervalSec
            # When the failure code is 429 and the response includes the Retry-After property in its headers, 
            # the cmdlet uses that value for the retry interval, even if RetryIntervalSec is specified
         }
         # Will attempt retry up to 3 times
         if ($returnHeader) {
            Invoke-RestMethod @request -ResponseHeadersVariable rhv | Out-Null
            return $rhv
         }
         Invoke-RestMethod @request
      }
      else {
         throw $_
      }
   }
   catch {
      throw $_
   }
}

このような関数を再利用可能な関数で使用できます。 関数が応答のヘッダーから値を返す必要がある場合、関数は returnHeader 値を $true に設定する必要があります。 たとえば、次の New-Record 関数は、テーブル操作関数の作成 のサンプル関数を変更して、直接 Invoke-RestMethod の代わりに Invoke-ResilientRestMethod を使用します。

function New-Record {
   param (
      [Parameter(Mandatory)] 
      [String] 
      $setName,
      [Parameter(Mandatory)] 
      [hashtable]
      $body
   )
   $postHeaders = $baseHeaders.Clone()
   $postHeaders.Add('Content-Type', 'application/json')
   
   $CreateRequest = @{
      Uri     = $environmentUrl + 'api/data/v9.2/' + $setName
      Method  = 'Post'
      Headers = $postHeaders
      Body    = ConvertTo-Json $body

   }
   # Before: 
   # Invoke-RestMethod @CreateRequest -ResponseHeadersVariable rh | Out-Null

   # After:
   $rh = Invoke-ResilientRestMethod -request $CreateRequest -returnHeader $true
   $url = $rh['OData-EntityId']
   $selectedString = Select-String -InputObject $url -Pattern '(?<=\().*?(?=\))'
   return [System.Guid]::New($selectedString.Matches.Value.ToString())
}

それ以外の場合は、Invoke-ResilientRestMethod の例に示すように、この Get-Record 例に示されているように Invoke-RestMethod を置き換えます。

function Get-Record {
   param (
      [Parameter(Mandatory)] 
      [String] 
      $setName,
      [Parameter(Mandatory)] 
      [Guid] 
      $id,
      [String] 
      $query
   )
   $uri = $environmentUrl + 'api/data/v9.2/' + $setName
   $uri = $uri + '(' + $id.Guid + ')' + $query
   $getHeaders = $baseHeaders.Clone()
   $getHeaders.Add('If-None-Match', $null)
   $getHeaders.Add('Prefer', 'odata.include-annotations="*"')
   $RetrieveRequest = @{
      Uri     = $uri
      Method  = 'Get'
      Headers = $getHeaders
   }
   # Before:
   # Invoke-RestMethod @RetrieveRequest

   # After: 
   Invoke-ResilientRestMethod $RetrieveRequest
}

唯一の違いは、スプラッティング (@RetrieveRequest) を使用する代わりにハッシュテーブル ($RetrieveRequest) をメソッドに渡すことです。 そうしないと、次のスクリプト エラーが発生します: A parameter cannot be found that matches parameter name 'Headers'.

Fiddler を使用したデバッグ

Fiddler は、コンピューター上の HTTP トラフィックを表示するために使用される Web デバッグ プロキシです。 このデータを表示すると、スクリプトをデバッグするときに役立ちます。 デフォルトでは、Invoke-RestMethod コマンドレット を使用して送信された HTTP リクエストと応答は、Fiddler を使用して表示されません。

Fiddler を使用して HTTP トラフィックを表示するには、Invoke-RestMethod プロキシ パラメータ を、ローカル コンピュータ上で Fiddler プロキシとして構成されたURLに設定します。 既定では、URL は http://127.0.0.1:8888 です。 あなたのものは違うかもしれません。

たとえば、Fiddler がトラフィックをキャプチャしているときに、-Proxy パラメータセットで WhoAmI 関数 を呼び出すと、次のようになります:

Invoke-RestMethod `
   -Uri ($environmentUrl + 'api/data/v9.2/WhoAmI') `
   -Method Get `
   -Headers $baseHeaders `
   -Proxy 'http://127.0.0.1:8888'

Fiddler では、すべての詳細を確認できます。

GET https://yourorg.api.crm.dynamics.com/api/data/v9.2/WhoAmI HTTP/1.1
Host: yourorg.api.crm.dynamics.com
OData-MaxVersion: 4.0
Accept: application/json
Authorization: Bearer [REDACTED]
OData-Version: 4.0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Microsoft Windows 10.0.22631; en-US) PowerShell/7.4.0
Accept-Encoding: gzip, deflate, br


HTTP/1.1 200 OK
Cache-Control: no-cache
Allow: OPTIONS,GET,HEAD,POST
Content-Type: application/json; odata.metadata=minimal
Expires: -1
Vary: Accept-Encoding
x-ms-service-request-id: 7341c0c1-3343-430b-98ea-292567ed4776
Set-Cookie: ARRAffinity=f60cbee43b7af0a5f322e7ce57a018546ed978f67f0c11cbb5e15b02ddb091a915134d20c556b0b34b9b6ae43ec3f5dcdad61788de889ffc592af7aca85fc1c508DC0FC94CB062A12107345846; path=/; secure; HttpOnly
Set-Cookie: ReqClientId=4fc95009-0b3d-4a19-b223-0d80745636ac; expires=Sun, 07-Jan-2074 21:10:42 GMT; path=/; secure; HttpOnly
Set-Cookie: orgId=648e8efd-db86-466e-a5bc-a4d5eb9c52d4; expires=Sun, 07-Jan-2074 21:10:42 GMT; path=/; secure; HttpOnly
x-ms-service-request-id: 1ee13aa7-47f3-4a75-95fa-2916775a1f79
Strict-Transport-Security: max-age=31536000; includeSubDomains
REQ_ID: 1ee13aa7-47f3-4a75-95fa-2916775a1f79
CRM.ServiceId: framework
AuthActivityId: 0b562cc3-56f6-44f0-a26e-4039cfc4be6a
x-ms-dop-hint: 48
x-ms-ratelimit-time-remaining-xrm-requests: 1,200.00
x-ms-ratelimit-burst-remaining-xrm-requests: 5999
OData-Version: 4.0
X-Source: 110212218438874147222728177124203420477168182861012399121919014511175711948418152
Public: OPTIONS,GET,HEAD,POST
Set-Cookie: ARRAffinity=f60cbee43b7af0a5f322e7ce57a018546ed978f67f0c11cbb5e15b02ddb091a915134d20c556b0b34b9b6ae43ec3f5dcdad61788de889ffc592af7aca85fc1c508DC0FC94CB062A12107345846; path=/; secure; HttpOnly
X-Source: 2302101791355821068628523819830862152291172232072372448021147103846182145238216119
Date: Sun, 07 Jan 2024 21:10:42 GMT
Content-Length: 277

{"@odata.context":"https://yourorg.api.crm.dynamics.com/api/data/v9.2/$metadata#Microsoft.Dynamics.CRM.WhoAmIResponse","BusinessUnitId":"1647bf36-e90a-4c4d-9b61-969d57ce7a66","UserId":"24e34f5e-7f1a-43fe-88da-7e4b862d51ad","OrganizationId":"648e8efd-db86-466e-a5bc-a4d5eb9c52d4"}

Fiddler が実行されていない場合は、次のようなエラーが表示されます。

Invoke-RestMethod: C:\scripts\test.ps1:8:1
Line |
   8 |  Invoke-RestMethod `
     |  ~~~~~~~~~~~~~~~~~~~
     | No connection could be made because the target machine actively refused it.

Dataverse サービス保護制限の管理 で説明されている Invoke-ResilientRestMethod のような単一関数経由ですべての Invoke-RestMethod 通話をルートすることを選択する場合、Core.ps1 ファイルでいくつかの変数を設定して、このオプションを単一場所で構成できます。

# <a name="set-to-true-only-while-debugging-with-fiddler"></a>Set to true only while debugging with Fiddler
$debug = $true
# <a name="set-this-value-to-the-fiddler-proxy-url-configured-on-your-computer"></a>Set this value to the Fiddler proxy URL configured on your computer
$proxyUrl = 'http://127.0.0.1:8888'

そして、Fiddler でデバッグするときだけ、$request ハッシュ テーブルを使ったスプラッティングを使って、集中化した関数内で -Proxy パラメーターを設定することができます。

function Invoke-ResilientRestMethod {
   param (
      [Parameter(Mandatory)] 
      $request,
      [bool]
      $returnHeader
   )

   if ($debug) {
      $request.Add('Proxy', $proxyUrl)
   }

   ...

Fiddler を使用した Web トラフィックのキャプチャについて学ぶ

Dataverse Web API CSDL $metadata ドキュメントをダウンロードする

CSDL $metadata は、 Dataverse Web API 機能に関する真実の情報源です。 ブラウザで表示することもできますが、ファイルをダウンロードして Visual Studio Code 内で表示する方が簡単かもしれません。 次のスクリプトは、PowerShell を使用したクイック スタート Web API で紹介されたスクリプトの修正バージョンです。 違いは、XML ドキュメントのダウンロードにより適した Invoke-WebRequest コマンドレット を使用することです。

$environmentUrl = 'https://yourorg.crm.dynamics.com/' # change this
$writeFileTo =  'C:\temp\yourorg.xml' # change this

## <a name="login-if-not-already-logged-in"></a>Login if not already logged in
if ($null -eq (Get-AzTenant -ErrorAction SilentlyContinue)) {
   Connect-AzAccount | Out-Null
}
# <a name="get-an-access-token"></a>Get an access token
$token = (Get-AzAccessToken -ResourceUrl $environmentUrl).Token
# <a name="common-headers"></a>Common headers
$xmlHeaders = @{
   'Authorization'    = 'Bearer ' + $token
   'Accept'           = 'application/xml'
   'OData-MaxVersion' = '4.0'
   'OData-Version'    = '4.0'
}

$doc = [xml](Invoke-WebRequest `
      -Uri ($environmentUrl + 'api/data/v9.2/$metadata?annotations=true') `
      -Method 'Get' `
      -Headers $xmlHeaders ).Content

$StringWriter = New-Object System.IO.StringWriter
$XmlWriter = New-Object System.XMl.XmlTextWriter $StringWriter
$xmlWriter.Formatting = 'indented'
$xmlWriter.Indentation = 2
$doc.WriteContentTo($XmlWriter)
$XmlWriter.Flush()
$StringWriter.Flush()
Set-Content -Path $writeFileTo -Value $StringWriter.ToString()
code $writeFileTo
  1. スクリプトをコピーします。
  2. 必要に応じて $environmentUrl 変数と $writeFileTo 変数を編集します。
  3. スクリプトを Visual Studio Code で実行します。

Dataverse Web API CSDL $metadata ドキュメントは Visual Studio Code で開きます。

おそらく次のような通知が届くでしょう。

パフォーマンス上の理由から、ドキュメント シンボルは 5000 項目に制限されています。 新しい制限が設定されている場合は、このファイルを閉じて再度開き、ドキュメント シンボルを再計算してください。

この通知には、Visual Studio XML 拡張 xml.symbols.maxItemsComputed 制限を変更するオプションが表示されます。 ほとんどの Dataverse Web API CSDL $metadata ドキュメントでは、制限を 500000 に設定するだけで十分です。

トラブルシューティング​​

このセクションには、発生する可能性のある問題に関するガイダンスが含まれています。

エラー ダイアログ: ENOENT\\.\pipe\<RANDOM_text> を 'launch.json' を開くボタンで接続します

このエラーは、Visual Studio Code を使用してデバッグするときに発生することがあります。 解決するには:

  1. Visual Studio Code メニューから表示 > コマンド パレット... を選択するか、Ctrl+シフト+P キーを押します。
  2. restart をタイプして、Powershell: Restart session を選択します。 詳細については、PowerShell/vscode-powershell GitHub Issue 4332 を参照してください。

次の手順

サービス ドキュメントを理解することで、Dataverse Web API 機能の詳細を学びます。

サンプルコードを確認して実行します。