PowerShell kullanarak Always Encrypted anahtarları sağlama

Şunlar için geçerlidir:SQL ServerAzure SQL VeritabanıAzure SQL Yönetilen Örneği

Bu makalede, SqlServer PowerShell modülünü kullanarak Always Encrypted için anahtar sağlama adımları sağlanır. PowerShell'i kullanarak hem hem de rol ayrımıolmadan Always Encrypted anahtarları sağlayabilir, böylece anahtar deposundaki gerçek şifreleme anahtarlarına kimlerin erişimi olduğu ve veritabanına kimlerin erişimi olduğu üzerinde denetim sağlayabilirsiniz.

Note

Microsoft, Always Encrypted PowerShell betiklerini çalıştırırken PowerShell 7 veya üzerini kullanmanızı önerir. PowerShell 7, birçok Always Encrypted senaryosu için gereken gelişmiş platformlar arası destek, daha iyi performans ve SqlServer modülü (v22+) ile en son uyumluluk sağlar.

Bazı üst düzey en iyi uygulama önerileri de dahil olmak üzere Always Encrypted anahtar yönetimine genel bakış için bkz. Always Encryptediçin anahtar yönetimine genel bakış . Always Encrypted için SqlServer PowerShell modülünü kullanmaya başlama hakkında bilgi için bkz. PowerShellkullanarak Always Encrypted'ı yapılandırma .

Rol ayrımı olmadan Anahtar Temini

Bu bölümde açıklanan anahtar sağlama yöntemi, güvenlik yöneticileriyle DTA'lar arasındaki rol ayrımını desteklemez. Bu bölümdeki adımlardan bazıları, fiziksel anahtarlardaki işlemleri anahtar meta verilerindeki işlemlerle birleştirir. Bu nedenle, kuruluşunuz DevOps modelini kullanıyorsa veya veritabanı bulutta barındırılıyorsa ve birincil hedef bulut yöneticilerinin (şirket içi DTA'ların değil) hassas verilere erişmesini kısıtlamaksa anahtarları sağlamak için bu yöntemi kullanın. Olası saldırganlar DTA'lar içeriyorsa veya DTA'ların hassas verilere erişimi olmaması gerekiyorsa bu yöntemi kullanmayın.

Düz metin anahtarlarına veya anahtar deposuna (aşağıdaki tabloda yer alan Accesses düz metin anahtarları/anahtar deposu sütununda tanımlanan) erişimi içeren adımları çalıştırmadan önce, PowerShell ortamının veritabanınızı barındıran bir bilgisayardan farklı güvenli bir makinede çalıştığından emin olun. Daha fazla bilgi için bkz. anahtar yönetimi için güvenlik konuları.

Görev Makale Düz metin anahtarlarına/anahtar deposuna erişir Veritabanına erişir
Adım 1. Anahtar deposunda bir sütun ana anahtarı oluşturun.

Not: SqlServer PowerShell modülü bu adımı desteklemez. Bu görevi bir komut satırından gerçekleştirmek için, seçtiğiniz anahtar deposuna özgü araçları kullanın.
Always Encrypted için sütun ana anahtarları oluşturma ve depolama Evet Hayır
Adım 2. Bir PowerShell ortamı başlatın ve SqlServer PowerShell modülünü içeri aktarın. PowerShell kullanarak Always Encrypted'ı Yapılandırma Hayır Hayır
Adım 3. Sunucunuza ve veritabanınıza bağlanın. Veritabanına bağlanma Hayır Evet
Adım 4. Sütun ana anahtarınızın konumu hakkında bilgi içeren bir SqlColumnMasterKeySettings nesnesi oluşturun. SqlColumnMasterKeySettings, bellekte (PowerShell'de) bulunan bir nesnedir. Anahtar deponuza özgü komut kümesini kullanın. New-SqlAzureKeyVaultColumnMasterKeySettings

New-SqlCertificateStoreColumnMasterKeySettings

New-SqlCngColumnMasterKeySettings

New-SqlCspColumnMasterKeySettings
Hayır Hayır
Adım 5. Veritabanınızdaki sütun ana anahtarıyla ilgili meta verileri oluşturun.

Not: Sütun ana anahtarını oluşturmak için kullanılan anahtarların veya sertifikaların geçerliliğini doğrulamayız.
[New-SqlColumnMasterKey](/powershell/sqlserver/sqlserver/vlatest/new-sqlcolumnmasterkey)

Not: Arka planda, cmdlet anahtar meta verilerini oluşturmak için CREATE COLUMN MASTER KEY deyimini çalıştırır.
Hayır Evet
Adım 6. Sütun ana anahtarınız Azure Key Vault'ta depolanıyorsa Azure'da kimlik doğrulaması yapma. Connect-AzAccount Evet Hayır
Adım 7. Sütun ana anahtarınız Azure Key Vault'ta depolanıyorsa Azure Key Vault için bir erişim belirteci alın. Get-AzAccessToken Hayır Hayır
8. Adım. Yeni bir sütun şifreleme anahtarı oluşturun, bunu sütun ana anahtarıyla şifreleyin ve veritabanında sütun şifreleme anahtarı meta verileri oluşturun. New-SqlColumnEncryptionKey

Not: Dahili olarak bir sütun şifreleme anahtarı oluşturan ve şifreleyen cmdlet'in bir türevini kullanın.

Not: Arka planda, cmdlet anahtar meta verilerini oluşturmak için CREATE COLUMN ENCRYPTION KEY deyimini çalıştırır.
Evet Evet

Rol ayrımı olmadan Windows Sertifika Deposu (örnek)

Bu betik, Windows Sertifika Deposu'nda sertifika olan bir sütun ana anahtarı oluşturmaya, sütun şifreleme anahtarı oluşturup şifrelemeye ve SQL Server veritabanında anahtar meta verileri oluşturmaya yönelik uçtan uca bir örnektir.

[CmdletBinding()]
param(
	[Parameter(Mandatory = $false)]
	[string]$DatabaseName = '<database name>',

	[Parameter(Mandatory = $false)]
	[string]$ServerName = "<server name>",

	[Parameter(Mandatory = $false)]
	[string]$CertificateSubject = "AlwaysEncryptedCert",

	[Parameter(Mandatory = $false)]
	[string]$CmkName = "CMK",

	[Parameter(Mandatory = $false)]
	[string]$CekName = "CEK"
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop

Write-Host "[AE] Locating certificate '$CertificateSubject' in CurrentUser\\My"
$cert = Get-ChildItem -Path Cert:CurrentUser\My |
	Where-Object { $_.Subject -eq "CN=$CertificateSubject" } |
	Sort-Object NotAfter -Descending |
	Select-Object -First 1

if (-not $cert) {
	Write-Host "[AE] Certificate not found. Creating self-signed certificate."
	$cert = New-SelfSignedCertificate `
		-Subject $CertificateSubject `
		-CertStoreLocation Cert:CurrentUser\My `
		-KeyExportPolicy Exportable `
		-Type DocumentEncryptionCert `
		-KeyUsage DataEncipherment `
		-KeySpec KeyExchange
}

Write-Host "[AE] Connecting to SQL Server '$ServerName' / Database '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30"

try {
	$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
}
catch {
	Write-Error "Failed to connect to '$ServerName' database '$DatabaseName'. Verify instance name SQL2025, database existence, and local permissions."
	throw
}

Write-Host "[AE] Creating CMK settings from certificate thumbprint"
$cmkSettings = New-SqlCertificateStoreColumnMasterKeySettings -CertificateStoreLocation "CurrentUser" -Thumbprint $cert.Thumbprint

Write-Host "[AE] Ensuring CMK '$CmkName' exists"
$existingCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
if (-not $existingCmk) {
	New-SqlColumnMasterKey -Name $CmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings | Out-Null
}

Write-Host "[AE] Ensuring CEK '$CekName' exists"
$existingCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $CekName }
if (-not $existingCek) {
	New-SqlColumnEncryptionKey -Name $CekName -InputObject $database -ColumnMasterKey $CmkName | Out-Null
}

Write-Host "Completed successfully"

Rol ayrımı olmadan Azure Key Vault (örnek)

Bu betik, Azure Key Vault'ta anahtar kasası sağlama ve yapılandırma, kasada bir sütun ana anahtarı oluşturma, sütun şifreleme anahtarı oluşturup şifreleme ve Azure SQL veritabanında anahtar meta verileri oluşturmaya yönelik uçtan uca bir örnektir.

param(
	[Parameter(Mandatory = $true)] [string]$SubscriptionId,
	[Parameter(Mandatory = $true)] [string]$ResourceGroupName,
	[Parameter(Mandatory = $true)] [string]$AzureLocation,
	[Parameter(Mandatory = $true)] [string]$KeyVaultName,
	[Parameter(Mandatory = $true)] [string]$KeyName,
	[Parameter(Mandatory = $true)] [string]$ServerName,
	[Parameter(Mandatory = $true)] [string]$DatabaseName,
	[string]$CmkName = "CMK",
	[string]$CekName = "CEK",
	[bool]$AssignRbacToCurrentPrincipal = $true
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

Import-Module Az.Accounts -ErrorAction Stop
Import-Module Az.Resources -ErrorAction Stop
Import-Module Az.KeyVault -ErrorAction Stop
Import-Module SqlServer -ErrorAction Stop

function Get-CurrentPrincipalObjectId {
	param([string]$AccountId)

	$userSignedIn = Get-AzADUser -SignedIn -ErrorAction SilentlyContinue
	if ($userSignedIn) { return $userSignedIn.Id }

	$user = Get-AzADUser -UserPrincipalName $AccountId -ErrorAction SilentlyContinue
	if ($user) { return $user.Id }

	$sp = Get-AzADServicePrincipal -DisplayName $AccountId -ErrorAction SilentlyContinue | Select-Object -First 1
	if ($sp) { return $sp.Id }

	throw "Could not resolve Microsoft Entra object id for account '$AccountId'."
}

try {
	Write-Host "[AE] Signing in and selecting subscription"
	Connect-AzAccount | Out-Null
	$ctx = Set-AzContext -SubscriptionId $SubscriptionId

	Write-Host "[AE] Ensuring resource group exists"
	$resourceGroup = Get-AzResourceGroup -Name $ResourceGroupName -ErrorAction SilentlyContinue
	if (-not $resourceGroup) {
		$resourceGroup = New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation
	}

	Write-Host "[AE] Ensuring key vault exists (RBAC mode)"
	$vault = Get-AzKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -ErrorAction SilentlyContinue
	if (-not $vault) {
		$vault = New-AzKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroupName -Location $AzureLocation -EnableRbacAuthorization
	}

	if (-not $vault.EnableRbacAuthorization) {
		throw "Key Vault '$KeyVaultName' is not using RBAC authorization. Enable RBAC authorization on the vault before running this script."
	}

	if ($AssignRbacToCurrentPrincipal) {
		Write-Host "[AE] Ensuring RBAC role assignment"
		$principalSignInName = $ctx.Account.Id
		$roleName = "Key Vault Crypto Officer"
		$existingRole = Get-AzRoleAssignment -SignInName $principalSignInName -Scope $vault.ResourceId -RoleDefinitionName $roleName -ErrorAction SilentlyContinue
		if (-not $existingRole) {
			New-AzRoleAssignment -SignInName $principalSignInName -Scope $vault.ResourceId -RoleDefinitionName $roleName | Out-Null
		}
	}

	Write-Host "[AE] Ensuring column master key material exists in Key Vault"
	$akvKey = Get-AzKeyVaultKey -VaultName $KeyVaultName -Name $KeyName -ErrorAction SilentlyContinue
	if (-not $akvKey) {
		$akvKey = Add-AzKeyVaultKey -VaultName $KeyVaultName -Name $KeyName -Destination "Software"
	}

	Write-Host "[AE] Connecting to Azure SQL and creating metadata"
	$keyVaultAccessToken = (Get-AzAccessToken -ResourceUrl "https://vault.azure.net").Token
	$connStr = "Server=tcp:$ServerName.database.windows.net,1433;Database=$DatabaseName;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;Authentication=Active Directory Interactive"
	$database = Get-SqlDatabase -ConnectionString $connStr -Encrypt Mandatory
	$cmkSettings = New-SqlAzureKeyVaultColumnMasterKeySettings -KeyUrl $akvKey.Key.Kid

	$existingCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
	if (-not $existingCmk) {
		New-SqlColumnMasterKey -Name $CmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings | Out-Null
	}

	$existingCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $CekName }
	if (-not $existingCek) {
		New-SqlColumnEncryptionKey -Name $CekName -InputObject $database -ColumnMasterKey $CmkName -KeyVaultAccessToken $keyVaultAccessToken | Out-Null
	}

	Write-Host "Completed successfully"
}
catch {
	Write-Error "Script failed: $($_.Exception.Message)"
	throw
}

Rol ayrımı olmadan CNG/KSP (örnek)

Aşağıdaki betik, Şifreleme Yeni Nesil API'si (CNG) uygulayan bir anahtar deposunda sütun ana anahtarı oluşturmaya, sütun şifreleme anahtarı oluşturup şifrelemeye ve SQL Server veritabanında anahtar meta verileri oluşturmaya yönelik uçtan uca bir örnektir.

Örnek, Microsoft Yazılım Anahtarı Depolama Sağlayıcısı'nı kullanan anahtar depoyu kullanır. Örneği, donanım güvenlik modülü gibi farklı bir depolama birimi kullanacak şekilde değiştirmeyi seçebilirsiniz. Bunun için cihazınız için CNG'yi uygulayan anahtar deposu sağlayıcısının (KSP) makinenize yüklendiğinden ve doğru şekilde yüklendiğinden emin olmanız gerekir. Microsoft Software Key Storage Provider cihazınızın KSP adıyla değiştirmeniz gerekir.

[CmdletBinding()]
param(
	[Parameter(Mandatory = $false)]
	[string]$ServerName = "<server name>",

	[Parameter(Mandatory = $true)]
	[string]$DatabaseName = "<database name>",

	[Parameter(Mandatory = $false)]
	[string]$CngKeyName = "AlwaysEncryptedKey",

	[Parameter(Mandatory = $false)]
	[string]$CmkName = "CMK",

	[Parameter(Mandatory = $false)]
	[string]$CekName = "CEK"
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

# Local key store provider and key settings.
$cngProviderName = "Microsoft Software Key Storage Provider"
$cngAlgorithmName = "RSA"
$cngKeySize = 2048

Import-Module SqlServer -ErrorAction Stop

Write-Host "[AE] Creating local CNG key '$CngKeyName'"
$cngProvider = New-Object System.Security.Cryptography.CngProvider($cngProviderName)
$cngKeyParams = New-Object System.Security.Cryptography.CngKeyCreationParameters
$cngKeyParams.Provider = $cngProvider
$cngKeyParams.KeyCreationOptions = [System.Security.Cryptography.CngKeyCreationOptions]::OverwriteExistingKey
$keySizeProperty = New-Object System.Security.Cryptography.CngProperty(
	"Length",
	[System.BitConverter]::GetBytes($cngKeySize),
	[System.Security.Cryptography.CngPropertyOptions]::None
)
$cngKeyParams.Parameters.Add($keySizeProperty)
$cngAlgorithm = New-Object System.Security.Cryptography.CngAlgorithm($cngAlgorithmName)
[System.Security.Cryptography.CngKey]::Create($cngAlgorithm, $CngKeyName, $cngKeyParams) | Out-Null

Write-Host "[AE] Connecting to $ServerName / $DatabaseName"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;Encrypt=True;TrustServerCertificate=True"
$database = Get-SqlDatabase -ConnectionString $connStr

Write-Host "[AE] Preparing column master key settings"
$cmkSettings = New-SqlCngColumnMasterKeySettings -CngProviderName $cngProviderName -KeyName $CngKeyName

Write-Host "[AE] Ensuring CMK exists"
$existingCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
if (-not $existingCmk) {
	New-SqlColumnMasterKey -Name $CmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings | Out-Null
}

Write-Host "[AE] Ensuring CEK exists"
$existingCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $CekName }
if (-not $existingCek) {
	New-SqlColumnEncryptionKey -Name $CekName -InputObject $database -ColumnMasterKey $CmkName | Out-Null
}

Write-Host "Completed successfully"

Rol ayrımı ile anahtar sağlama

Bu bölümde, güvenlik yöneticilerinin veritabanına erişimi olmayan ve veritabanı yöneticilerinin anahtar deposuna veya düz metin anahtarlarına erişimi olmayan şifrelemeyi yapılandırma adımları sağlanır.

Güvenlik yöneticisi

Düz metin anahtarlarına veya anahtar deposuna erişim içeren adımları çalıştırmadan önce (aşağıdaki tabloda yer alan Accesses düz metin anahtarları/anahtar deposu sütununda tanımlanır) şunlardan emin olun:

  • PowerShell ortamı, veritabanınızı barındıran bir bilgisayardan farklı olan güvenli bir makinede çalışır.
  • Kuruluşunuzdaki DTA'ların makineye erişimi yoktur (bu, rol ayrımının amacını yenebilir).

Daha fazla bilgi için bkz. anahtar yönetimi için güvenlik konuları.

Görev Makale Düz metin anahtarlarına/anahtar deposuna erişir Veritabanına erişir
Adım 1. Anahtar deposunda bir sütun ana anahtarı oluşturun.

Not: SqlServer modülü bu adımı desteklemez. Bu görevi bir komut satırından gerçekleştirmek için, anahtar deponuzun türüne özgü araçları kullanmanız gerekir.
Always Encrypted için sütun ana anahtarları oluşturma ve depolama Evet Hayır
Adım 2. Bir PowerShell oturumu başlatın ve SqlServer modülünü içeri aktarın. SqlServer modülünü içeri aktarma Hayır Hayır
Adım 3. Sütun ana anahtarınızın konumu hakkında bilgi içeren bir SqlColumnMasterKeySettings nesnesi oluşturun. SqlColumnMasterKeySettings, bellekte (PowerShell'de) bulunan bir nesnedir. Anahtar deponuza özgü komut kümesini kullanın. New-SqlAzureKeyVaultColumnMasterKeySettings

New-SqlCertificateStoreColumnMasterKeySettings

New-SqlCngColumnMasterKeySettings

New-SqlCspColumnMasterKeySettings
Hayır Hayır
Adım 4. Sütun ana anahtarınız Azure Key Vault'ta depolanıyorsa Azure'da kimlik doğrulaması yapma. Connect-AzAccount Evet Hayır
Adım 5. Sütun ana anahtarınız Azure Key Vault'ta depolanıyorsa Azure Key Vault için bir erişim belirteci alın. Get-AzAccessToken Hayır Hayır
Adım 6. Bir sütun şifreleme anahtarı oluşturun, sütun şifreleme anahtarının şifrelenmiş değerini oluşturmak için bunu sütun ana anahtarıyla şifreleyin. New-SqlColumnEncryptionKeyEncryptedValue Evet Hayır
Adım 7. Sütun ana anahtarının konumunu (sağlayıcı adı ve sütun ana anahtarının anahtar yolu) ve DBA'ya sütun şifreleme anahtarının şifrelenmiş değerini sağlayın. Makalenin sonundaki örneklere bakın. Hayır Hayır

Veritabanı Yöneticisi (DBA)

DTA'lar, veritabanında Always Encrypted anahtar meta verilerini oluşturmak ve yönetmek için Güvenlik Yöneticisi'nden (yukarıdaki 7. adım) aldıkları bilgileri kullanır.

Görev Makale Düz metin anahtarlarına erişir Veritabanına erişir
Adım 1. Güvenlik Yöneticinizden sütun ana anahtarının konumunu ve sütun şifreleme anahtarının şifrelenmiş değerini alın. Makalenin sonundaki örneklere bakın. Hayır Hayır
Adım 2. Bir PowerShell ortamı başlatın ve SqlServer modülünü içeri aktarın. PowerShell kullanarak Always Encrypted'ı Yapılandırma Hayır Hayır
Adım 3. Sunucunuza ve bir veritabanına bağlanın. Veritabanına bağlanma Hayır Evet
Adım 4. Sütun ana anahtarınızın konumu hakkında bilgi içeren bir SqlColumnMasterKeySettings nesnesi oluşturun. SqlColumnMasterKeySettings, bellekte bulunan bir nesnedir. Yeni-SqlSütunAnahtarAyarlaması Hayır Hayır
Adım 5. Veritabanınızdaki sütun ana anahtarıyla ilgili meta verileri oluşturun.

Not: Sütun ana anahtarını oluşturmak için kullanılan anahtarların veya sertifikaların geçerliliğini doğrulamayız.
New-SqlColumnMasterKey
Not: Cmdlet, arka planda sütun ana anahtarı meta verilerini oluşturmak için CREATE COLUMN MASTER KEY (Transact-SQL) deyimini çalıştırır.
Hayır Evet
Adım 6. Veritabanında sütun şifreleme anahtarı meta verilerini oluşturun. New-SqlColumnEncryptionKey
Not: DTA'lar, cmdlet'in yalnızca sütun şifreleme anahtarı meta verilerini oluşturan bir varyasyonunu kullanır.
Arka planda, cmdlet sütun şifreleme anahtarı meta verisi oluşturmak için CREATE COLUMN ENCRYPTION KEY (Transact-SQL) deyimini çalıştırır.
Hayır Evet

Rol ayrımı ile Windows Sertifika Deposu (örnek)

Güvenlik yöneticisi

[CmdletBinding()]
param(
	[Parameter(Mandatory = $false)]
	[string]$ServerName = '<server name>',

	[Parameter(Mandatory = $false)]
	[ValidateNotNullOrEmpty()]
	[string]$DatabaseName = '<database name>',

	[Parameter(Mandatory = $false)]
	[string]$CertificateSubject = 'AlwaysEncryptedCert',

	[Parameter(Mandatory = $false)]
	[string]$CmkName = 'CMK1',

	[Parameter(Mandatory = $false)]
	[string]$CekName = 'CEK1',

	[Parameter(Mandatory = $false)]
	[string]$ExportKeyDataPath = 'C:\temp\keydata.txt'
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop

Write-Host "[AE] Finding certificate '$CertificateSubject' in CurrentUser\\My"
$cert = Get-ChildItem -Path 'Cert:CurrentUser\My' |
	Where-Object { $_.Subject -eq "CN=$CertificateSubject" } |
	Sort-Object NotAfter -Descending |
	Select-Object -First 1

if (-not $cert) {
	Write-Host '[AE] Certificate not found. Creating a new self-signed certificate.'
	$cert = New-SelfSignedCertificate `
		-Subject $CertificateSubject `
		-CertStoreLocation 'Cert:CurrentUser\My' `
		-KeyExportPolicy Exportable `
		-Type DocumentEncryptionCert `
		-KeyUsage DataEncipherment `
		-KeySpec KeyExchange
}

Write-Host "[AE] Connecting to SQL Server '$ServerName' / Database '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30"

try {
	$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
}
catch {
	Write-Error "Failed to connect to '$ServerName' / '$DatabaseName'. Verify instance name, database, and local permissions."
	throw
}

Write-Host '[AE] Building CMK settings from certificate'
$cmkSettings = New-SqlCertificateStoreColumnMasterKeySettings -CertificateStoreLocation 'CurrentUser' -Thumbprint $cert.Thumbprint

Write-Host "[AE] Ensuring CMK '$CmkName' exists"
$existingCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
if (-not $existingCmk) {
	New-SqlColumnMasterKey -Name $CmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings | Out-Null
}

Write-Host "[AE] Ensuring CEK '$CekName' exists"
$existingCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $CekName }
if (-not $existingCek) {
	New-SqlColumnEncryptionKey -Name $CekName -InputObject $database -ColumnMasterKey $CmkName | Out-Null
}

if ($ExportKeyDataPath) {
	Write-Host "[AE] Exporting key metadata to '$ExportKeyDataPath'"
	$encryptedValue = New-SqlColumnEncryptionKeyEncryptedValue -TargetColumnMasterKeySettings $cmkSettings
	"KeyStoreProviderName,KeyPath,EncryptedValue" | Set-Content -Path $ExportKeyDataPath -Encoding UTF8
	"$($cmkSettings.KeyStoreProviderName),$($cmkSettings.KeyPath),$encryptedValue" | Add-Content -Path $ExportKeyDataPath -Encoding UTF8
}

Write-Host 'Completed successfully'

Veritabanı Yöneticisi (DBA)

[CmdletBinding()]
param(
	[Parameter(Mandatory = $false)]
	[string]$ServerName = 'localhost\SQL2025',

	[Parameter(Mandatory = $false)]
	[ValidateNotNullOrEmpty()]
	[string]$DatabaseName = 'AdventureWorks2025',

	[Parameter(Mandatory = $false)]
	[ValidateNotNullOrEmpty()]
	[string]$KeyDataFile = 'C:\temp\keydata.txt',

	[Parameter(Mandatory = $false)]
	[ValidateNotNullOrEmpty()]
	[string]$CmkName = 'CMK1',

	[Parameter(Mandatory = $false)]
	[ValidateNotNullOrEmpty()]
	[string]$CekName = 'CEK1'
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

Import-Module SqlServer -MinimumVersion 22.0.50 -ErrorAction Stop

if (-not (Test-Path -Path $KeyDataFile -PathType Leaf)) {
	throw "Key data file not found: $KeyDataFile"
}

Write-Host "[AE] Loading key metadata from '$KeyDataFile'"
$keyData = Import-Csv -Path $KeyDataFile
if (-not $keyData) {
	throw "Key data file '$KeyDataFile' is empty."
}

$keyDataRow = $keyData | Select-Object -First 1
if (-not $keyDataRow.KeyStoreProviderName -or -not $keyDataRow.KeyPath -or -not $keyDataRow.EncryptedValue) {
	throw "Key data file must include non-empty columns: KeyStoreProviderName, KeyPath, EncryptedValue."
}

Write-Host "[AE] Connecting to SQL Server '$ServerName' / Database '$DatabaseName'"
$connStr = "Server=$ServerName;Database=$DatabaseName;Integrated Security=True;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30"

try {
	$database = Get-SqlDatabase -ConnectionString $connStr -ErrorAction Stop
}
catch {
	Write-Error "Failed to connect to '$ServerName' / '$DatabaseName'. Verify instance name, database, and local permissions."
	throw
}

Write-Host "[AE] Building CMK settings for provider '$($keyDataRow.KeyStoreProviderName)'"
$cmkSettings = New-SqlColumnMasterKeySettings -KeyStoreProviderName $keyDataRow.KeyStoreProviderName -KeyPath $keyDataRow.KeyPath

Write-Host "[AE] Ensuring CMK '$CmkName' exists"
$existingCmk = Get-SqlColumnMasterKey -InputObject $database | Where-Object { $_.Name -eq $CmkName }
if (-not $existingCmk) {
	New-SqlColumnMasterKey -Name $CmkName -InputObject $database -ColumnMasterKeySettings $cmkSettings | Out-Null
}

Write-Host "[AE] Ensuring CEK '$CekName' exists"
$existingCek = Get-SqlColumnEncryptionKey -InputObject $database | Where-Object { $_.Name -eq $CekName }
if (-not $existingCek) {
	New-SqlColumnEncryptionKey -Name $CekName -InputObject $database -ColumnMasterKey $CmkName -EncryptedValue $keyDataRow.EncryptedValue | Out-Null
}

Write-Host 'Completed successfully'