【问题标题】:Set-SqlColumnEncryption throws errorSet-SqlColumnEncryption 抛出错误
【发布时间】:2018-05-04 05:19:28
【问题描述】:

我正在使用 SSMS 中的加密列功能加密现有表中的多个列。我选择生成一个 Powershell 脚本,而不是在向导中加密列,这样我就可以在稍后的时间点加密这些列。脚本如下:

# Generated by SQL Server Management Studio at 3:03 PM on 4/05/2018

Import-Module SqlServer
# Set up connection and database SMO objects

$sqlConnectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True;MultipleActiveResultSets=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;Packet Size=4096;Application Name=`"Microsoft SQL Server Management Studio`""
$smoDatabase = Get-SqlDatabase -ConnectionString $sqlConnectionString

# If your encryption changes involve keys in Azure Key Vault, uncomment one of the lines below in order to authenticate:
#   * Prompt for a username and password:
#Add-SqlAzureAuthenticationContext -Interactive

#   * Enter a Client ID, Secret, and Tenant ID:
#Add-SqlAzureAuthenticationContext -ClientID '<Client ID>' -Secret '<Secret>' -Tenant '<Tenant ID>'

# Change encryption schema

$encryptionChanges = @()

# Add changes for table [dbo].[Voucher]
$encryptionChanges += New-SqlColumnEncryptionSettings -ColumnName dbo.Voucher.Code -EncryptionType Randomized -EncryptionKey "cek"

Set-SqlColumnEncryption -ColumnEncryptionSettings $encryptionChanges -InputObject $smoDatabase

但是,当我运行脚本时,我从 Set-SqlColumnEncryption cmdlet 得到以下异常:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an
invocation. ---> System.TypeInitializationException: The type initializer for
'Microsoft.SqlServer.Management.AlwaysEncrypted.Management.AlwaysEncryptedManagement' threw an
exception. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json,
Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The
system cannot find the file specified.

我也更新了 Sqlserver 模块。当然,我不必手动将 Newtonsoft.Json.dll 文件放到 SqlServer 模块目录中。有什么想法吗?

【问题讨论】:

  • 我遇到了同样的问题。就像 powershell 需要对 Newtonsoft.Json 进行某种绑定重定向。我认为这最终是通过 Microsoft.Azure.KeyVault.dll 触发的,这似乎是 AlwaysEncryptedManagement 程序集的依赖项。 Newtonsoft.json 确实在同一目录中使用此 dll,但在我的情况下,它是版本 10。我放弃了版本 6.0.1,这并不能解决我的问题。

标签: powershell always-encrypted


【解决方案1】:

您使用的是“始终加密”。我假设您的列主密钥存储在运行脚本的计算机上的 Windows 证书存储中。而且,我假设您的密钥设置正确。

假设我有一个带有架构的表:

CREATE TABLE dbo.property_bag (
id int identity(1,1) primary key
, insert_user sysname not null
, insert_date datetime2 not null
, insert_source sysname not null
, [stuff] varchar(max) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED
, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256'
, COLUMN_ENCRYPTION_KEY = [dbo-property_bag]) NULL
);
GO

这是一个将数据插入我的表的脚本:

$insert_count = 10
$words = @('bobby','mikey','billy','suzie','kenny','narav','navneet','rachel','jose','juan')

$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = “Server='<db-server>';Database='<db>';Column Encryption Setting=enabled;Integrated Security=True;”
$hostname = $env:computername

try {
    $conn.Open()
 
    for ($i = 1; $i -le $insert_count; $i++) {
        $val = Get-Random -Maximum 10
        $word_to_insert = $words[$val]
        $sqlcmd = New-Object System.Data.SqlClient.SqlCommand
        $sqlcmd.Connection = $conn
        $sqlcmd.CommandText = “INSERT INTO dbo.property_bag ([insert_user], [insert_date], [insert_source], [stuff]) VALUES (SUSER_SNAME(), GETDATE(), '${hostname}', @value)”
        $sqlcmd.Parameters.Add((New-Object Data.SqlClient.SqlParameter("@value",[Data.SQLDBType]::VarChar, 4000))) | Out-Null
        $sqlcmd.Parameters[0].Value = $word_to_insert
        $sqlcmd.ExecuteNonQuery() | Out-Null
        Write-Progress -Activity "Inserting Records..." -Status "Progress $($i / $insert_count * 100)%" -percentComplete ($i / $insert_count)
    }
} finally {
    $conn.Close()
    $conn.Dispose()
}

当我向数据库注册列主密钥时(通过对象资源管理器),我会将路径设置为“CurrentUser/My/”。 SQL Server 会将该位置传递回驱动程序,驱动程序将在本地密钥存储区中的该位置搜索与提供的指纹匹配的证书。该密钥(在我的情况下位于运行脚本的应用服务器上)将解密列加密密钥。脚本中没有详细说明这些。这一切都在数据库中设置。以下是此示例的数据流:

在您的示例中,连接字符串不包含“Column Encryption Setting=enabled”。我不相信Get-SqlDatabase 命令行开关采用连接字符串参数。我相信你会给它一个实例对象。只是有一堆看起来不太安静的事情。

如果您的密钥设置不正确,我会开始here

【讨论】:

  • 我认为这不是问题所在。在他的情况下,他的问题是 Set-SqlColumnEncryption 由于找不到 Newtonsoft.Json 而崩溃。他很可能已经完成了上述所有工作,甚至达到了那一步。
  • 我不认为比我在帖子中看到的更多。你知道什么是真正有用的。如果您在另一个答案中发布了您的设置步骤和重新创建的步骤,那么我可以重新创建问题。
  • 我重新创建他的问题并不构成解决方案,因为我有同样的问题。但是,是的,我可以通过包括 ssms、windows、powershell 等的版本号来改进他的问题。
  • 听起来是个好主意。
【解决方案2】:

我遇到了完全相同的问题,我相信这是您的操作系统和 Sql Server 的特定组合上的某种组件集成问题。

例如,我在笔记本电脑上尝试运行该 powershell 脚本时收到此错误。我的笔记本电脑恰好使用 Windows 10 和 Sql Server Management Studio 17.2(最终生成 ps1)。此外,我的笔记本电脑确实在正确的目录中包含 Newtonsoft.Json.dll。

但是,我跳到了使用 Windows 2012 R2 和 SSMS 17.2 的服务器上,并且脚本可以正常工作!

最终,好像在 Windows10/SSMS17.2 安装中缺少某种程序集绑定重定向,Windows2012R2/SSMS17.2 似乎可以正确解决。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-06
    • 2016-12-02
    • 2021-03-20
    • 2020-09-29
    • 1970-01-01
    • 2023-03-14
    • 2012-10-28
    相关资源
    最近更新 更多