本文介绍如何将 PowerShell 和 Visual Studio Code 与 Dataverse Web API 配合使用,实现高级功能。 你将了解如何创建可重用函数、处理异常以及管理服务保护限制。
注释
本文中的说明适用于 Windows、Linux 和 macOS,但这些步骤仅在 Windows 上进行测试。 如果需要更改,请使用本文底部的 “反馈 ”部分。
先决条件
本文的先决条件与 PowerShell 文章中的快速入门 Web API 相同。
安装或验证是否已安装以下内容
安装 Visual Studio Code。 请参阅 Download Visual Studio Code
安装适用于 Visual Studio Code 的 PowerShell 扩展。 请参阅 PowerShell for Visual Studio Code
安装 PowerShell 7.4 或更高版本。 请参阅 在 Windows、Linux 和 macOS 上安装 PowerShell
安装 Az PowerShell 模块版本 11.1.0 或更高版本。 请参阅 如何安装 Azure PowerShell
若要 将现有安装更新到最新版本,请使用
Update-Module -Name Az -Force
验证安装
打开Visual Studio代码。
在“终端”菜单中,选择“新终端”。
在 Visual Studio Code 导航窗格中,选择
PowerShell 扩展的图标。在Visual Studio Code终端窗口中复制并粘贴以下脚本:
Write-Host 'PowerShell Version:'$PSVersionTable.PSVersion.ToString() Write-Host 'PowerShell Az version:'(Get-InstalledModule Az).Version按 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 函数 进行身份验证和调用。 对于一个或多个操作的临时测试,这种方法可能就足够了。 但是,随着脚本变得更加复杂,你可能会发现自己再次键入相同的代码。
在本节中,您将开始在单独的文件中创建一组可重用的函数,您可以通过点引用访问这些函数。 使用点引用加载包含 PowerShell 脚本的文件,这些脚本中的函数和变量将作为本地脚本作用域的一部分。
小窍门
可以在 PowerApps-Samples/dataverse/webapi/PS/ 的 GitHub PowerApps-Samples 存储库中找到这些函数的完整文档定义和其他内容
创建 Connect 函数
将认证到 Dataverse 的代码放入一个名为Connect的函数中,并存放在名为Core.ps1的文件,以便可以在一行代码中重复使用它。
创建文件夹。 在此示例中,在 . 中创建
C:\scripts一个文件夹。在脚本文件夹中创建一个名为
Core.ps1的文本文件。将以下
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/' }在 Visual Studio Code 的
scripts文件夹中创建一个名为test.ps1的文本文件。将以下脚本复制并粘贴到
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使用点引用指示脚本加载该文件的内容。请记得更改
https://yourorg.crm.dynamics.com/以匹配环境的 URL。若要运行脚本,请按 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 函数
将调用CommonFunctions.ps1的代码放在名为CommonFunctions.ps1的文件中的函数内。 这样,每次想要使用 WhoAmI 函数时,只需键入 11 个字符而不是 100 个字符。
在您的
scripts文件夹中创建一个名为CommonFunctions.ps1的新文本文件。在
CommonFunctions.ps1中复制并粘贴以下函数定义。function Get-WhoAmI{ $WhoAmIRequest = @{ Uri = $baseURI + 'WhoAmI' Method = 'Get' Headers = $baseHeaders } Invoke-RestMethod @WhoAmIRequest }注释
此函数定义使用了一种称为展开的技术。 拆分能让命令更简洁、更易读,因为它将一组参数值作为一个整体传递给命令。
保存
CommonFunctions.ps1文件。将
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请记得将
https://yourorg.crm.dynamics.com/值更改为与您环境对应的 URL。若要运行脚本,请按 F5。
输出应与以前完全相同。
创建表操作函数
将执行常见表操作的函数放入名为 TableOperations.ps1 的文件中,以便重复使用它们。
在
scripts文件夹中创建一个名为TableOperations.ps1的新文本文件。将以下函数定义复制并粘贴到
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 }有关如何撰写这些请求的信息,请参阅以下文章:
保存
TableOperations.ps1文件。复制以下代码并将其粘贴到
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"请记住更改
https://yourorg.crm.dynamics.com/的值,以匹配您环境的 URL。若要运行脚本,请按 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 返回的错误中提取相关详细信息。
将以下
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 cmdlet 在 try/catch 块中处理一组命令。 Dataverse 返回的任何错误都是 HttpResponseException 错误,因此第一个catch代码块会将包含 JSON 错误数据的An error occurred calling Dataverse:消息写入终端。$_.ErrorDetails.Message中的 JSON 数据包含一些转义的 Unicode 字符。 例如:\u0026而不是&而不是\u0027'。 此函数包含一些代码,会将这些字符替换为未转义的字符,以便它们与您在其他地方看到的错误完全一致。否则,错误信息将被写回到终端窗口,并显示如下消息:
An error occurred in the script:保存
Core.ps1文件。编辑
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 }请记住更改
https://yourorg.crm.dynamics.com/的值,以匹配您环境的 URL。若要运行脚本,请按 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'." } }编辑
test.ps1文件,在Invoke-DataverseCommands块中抛出脚本错误:Invoke-DataverseCommands { throw 'A script error' }若要运行脚本,请按 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 cmdletMaximumRetryCount 参数 指定在收到 400 到 599 之间的故障代码(含)或 304 之间的失败代码时,PowerShell 重试请求的次数。 此参数表示,当您为其设置值时,PowerShell 将重试 Dataverse 服务保护 429 错误。 将 MaximumRetryCount 参数与 RetryIntervalSec 一起使用,以指定要等待的秒数。 默认值为 5 秒。 如果错误响应包含 429 错误的 Retry-After 标头(如 Dataverse 服务保护错误那样),则使用该值代替。
在了解如何将 Dataverse Web API 与 PowerShell 配合使用时,可能永远不会遇到服务保护限制错误。 但是,你编写的脚本可能会发送大量生成错误的请求,因此了解如何使用 PowerShell 最好地管理这些请求。
如果您通过 Invoke-RestMethod 将 MaximumRetryCount 参数添加到每个 Dataverse 调用中,PowerShell 会重试各种类型的错误。 重试每个错误会使脚本变慢,尤其是在开发和测试时。 每次发生错误时,都需要等待 10 到 15 秒,具体取决于指定的重试次数。 另一种方法是将 Invoke-RestMethod 封装在您自己的方法中,用于管理特定错误的重试。
以下 Invoke-ResilientRestMethod 函数采用 request 哈希表对象作为必需参数和布尔 returnHeader 标志,以指示是否返回响应标头。 如果 $returnHeader 为 true,它将使用 Invoke-RestMethod 带有 ResponseHeadersVariable 参数的命令发送请求,以捕获返回的标头。 该函数使用 Out-Null ,因此该函数不会返回表示空响应正文的输出。 否则,该函数使用Invoke-RestMethodrequest对象发送请求并返回响应正文。
Invoke-RestMethod如果失败并出现 429 错误,它将检查对象是否request具有MaximumRetryCount属性。 如果函数成功,它将创建一个 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-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-RestMethod,如在以下示例 Get-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 是一个 Web 调试代理,可用于查看计算机上的 HTTP 流量。 调试脚本时,查看此数据非常有用。 默认情况下,Fiddler 不会显示使用 Invoke-RestMethod cmdlet 发送的 HTTP 请求和响应。
若要查看 Fiddler 中的 HTTP 流量,请将 Invoke-RestMethodProxy 参数 设置为在本地计算机上配置为 Fiddler 代理的 URL。 默认情况下,该 URL 为 http://127.0.0.1:8888。 URL 可能有所不同。
例如,当 Fiddler 正在捕获流量时,如果您调用 WhoAmI 函数并设置了 -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-RestMethodInvoke-ResilientRestMethod中所述)路由所有调用,则可以在Core.ps1文件中设置一些变量,以在单个位置配置此选项。
# 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)
}
...
下载 Dataverse Web API CSDL $metadata 文档
公共架构定义语言(CSDL)$metadata 是关于 Dataverse Web API 功能的可信来源。 可以在浏览器中查看它,但你可能会发现下载文件并在 Visual Studio Code 中查看该文件更容易。 以下脚本是 PowerShell 快速入门 Web API 中引入的脚本的修改版本。 区别在于它使用 Invoke-WebRequest cmdlet,该 cmdlet 更适合下载 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
- 复制脚本。
- 请编辑
$environmentUrl和$writeFileTo变量以匹配您的需求。 - 在 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 就足够了。
故障排除
本部分包含你可能遇到的问题的一些指南。
错误对话:连接 ENOENT\\.\pipe\<RANDOM_text> 和 Open 'launch.json' 按钮
使用 Visual Studio Code 进行调试时,可能会出现此错误。 若要解决该错误:
- 从 Visual Studio Code 菜单中选择 “查看>命令面板...” ,或按 Ctrl+Shift+P。
- 键入
restart并选择Powershell: Restart session。 有关详细信息,请参阅 PowerShell/vscode-powershell GitHub 问题 4332 。
后续步骤
通过了解服务文档详细了解 Dataverse Web API 功能。
查看并运行示例代码。