Skip to content

Commit 44c6fe9

Browse files
impl(bq_driver): Migration sripts
1 parent 89a746f commit 44c6fe9

2 files changed

Lines changed: 519 additions & 0 deletions

File tree

ci/migration/migrate_dsn.ps1

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
<#
2+
Migration script for Windows ODBC DSNs
3+
- Migrates from "Simba ODBC Driver for Google Bigquery"
4+
- to "Google Bigquery Driver"
5+
6+
Usage:
7+
migrate.ps1 -Mode copy -DriverInstaller "GoogleBigQueryODBC.msi"
8+
migrate.ps1 -Mode replace -DriverInstaller "GoogleBigQueryODBC.msi"
9+
#>
10+
11+
param(
12+
[Parameter(Mandatory=$true)]
13+
[ValidateSet("copy","replace")]
14+
[string]$Mode,
15+
16+
[Parameter(Mandatory=$true)]
17+
[string]$DriverInstaller
18+
)
19+
20+
$SimbaDriverName = "Simba ODBC Driver for Google Bigquery"
21+
$GoogleDriverName = "Google Bigquery Driver"
22+
23+
Write-Host "=== Installing Google Bigquery Driver ==="
24+
Start-Process "msiexec.exe" -ArgumentList "/i `"$DriverInstaller`" /quiet /norestart" -Wait
25+
Write-Host "=== Driver installation complete ===`n"
26+
27+
# Registry paths for DSNs
28+
$DSNRoots = @(
29+
"HKLM:\SOFTWARE\ODBC\ODBC.INI",
30+
"HKCU:\SOFTWARE\ODBC\ODBC.INI"
31+
)
32+
$DSNListRoot = "ODBC Data Sources"
33+
34+
function CopyRegistryTree($SourcePath, $TargetPath) {
35+
if (!(Test-Path $TargetPath)) {
36+
New-Item -Path $TargetPath | Out-Null
37+
}
38+
39+
$props = Get-ItemProperty -Path $SourcePath
40+
foreach ($p in $props.PSObject.Properties) {
41+
if ($p.Name -notlike "PS*") {
42+
Set-ItemProperty -Path $TargetPath -Name $p.Name -Value $p.Value
43+
}
44+
}
45+
}
46+
47+
# === DPAPI HEX DECRYPTOR ===
48+
function Decode-DPAPIHex($hex) {
49+
if ([string]::IsNullOrWhiteSpace($hex)) { return $null }
50+
51+
Add-Type -AssemblyName System.Security
52+
53+
# Convert hexadecimal → byte array
54+
$bytes = for ($i = 0; $i -lt $hex.Length; $i += 2) {
55+
[Convert]::ToByte($hex.Substring($i, 2), 16)
56+
}
57+
58+
# Try LocalMachine first
59+
try {
60+
return [System.Security.Cryptography.ProtectedData]::Unprotect(
61+
$bytes, $null,
62+
[System.Security.Cryptography.DataProtectionScope]::LocalMachine
63+
)
64+
}
65+
catch {
66+
# Try CurrentUser if LocalMachine does not work
67+
return [System.Security.Cryptography.ProtectedData]::Unprotect(
68+
$bytes, $null,
69+
[System.Security.Cryptography.DataProtectionScope]::CurrentUser
70+
)
71+
}
72+
}
73+
74+
function TestODBCConnection($DSN) {
75+
Write-Host " → Testing ODBC connection..."
76+
try {
77+
$conn = New-Object System.Data.Odbc.OdbcConnection("DSN=$DSN")
78+
$conn.Open()
79+
Write-Host " → Connection test: OK" -ForegroundColor Green
80+
$conn.Close()
81+
} catch {
82+
Write-Host " → Connection test: FAILED" -ForegroundColor Red
83+
Write-Host $_.Exception.Message
84+
}
85+
}
86+
$SimbaDSNs = @()
87+
88+
foreach ($root in $DSNRoots) {
89+
90+
$dsnTablePath = Join-Path $root $DSNListRoot
91+
if (!(Test-Path $dsnTablePath)) { continue }
92+
93+
$dsns = Get-ItemProperty $dsnTablePath
94+
foreach ($entry in $dsns.PSObject.Properties) {
95+
96+
$dsnName = $entry.Name
97+
$driverValue = $entry.Value
98+
99+
if ($driverValue -eq $SimbaDriverName) {
100+
$SimbaDSNs += [PSCustomObject]@{
101+
Root = $root
102+
DsnName = $dsnName
103+
DsnTablePath = $dsnTablePath
104+
}
105+
}
106+
}
107+
}
108+
109+
if ($SimbaDSNs.Count -eq 0) {
110+
Write-Host "No Simba DSNs found. Nothing to migrate."
111+
exit
112+
}
113+
elseif ($SimbaDSNs.Count -eq 1) {
114+
$Chosen = $SimbaDSNs[0]
115+
}
116+
else {
117+
Write-Host "`nMultiple Simba DSNs found:"
118+
for ($i=0; $i -lt $SimbaDSNs.Count; $i++) {
119+
Write-Host " [$($i+1)] $($SimbaDSNs[$i].DsnName) ($($SimbaDSNs[$i].Root))"
120+
}
121+
122+
do {
123+
$sel = Read-Host "Enter the number of the DSN you want to migrate"
124+
} until ($sel -as [int] -and $sel -ge 1 -and $sel -le $SimbaDSNs.Count)
125+
126+
$Chosen = $SimbaDSNs[$sel - 1]
127+
}
128+
129+
Write-Host "`nSelected DSN: $($Chosen.DsnName)"
130+
Write-Host "Location: $($Chosen.Root)`n"
131+
132+
# ===============================================================
133+
# === Continue the original loop logic ONLY for chosen DSN ===
134+
# ===============================================================
135+
136+
$root = $Chosen.Root
137+
$dsnName = $Chosen.DsnName
138+
$dsnTablePath = $Chosen.DsnTablePath
139+
140+
Write-Host "`nFound Simba DSN: $dsnName"
141+
142+
# Source DSN registry key
143+
$srcDSNKey = Join-Path $root $dsnName
144+
if (!(Test-Path $srcDSNKey)) {
145+
Write-Warning "DSN entry exists in table but no registry key: $srcDSNKey"
146+
exit
147+
}
148+
149+
# Determine target DSN values based on mode
150+
if ($Mode -eq "replace") {
151+
$newDSNName = $dsnName
152+
} else {
153+
$newDSNName = "${dsnName}_Google"
154+
}
155+
156+
Write-Host " → Target DSN: $newDSNName"
157+
$dstDSNKey = Join-Path $root $newDSNName
158+
159+
# 1. Update ODBC Data Sources table
160+
Set-ItemProperty -Path $dsnTablePath -Name $newDSNName -Value $GoogleDriverName
161+
if ($Mode -eq "replace" -and $newDSNName -eq $dsnName) {
162+
Set-ItemProperty -Path $dsnTablePath -Name $dsnName -Value $GoogleDriverName
163+
}
164+
165+
# 2. Copy registry values
166+
CopyRegistryTree -SourcePath $srcDSNKey -TargetPath $dstDSNKey
167+
168+
# 3. Update Driver DLL
169+
$googleDriverKey = Get-ChildItem "HKLM:\SOFTWARE\ODBC\ODBCINST.INI" |
170+
Where-Object { $_.PSChildName -eq $GoogleDriverName }
171+
if (!$googleDriverKey) { Write-Warning "Google driver not found in ODBCINST.INI"; exit }
172+
173+
$googleDLL = (Get-ItemProperty $googleDriverKey.PSPath).Driver
174+
Set-ItemProperty -Path $dstDSNKey -Name "Driver" -Value $googleDLL
175+
Write-Host " → Set Driver DLL to: $googleDLL"
176+
177+
# 3b. Fix TrustedCerts
178+
$driverFolder = Split-Path $googleDLL -Parent
179+
$rootsCert = Join-Path $driverFolder "Assets\roots.pem"
180+
if (Test-Path $rootsCert) {
181+
Set-ItemProperty -Path $dstDSNKey -Name "TrustedCerts" -Value $rootsCert
182+
Write-Host " → Updated TrustedCerts to: $rootsCert"
183+
} else {
184+
Write-Warning " → roots.pem not found in $driverFolder\Assets"
185+
}
186+
187+
# 4. Decrypt KeyFilePath_Enc
188+
$encKeyPath = (Get-ItemProperty $srcDSNKey -ErrorAction SilentlyContinue).KeyFilePath_Enc
189+
if ($encKeyPath) {
190+
191+
Write-Host " → Decrypting KeyFilePath_Enc..."
192+
193+
$rawBytes = Decode-DPAPIHex $encKeyPath
194+
if ($rawBytes) {
195+
$plainPath = [System.Text.Encoding]::UTF8.GetString($rawBytes)
196+
Write-Host " → Decrypted KeyFilePath: $plainPath"
197+
198+
# Write plain KeyFilePath into new DSN
199+
Set-ItemProperty -Path $dstDSNKey -Name "KeyFilePath" -Value $plainPath
200+
} else {
201+
Write-Warning " → Failed to decrypt KeyFilePath_Enc"
202+
}
203+
}
204+
205+
# 5. Test DSN connectivity
206+
TestODBCConnection -DSN $newDSNName
207+
208+
Write-Host "`n=== Migration complete ==="

0 commit comments

Comments
 (0)