You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PowerShell Invoke-Sqlcmd连接Azure SQL Database失败求助

问题:PowerShell Invoke-Sqlcmd连接Azure SQL Database失败(服务主体认证)

背景

  • 本机WSL Ubuntu中的sqlcmd(版本18.2.0001.1)可通过服务主体访问令牌成功连接Azure SQL Database
  • 同一机器上的PowerShell Invoke-Sqlcmd(22.2版本)连接失败,同时使用System.Data.SqlClient.SqlConnection方式也报错

用户操作与错误信息

1. 获取服务主体令牌的命令(WSL中执行)

az account get-access-token --resource https://database.windows.net --output tsv | cut -f 1 | tr -d '\n' | iconv -f ascii -t UTF-16LE > TOKEN_LOCATION

2. 可正常运行的sqlcmd命令

sqlcmd -S myserver.database.windows.net -d mydatabase -G -P TOKEN_LOCATION -C -Q "print 'hello'"

3. 失败的Invoke-Sqlcmd命令

Invoke-Sqlcmd -ServerInstance myserver.database.windows.net -Database mydatabase -AccessToken (TOKEN_LOCATION or $TOKEN) -query "print 'hello'" -TrustServerCertificate -Verbose

错误信息:

Invoke-Sqlcmd: Login failed for user '<token-identified principal>'.
Invoke-Sqlcmd: Incorrect syntax was encountered while parsing ''.

4. 失败的SqlConnection代码

$SQLConnection = New-Object System.Data.SqlClient.SqlConnection($ConnectionString)
$SQLConnection.AccessToken = $token
$SQLConnection.Open()

错误信息:

Exception calling "Open" with "0" argument(s): "A connection was successfully established with the server, but then an error occurred during the login process. (provider: TCP Provider, error
: 0 - An existing connection was forcibly closed by the remote host.)"

原因分析

  1. 令牌格式不匹配:sqlcmd的-P参数要求令牌是UTF-16LE编码的文件,所以你用iconv转码并写入文件;但Invoke-Sqlcmd的-AccessToken参数需要的是原始UTF-8格式的令牌字符串,转码后的内容会被识别为无效令牌。
  2. 令牌传递错误:你可能直接传入了文件路径或者转码后的字节内容,而非原始的令牌字符串。
  3. 旧版驱动兼容性:System.Data.SqlClient是旧版SQL驱动,对Azure SQL的服务主体令牌认证支持存在兼容性问题,建议改用新版Microsoft.Data.SqlClient。

解决办法

方法1:修正Invoke-Sqlcmd的令牌获取与传递

先在PowerShell中直接获取原始UTF-8格式的令牌字符串,无需转码和写入文件:

# 获取原始令牌字符串(自动去除多余换行)
$token = (az account get-access-token --resource https://database.windows.net --output tsv).Trim()

# 正确调用Invoke-Sqlcmd
Invoke-Sqlcmd -ServerInstance "myserver.database.windows.net" -Database "mydatabase" -AccessToken $token -Query "print 'hello'" -TrustServerCertificate -Verbose

方法2:改用Microsoft.Data.SqlClient连接

System.Data.SqlClient已被微软标记为维护模式,推荐使用Microsoft.Data.SqlClient:

# 先安装Microsoft.Data.SqlClient模块(首次运行)
Install-Package -Name Microsoft.Data.SqlClient -ProviderName NuGet -Scope CurrentUser -Force

# 获取令牌
$token = (az account get-access-token --resource https://database.windows.net --output tsv).Trim()

# 构建连接字符串并打开连接
$connectionString = "Server=tcp:myserver.database.windows.net,1433;Database=mydatabase;TrustServerCertificate=True;"
$SQLConnection = New-Object Microsoft.Data.SqlClient.SqlConnection($connectionString)
$SQLConnection.AccessToken = $token
$SQLConnection.Open()

# 执行查询示例
$command = $SQLConnection.CreateCommand()
$command.CommandText = "print 'hello'"
$command.ExecuteNonQuery()

# 关闭连接
$SQLConnection.Close()

诊断思路

  1. 验证令牌有效性:执行az account get-access-token --resource https://database.windows.net,复制令牌到JWT解码工具(如本地的jwt.ms)检查:
    • aud字段是否为https://database.windows.net
    • exp字段是否未过期
  2. 确认服务主体权限:检查服务主体是否是Azure SQL Server的Microsoft Entra管理员,或已被授予目标数据库的访问角色(如db_owner)
  3. 测试网络连通性:在PowerShell中执行Test-NetConnection myserver.database.windows.net -Port 1433,确认1433端口可正常访问
  4. 升级Invoke-Sqlcmd版本:执行Update-Module -Name SqlServer升级到最新版,旧版本可能存在令牌认证的bug
  5. 对比令牌内容:将sqlcmd使用的文件内容转成UTF-8字符串,和PowerShell获取的$token对比,确保两者一致

内容的提问来源于stack exchange,提问作者Shimii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 21:05:31