次の方法で共有


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 では、Visual Studio Code で WhoAmI 関数 を認証して呼び出す方法が導入されました。 この方法は、1 つ以上の操作のアドホック テストに必要な場合があります。 ただし、スクリプトが複雑になるにつれて、同じコードを何度も入力する場合があります。

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

ヒント

これらの関数の完全に文書化された定義については、GitHub PowerApps-Samples リポジトリPowerApps-Samples/dataverse/webapi/PS/ で確認できます。

Connect 関数を作成する

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

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

  2. Visual Studio Code 内の scripts フォルダーを開きます

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

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

    function Connect {
       param (
          [Parameter(Mandatory)] 
          [String] 
          $environmentUrl
       )
    
       ## Login interactively if not already logged in
       if ($null -eq (Get-AzTenant -ErrorAction SilentlyContinue)) {
          Connect-AzAccount | Out-Null
       }
    
       # Get an access token
       $secureToken = (Get-AzAccessToken `
          -ResourceUrl $environmentUrl `
          -AsSecureString).Token
    
       # Convert the secure token to a string
       $token = ConvertFrom-SecureString `
          -SecureString $secureToken `
          -AsPlainText
    
       # 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 = $environmentUrl + 'api/data/v9.2/'
    }
    

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

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

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

    . $PSScriptRoot\Core.ps1
    
    Connect 'https://yourorg.crm.dynamics.com/' # change to your organization
    # 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": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff",
    "UserId": "22cc22cc-dd33-ee44-ff55-66aa66aa66aa",
    "OrganizationId": "00aa00aa-bb11-cc22-dd33-44ee44ee44ee"
    }
    

WhoAmI 関数を作成する

WhoAmI 関数を使用するたびに 100 文字ではなく 11 文字だけ入力できるように、Get-WhoAmI という名前のファイル内の CommonFunctions.ps1 という関数に WhoAmI 関数を呼び出すコードを配置しましょう。

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

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

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

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

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

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

    . $PSScriptRoot\Core.ps1
    . $PSScriptRoot\CommonFunctions.ps1
    
    Connect 'https://yourorg.crm.dynamics.com/' # change to your organization
    # 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 to your organization
    
    # 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. Invoke-DataverseCommands ファイルに次のCore.ps1関数を追加します。

    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 パラメーター値を使用する次のスクリプトを追加します。 account パラメーターはaccountsする必要があります。 このエラーは一般的です

    . $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 コマンドレットMaximumRetryCount パラメーター は、エラー コードが 400 ~ 599 (304 を含む) の間で受信されたときに PowerShell が要求を再試行する回数を指定します。 つまり、このパラメーターの値を含めると、PowerShell は Dataverse サービス保護 429 エラーを再試行します。 MaximumRetryCount パラメーターを RetryIntervalSec と共に使用して、待機する秒数を指定できます。 既定値は 5 秒です。 Dataverse サービス保護エラーのように、エラー応答に 429 エラーの Retry-After ヘッダーが含まれている場合は、代わりにその値が使用されます。

PowerShell で Dataverse Web API を使用する方法を学習しているときに、サービス保護の制限エラーが発生することはありません。 ただし、作成したスクリプトは、エラーを生成する多数の要求を送信する可能性があるため、PowerShell を使用して最適に管理する方法について説明します。

MaximumRetryCountを使用してすべての Dataverse 呼び出しに Invoke-RestMethod パラメーターを追加すると、PowerShell はさまざまなエラーを再試行します。 すべてのエラーを再試行すると、特に開発とテスト時にスクリプトが遅くなります。 指定した再試行回数に応じて、エラーが発生するたびに 10 ~ 15 秒待つ必要があります。 別の方法として、特定のエラーの再試行を管理する独自の方法で Invoke-RestMethod をカプセル化することもできます。

次の Invoke-ResilientRestMethod 関数は、 request ハッシュテーブル オブジェクトを必須パラメーターとして受け取り、ブール型の returnHeader フラグを使用して応答ヘッダーを返すかどうかを示します。 $returnHeaderが true の場合、Invoke-RestMethod コマンドと ResponseHeadersVariable パラメーターを使用して要求を送信し、返されたヘッダーをキャプチャします。 この関数は Out-Null を 使用するため、空の応答本文を表す出力は関数で返されません。 それ以外の場合、関数は、Invoke-RestMethod オブジェクトでrequestを使用して要求を送信し、応答本文を返します。

Invoke-RestMethodが 429 エラーで失敗した場合は、request オブジェクトに MaximumRetryCount プロパティがあるかどうかを確認します。 関数が成功すると、MaximumRetryCountに設定された3プロパティが作成されます。 Invoke-RestMethodは、要求オブジェクトとRetry-After応答ヘッダー値を使用して再試行されます。 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-ResilientRestMethod直接ではなくInvoke-RestMethodを使用します。

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

   }
   # 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例に示すように、Invoke-RestMethodGet-Recordを置き換えることができます。

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
   }
   # Before:
   # Invoke-RestMethod @RetrieveRequest

   # After: 
   Invoke-ResilientRestMethod $RetrieveRequest
}

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

Fiddler を使用したデバッグ

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

Fiddler で HTTP トラフィックを表示するには、 Invoke-RestMethodProxy パラメーター を、ローカル コンピューターで Fiddler プロキシとして構成された URL に設定します。 既定では、URL は http://127.0.0.1:8888。 URL が異なる場合があります。

たとえば、Fiddler がトラフィックをキャプチャしているときに、 パラメーターを設定して -Proxyを呼び出す場合は、次のようになります。

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=00aa00aa-bb11-cc22-dd33-44ee44ee44ee; 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":"11bb11bb-cc22-dd33-ee44-55ff55ff55ff","UserId":"22cc22cc-dd33-ee44-ff55-66aa66aa66aa","OrganizationId":"00aa00aa-bb11-cc22-dd33-44ee44ee44ee"}

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.

Invoke-RestMethodに関するページで説明されているInvoke-ResilientRestMethodなど、すべての呼び出しを 1 つの関数を介してルーティングすることを選択した場合は、Core.ps1 ファイルに一部の変数を設定して、このオプションを 1 つの場所に構成できます。

# Set to true only while debugging with Fiddler
$debug = $true
# Set this value to the Fiddler proxy URL configured on your computer
$proxyUrl = 'http://127.0.0.1:8888'

集中型関数内では、スプラッティングを使用して -Proxy パラメーターを設定し、Fiddler を使用してデバッグする場合にのみ、 $request ハッシュ テーブルを使用できます。

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 で導入されたスクリプトの変更バージョンです。 違いは、 Invoke-WebRequest コマンドレットを使用していることです。これは、XML ドキュメントをダウンロードする場合に適しています。

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

## Login if not already logged in
if ($null -eq (Get-AzTenant -ErrorAction SilentlyContinue)) {
   Connect-AzAccount | Out-Null
}
# Get an access token
$secureToken = (Get-AzAccessToken `
   -ResourceUrl $environmentUrl `
   -AsSecureString).Token

# Convert the secure token to a string
$token = ConvertFrom-SecureString `
   -SecureString $secureToken `
   -AsPlainText


# 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 で開きます。

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

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

トラブルシューティング

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

エラーダイアログ: Open 'launch.json' ボタンで ENOENT\\.\pipe\<RANDOM_text> に接続できませんでした。

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

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

次のステップ

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

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