Comparteix a través de


Use PowerShell y Visual Studio Code con la API web de Dataverse

Este artículo amplía el artículo Inicio rápido de API web con PowerShell para describir capacidades avanzadas usando PowerShell y Visual Studio Code con la API web de Dataverse para:

Nota

Las instrucciones de este artículo deberían funcionar para Windows, Linux y macOS, pero estos pasos solo se han probado en Windows. Si es necesario realizar cambios, háganoslo saber mediante la sección Comentarios al final de este artículo.

Requisitos previos

El contenido de este artículo tiene los mismos requisitos previos que el artículo Inicio rápido de API web con Powershell.

Instale o verifique que lo siguiente esté instalado

Verificar instalación

  1. Abra Visual Studio Code.

  2. En el menú Terminal, seleccione Nueva terminal.

  3. En el panel de navegación de Visual Studio Code, seleccione el icono para la extensión de PowerShell.

  4. Copie y pegue el script siguiente en la ventana de la terminal de Visual Studio Code:

    Write-Host 'PowerShell Version:'$PSVersionTable.PSVersion.ToString()
    Write-Host 'PowerShell Az version:'(Get-InstalledModule Az).Version
    
  5. Presione Entrar. El resultado debería similar al siguiente:

    PowerShell Version: 7.4.0
    PowerShell Az version: 11.1.0
    

Si no ve resultados como este, instale o actualice los requisitos previos.

También necesitará

  • Una cuenta de usuario válida para un entorno de Dataverse
  • La dirección URL al entorno de Dataverse al que quiere conectarse. Consulte Ver recursos para desarrolladores para saber cómo encontrarlo. Se parece a esto: https://yourorg.crm.dynamics.com/, donde yourorg.crm es diferente.
  • Comprensión básica de lenguaje de scripting PowerShell

Crear funciones reutilizables

Inicio rápido de API web con PowerShell presentó cómo autenticar y llamar a la función WhoAmI con Visual Studio Code. Este enfoque podría ser todo lo que necesita para una prueba ad hoc de una o más operaciones. Sin embargo, a medida que sus scripts se vuelven más complejos, es posible que se encuentre escribiendo el mismo código una y otra vez.

En esta sección, comenzamos a crear un conjunto de funciones reutilizables en archivos separados a los que podemos acceder usando dot sourcing. Utilice el origen de puntos para cargar un archivo que contenga scripts de PowerShell que puedan contener funciones y variables que pasen a formar parte del alcance del script local.

Sugerencia

Puede encontrar definiciones completamente documentadas de estas funciones y más en nuestro GitHub PowerApps- Repositorio de muestras en PowerApps-Samples/dataverse/webapi/PS/

Crear una función Connect

Pongamos el código para autenticarnos en Dataverse en una función llamada Connect dentro de un archivo llamado Core.ps1 para que podamos reutilizarlo en una sola línea de código.

  1. Cree una carpeta. En este ejemplo, creamos una carpeta en C:\scripts.

  2. Abra la carpeta de scripts dentro de Visual Studio Código.

  3. Cree un archivo de texto en la carpeta de scripts denominada Core.ps1.

  4. Copie y pegue la siguiente función Connect en el archivo 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/'
    }
    

    Nota

    El script agrega las variables baseURI y baseHeaders al contexto global usando el modificador de ámbito $global para que estén disponibles para otros scripts. en la misma sesión.

  5. Crea otro archivo de texto en código llamado Visual Studio en tu carpeta test.ps1 . scripts

  6. Copie y pegue el siguiente script en el archivo 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 en la parte superior del archivo se utiliza dot sourcing para indicarle al script que cargue el contenido de ese archivo.

    Recuerde cambiar https://yourorg.crm.dynamics.com/ para que coincida con la URL de su ambiente.

  7. Para ejecutar el script, presione F5.

    El resultado podría ser similar a este:

    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"
    }
    

Crear una función WhoAmI

Pongamos el código para invocar la función WhoAmI en una función llamada Get-WhoAmI dentro de un archivo llamado CommonFunctions.ps1 para que podamos escribir solo 11 caracteres en lugar de 100 cada vez que desee utilizar la función WhoAmI

  1. Cree un archivo de texto nuevo llamado CommonFunctions.ps1 en su carpeta scripts.

  2. Copie y pegue la siguiente definición de función en CommonFunctions.ps1.

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

    Nota

    Esta definición de función utiliza una técnica llamada splatting. Splatting hace que sus comandos sean más cortos y más fáciles de leer porque pasa una colección de valores de parámetros a un comando como una unidad.

  3. Guarde el archivo CommonFunctions.ps1.

  4. Cambie el archivo test.ps1 para que se parezca al siguiente script:

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

    Recuerde cambiar el valor https://yourorg.crm.dynamics.com/ para que coincida con la URL de su entorno.

  5. Para ejecutar el script, presione F5.

    La salida debería verse exactamente como antes.

Crear funciones de operaciones de tabla

Coloquemos funciones para realizar operaciones de tabla comunes en un archivo llamado TableOperations.ps1 para que podamos reutilizarlas.

  1. Cree un archivo de texto nuevo llamado TableOperations.ps1 en su carpeta scripts.

  2. Copie y pegue las siguientes definiciones de función en 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
    }
    
    

    Para obtener información acerca de cómo crear estas solicitudes, vea los artículos siguientes:

  3. Guarde el archivo TableOperations.ps1.

  4. Copie el siguiente código y péguelo en el cuadro archivo 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"
    

    Recuerde cambiar el valor https://yourorg.crm.dynamics.com/ para que coincida con la URL de su entorno.

  5. Para ejecutar el script, presione F5.

    El resultado podría ser similar a este:

    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
    

Administrar excepciones

Hasta ahora en este artículo copiaste y pegaste el código que te proporcionamos. Pero cuando comienzas a escribir y usar tus propias funciones, puedes encontrarte con errores. Cuando ocurren estos errores, es posible que se deban a Dataverse o a su script.

Agregue una función auxiliar que pueda ayudar a detectar la fuente de los errores y extraer detalles relevantes de los errores devueltos por Dataverse.

  1. Agregue la siguiente Invoke-DataverseCommands función al Core.ps1 archivo:

    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
          $_
       }
    }
    

    La función Invoke-DataverseCommands utiliza el cmdlet Invoke-Command para procesar un conjunto de comandos dentro de un bloque try/catch. Cualquier error devuelto por Dataverse son errores HttpResponseException, por lo que el primer bloque catch escribe un mensaje An error occurred calling Dataverse: en la terminal con los datos de error JSON.

    Los datos JSON en $_.ErrorDetails.Message contienen algunos caracteres Unicode escapados. Por ejemplo: \u0026 en lugar de & y \u0027 en lugar de '. Esta función incluye código que reemplaza esos caracteres con caracteres sin escape para que coincidan exactamente con los errores que ve en otros lugares.

    De lo contrario, los errores se escriben en la ventana del terminal con un mensaje: An error occurred in the script:

  2. Guarde el archivo Core.ps1.

  3. Edite el archivo test.ps1 para agregar el siguiente script que utiliza un valor de parámetro setName no válido. El parámetro account debe ser accounts. Este error es común.

    . $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
    
    }
    

    Recuerde cambiar el valor https://yourorg.crm.dynamics.com/ para que coincida con la URL de su entorno.

  4. Para ejecutar el script, presione F5.

    El resultado podría ser similar a este:

    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. Edite el archivo test.ps1 para generar un error de secuencia de comandos dentro del bloque Invoke-DataverseCommands:

    Invoke-DataverseCommands {
    
       throw 'A script error'
    
    }
    
  6. Para ejecutar el script, presione F5.

    El resultado debería ser casi el mismo que si no estuviera incluido en el bloque 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
    

Administrar límites de protección de servicio de Dataverse

Límites de API de protección de servicios de Dataverse ayudar a garantizar que Dataverse proporcione disponibilidad y rendimiento constantes. Cuando las aplicaciones cliente realizan demandas extraordinarias sobre los recursos del servidor mediante la API web, devuelve errores Dataverse 429 Demasiadas solicitudes y las aplicaciones cliente deben pausar las operaciones durante el tiempo especificado en el encabezado Retry-After .

El PowerShell Cmdlet Invoke-RestMethod Parámetro MaximumRetryCount especifica cuántas veces PowerShell reintenta una solicitud cuando se recibe un código de error entre 400 y 599, inclusive o 304. Esto significa que PowerShell reintenta errores de protección de servicio 429 de Dataverse cuando se incluye un valor para este parámetro. El parámetro MaximumRetryCount se puede utilizar con RetryIntervalSec para especificar el número de segundos de espera. El valor predeterminado es de 5 segundos. Si la respuesta de error incluye un encabezado Retry-After para un error 429, como hacen los errores de protección del servicio de Dataverse, en su lugar se utiliza ese valor.

Es posible que nunca encuentre un error de límite de protección del servicio mientras aprende a utilizar la API web de Dataverse con PowerShell. Sin embargo, los scripts que escribe pueden enviar una gran cantidad de solicitudes que producen errores, así que aprenda cómo administrarlos mejor usando PowerShell.

Si agrega el parámetro MaximumRetryCount a cada llamada a Dataverse usando Invoke-RestMethod, PowerShell reintenta una amplia gama de errores. Reintentar cada error hace que los scripts sean lentos, especialmente durante el desarrollo y las pruebas. Deberá esperar de 10 a 15 segundos cada vez que ocurra un error, dependiendo de cuántos reintentos especifique. Un enfoque alternativo es encapsular el Invoke-RestMethod en su propio método que gestiona los reintentos para errores específicos.

La siguiente función toma un objeto de tabla hash como parámetro obligatorio y un indicador booleano para indicar si se debe devolver o no el encabezado respuesta. Invoke-ResilientRestMethod request returnHeader Cuando $returnHeader es verdadero, envía la solicitud usando el comando Invoke-RestMethod con el parámetro ResponseHeadersVariable para capturar los encabezados devueltos. La función utiliza Out-Null , por lo que la salida que representa el cuerpo de la respuesta vacío no se devuelve con la función. De lo contrario, la función envía la solicitud utilizando Invoke-RestMethod con el objeto request y devuelve cuerpo de la respuesta.

Si el Invoke-RestMethod falla con un error 429, verifica si el objeto request tiene una propiedad MaximumRetryCount. Si la función tiene éxito, crea una propiedad MaximumRetryCount establecida en 3. Luego se vuelve a intentar utilizando el objeto de solicitud y el valor del encabezado respuesta. Invoke-RestMethod Retry-After Si el indicador returnHeader es verdadero, devuelve el encabezado de respuesta. Si Invoke-RestMethod falla con cualquier otro error, vuelve a lanzar la excepción.

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 $_
   }
}

Puedes utilizar una función similar en tus funciones reutilizables. Cuando las funciones necesitan devolver valores del encabezado de la respuesta, deben establecer el valor returnHeader en $true. Por ejemplo, la siguiente función New-Record modifica la función de ejemplo en Crear funciones de operaciones de tabla para usar Invoke-ResilientRestMethod en lugar de Invoke-RestMethod directamente.

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())
}

De lo contrario, Invoke-ResilientRestMethod puede reemplazar el Invoke-RestMethod como se muestra en este ejemplo de Get-Record:

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
}

La única diferencia es que pasa la tabla hash ($RetrieveRequest) al método en lugar de usar splatting (@RetrieveRequest). De lo contrario, obtendrá un error de script: A parameter cannot be found that matches parameter name 'Headers'.

Corregir errores usando Fiddler

Fiddler es un proxy de depuración web que se utiliza para ver el tráfico HTTP en su ordenador. Ver estos datos es útil al depurar scripts. De forma predeterminada, las solicitudes y respuestas HTTP enviadas mediante el cmdlet Invoke-RestMethod no son visibles cuando se usa Fiddler. ...

Para ver el tráfico HTTP en Fiddler, configure el Invoke-RestMethod parámetro Proxy en la URL configurada como proxy de Fiddler en su computadora local. De forma predeterminada, la URL es http://127.0.0.1:8888. Su URL podría ser diferente.

Por ejemplo, si invoca la función WhoAmI con el parámetro -Proxy establecido mientras Fiddler está capturando tráfico:

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

En Fiddler puedes ver todos los detalles:

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"}

Si Fiddler no se está ejecutando, aparecerá un error:

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

Si elige enrutar todas sus llamadas a través de una única función, como la que se describe en Invoke-RestMethod Administrar Invoke-ResilientRestMethod límites de protección del servicio , puede establecer algunas variables en el archivo para configurar esta opción en una única ubicación. Dataverse 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'

Dentro de su función centralizada, puede configurar el parámetro -Proxy con splatting y usar $request tabla hash solo al depurar con Fiddler.

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

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

   ...

Obtenga más información sobre cómo capturar tráfico web con Fiddler

Descargar el documento $metadata CSDL de la API web de Dataverse

Los metadatos del lenguaje de definición de esquema común (CSDL) son la fuente de la verdad sobre las capacidades de la API web. Dataverse Puede verlo en un navegador, pero puede que le resulte más fácil descargar el archivo y verlo dentro de Visual Studio Code. El siguiente script es una versión modificada del script introducido en Inicio rápido de API web con PowerShell. La diferencia es que utiliza el cmdlet Invoke-WebRequest, que es más apropiado para descargar un documento XML.

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

## <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. Copie el script.
  2. Edite las variables $environmentUrl y $writeFileTo para satisfacer sus necesidades.
  3. Ejecute el script en Visual Studio Code.

El documento de metadatos CSDL de la API web se abre en el código. Dataverse Visual Studio

Es posible que reciba una notificación que diga: Por razones de rendimiento, los símbolos de los documentos están limitados a 5000 elementos. Si se establece un nuevo límite, cierre y vuelva a abrir este archivo para volver a calcular los símbolos de los documentos.

La notificación ofrece la opción de cambiar el límite de la Visual Studio extensión del código XML xml.symbols.maxItemsComputed . Para la mayoría de los documentos de metadatos CSDL de API web, establecer el límite en Dataverse debería ser suficiente. 500000

Solución de problemas

Esta sección contiene algunas pautas para los problemas que pueda encontrar.

Cuadro de diálogo de error: conecte ENOENT\\.\pipe\<RANDOM_text> con el botón Abrir 'launch.json'

Este error puede ocurrir al depurar con Visual Studio Código. Para resolver el error:

  1. Seleccione Ver > Paleta de comandos... en el menú Visual Studio Code, o presione Ctrl+Mayús+P.
  2. Escriba restart y seleccione Powershell: Restart session. Consulte PowerShell/vscode-powershell GitHub Problema 4332 para obtener más información.

Pasos siguientes

Aprender más acerca de las Capacidades de API web de Dataverse mediante la comprensión de los documentos de servicio.

Revisar y ejecutar código de muestra.