ODBC scripts
- Fix and optimize export script for ODBC DSNs, registry keys, and driver inventory. - Fix bug in the restore ODBC DSNs and registry keys scripts, ensuring compatibility with different Windows architectures.
This commit is contained in:
273
export-ODBC.ps1
Normal file
273
export-ODBC.ps1
Normal file
@@ -0,0 +1,273 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Export ODBC DSNs, registry keys, and driver inventory.
|
||||
Generate migration package + report with vendor download links.
|
||||
|
||||
.DESCRIPTION
|
||||
This script:
|
||||
- Exports ODBC System/User DSNs
|
||||
- Exports registry keys for ODBC.INI
|
||||
- Lists all installed ODBC drivers and Add/Remove Program entries
|
||||
- Matches known ODBC drivers to official vendor download URLs
|
||||
- Searches for local EXE/MSI installers
|
||||
- Generates CSV + Markdown reports
|
||||
- Compresses all output into a single ZIP archive
|
||||
|
||||
Run as Administrator on the source PC.
|
||||
#>
|
||||
|
||||
# ===========================
|
||||
# CONFIGURATION
|
||||
# ===========================
|
||||
$BaseDir = "C:\ODBC_Migration"
|
||||
$ExportDir = Join-Path $BaseDir "export"
|
||||
$ZipFile = Join-Path $BaseDir "ODBC_Backup.zip"
|
||||
$LogFile = Join-Path $BaseDir "export_log.txt"
|
||||
|
||||
# Optional: Add local folders to search for installers
|
||||
$InstallerHuntPaths = @(
|
||||
"$env:USERPROFILE\Downloads",
|
||||
"C:\Installers",
|
||||
"C:\Drivers",
|
||||
"$env:PUBLIC\Downloads"
|
||||
) | Where-Object { Test-Path $_ }
|
||||
|
||||
# ===========================
|
||||
# PREP
|
||||
# ===========================
|
||||
New-Item -ItemType Directory -Path $ExportDir -Force | Out-Null
|
||||
Start-Transcript -Path $LogFile -Append
|
||||
Write-Host "Starting ODBC migration export..." -ForegroundColor Cyan
|
||||
|
||||
# ===========================
|
||||
# STEP 1: EXPORT BASELINE DATA
|
||||
# ===========================
|
||||
Write-Host "Exporting ODBC driver list..."
|
||||
$drivers = Get-OdbcDriver | Select-Object Name, Platform, Version, Attribute
|
||||
$driversCsv = Join-Path $ExportDir "odbc_drivers.csv"
|
||||
$drivers | Export-Csv -Path $driversCsv -NoTypeInformation -Encoding UTF8
|
||||
|
||||
Write-Host "Exporting DSNs..."
|
||||
$dsnsXml = Join-Path $ExportDir "odbc_dsns.xml"
|
||||
Get-OdbcDsn | Export-Clixml $dsnsXml
|
||||
|
||||
Write-Host "Exporting registry keys..."
|
||||
reg export "HKLM\SOFTWARE\ODBC\ODBC.INI" (Join-Path $ExportDir "ODBC_System.reg") /y | Out-Null
|
||||
reg export "HKCU\Software\ODBC\ODBC.INI" (Join-Path $ExportDir "ODBC_User.reg") /y | Out-Null
|
||||
$WowKey = "HKLM\SOFTWARE\WOW6432Node\ODBC\ODBC.INI"
|
||||
if (Test-Path "Registry::$WowKey") {
|
||||
reg export $WowKey (Join-Path $ExportDir "ODBC_System32.reg") /y | Out-Null
|
||||
Write-Host "Exported 32-bit ODBC keys."
|
||||
}
|
||||
|
||||
# ===========================
|
||||
# STEP 2: ENUMERATE INSTALLED PRODUCTS
|
||||
# ===========================
|
||||
Write-Host "Enumerating Add/Remove Programs entries..."
|
||||
function Get-UninstallEntries {
|
||||
$roots = @(
|
||||
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
|
||||
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
|
||||
"HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
|
||||
)
|
||||
foreach ($r in $roots) {
|
||||
if (Test-Path $r) {
|
||||
Get-ChildItem $r | ForEach-Object { Get-ItemProperty $_.PsPath }
|
||||
}
|
||||
}
|
||||
}
|
||||
$uninst = Get-UninstallEntries | Select-Object `
|
||||
DisplayName, DisplayVersion, Publisher, InstallLocation, UninstallString, ModifyPath, QuietUninstallString
|
||||
|
||||
# Tokenizer helper
|
||||
function Normalize([string]$s) {
|
||||
if (-not $s) { return "" }
|
||||
return (($s -replace '[^a-zA-Z0-9]+', ' ') -as [string]).Trim().ToLowerInvariant()
|
||||
}
|
||||
|
||||
# Map ODBC drivers -> installed programs
|
||||
Write-Host "Mapping ODBC drivers to installed programs..."
|
||||
$map = foreach ($d in $drivers) {
|
||||
$nameNorm = Normalize $d.Name
|
||||
$candidates = $uninst | Where-Object {
|
||||
$_.DisplayName -and (Normalize $_.DisplayName) -match ($nameNorm -replace '\s+','.*')
|
||||
}
|
||||
|
||||
if (-not $candidates -and $d.Name -match 'oracle|mysql|postgres|sql\s*server|mariadb|sqlite|snowflake|teradata|ibm|db2|progress|sybase|firebird|hana|vertica|redshift') {
|
||||
$kw = ($matches[0])
|
||||
$candidates = $uninst | Where-Object { $_.DisplayName -match $kw }
|
||||
}
|
||||
|
||||
[PSCustomObject]@{
|
||||
OdbcDriverName = $d.Name
|
||||
Platform = $d.Platform
|
||||
DriverVersion = $d.Version
|
||||
ProductName = ($candidates | Select-Object -First 1 -ExpandProperty DisplayName)
|
||||
ProductVersion = ($candidates | Select-Object -First 1 -ExpandProperty DisplayVersion)
|
||||
Publisher = ($candidates | Select-Object -First 1 -ExpandProperty Publisher)
|
||||
InstallLocation = ($candidates | Select-Object -First 1 -ExpandProperty InstallLocation)
|
||||
UninstallString = ($candidates | Select-Object -First 1 -ExpandProperty UninstallString)
|
||||
}
|
||||
}
|
||||
|
||||
# ===========================
|
||||
# STEP 3: ADD KNOWN VENDOR LINKS
|
||||
# ===========================
|
||||
Write-Host "Attaching known vendor download links..."
|
||||
|
||||
$vendorLinks = @{
|
||||
# --- Microsoft ---
|
||||
'odbc driver 18 for sql server' = 'https://learn.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server'
|
||||
'odbc driver 17 for sql server' = 'https://learn.microsoft.com/sql/connect/odbc/download-odbc-driver-for-sql-server'
|
||||
'sql server native client' = 'https://learn.microsoft.com/sql/relational-databases/native-client/applications/installing-sql-server-native-client'
|
||||
'microsoft access driver' = 'https://www.microsoft.com/download/details.aspx?id=54920'
|
||||
'microsoft excel driver' = 'https://www.microsoft.com/download/details.aspx?id=54920'
|
||||
'microsoft text driver' = 'https://www.microsoft.com/download/details.aspx?id=54920'
|
||||
'microsoft dbase driver' = 'https://www.microsoft.com/download/details.aspx?id=54920'
|
||||
'microsoft odbc for oracle' = 'https://learn.microsoft.com/sql/odbc/microsoft/odbc-driver-for-oracle'
|
||||
|
||||
# --- Oracle ---
|
||||
'oracle odbc driver' = 'https://www.oracle.com/database/technologies/releasenote-odbc-ic.html'
|
||||
'oracle in oraclient' = 'https://www.oracle.com/database/technologies/releasenote-odbc-ic.html'
|
||||
|
||||
# --- MySQL / MariaDB ---
|
||||
'mysql odbc' = 'https://dev.mysql.com/downloads/connector/odbc/'
|
||||
'mariadb odbc' = 'https://mariadb.com/products/connectors/odbc/'
|
||||
|
||||
# --- PostgreSQL ---
|
||||
'postgresql odbc' = 'https://odbc.postgresql.org/'
|
||||
'psqlodbc' = 'https://odbc.postgresql.org/'
|
||||
|
||||
# --- SQLite ---
|
||||
'sqlite odbc' = 'https://www.ch-werner.de/sqliteodbc/'
|
||||
|
||||
# --- IBM / Informix ---
|
||||
'ibm db2 odbc' = 'https://www.ibm.com/support/pages/db2-clients'
|
||||
'informix odbc' = 'https://www.ibm.com/support/pages/informix-odbc-driver'
|
||||
|
||||
# --- Snowflake ---
|
||||
'snowflake odbc' = 'https://developers.snowflake.com/odbc/'
|
||||
|
||||
# --- Teradata ---
|
||||
'teradata odbc' = 'https://downloads.teradata.com/connectivity/odbc-driver'
|
||||
|
||||
# --- Progress / OpenEdge ---
|
||||
'progress openedge odbc' = 'https://www.progress.com/odbc/openedge'
|
||||
'openedge odbc' = 'https://www.progress.com/odbc/openedge'
|
||||
|
||||
# --- SAP HANA ---
|
||||
'sap hana odbc' = 'https://tools.hana.ondemand.com/#hanatools'
|
||||
|
||||
# --- Amazon Redshift ---
|
||||
'redshift odbc' = 'https://docs.aws.amazon.com/redshift/latest/mgmt/configure-odbc-connection.html'
|
||||
|
||||
# --- Vertica ---
|
||||
'vertica odbc' = 'https://www.vertica.com/download/vertica/client-drivers/'
|
||||
|
||||
# --- Firebird ---
|
||||
'firebird odbc' = 'https://firebirdsql.org/en/odbc-driver/'
|
||||
|
||||
# --- Generic fallback ---
|
||||
'generic odbc driver' = 'https://www.microsoft.com/en-us/sql/connect/odbc/'
|
||||
}
|
||||
|
||||
foreach ($item in $map) {
|
||||
$norm = Normalize $item.OdbcDriverName
|
||||
$found = $false
|
||||
foreach ($key in $vendorLinks.Keys) {
|
||||
if ($norm -like "*$key*") {
|
||||
$item | Add-Member -NotePropertyName "DownloadURL" -NotePropertyValue $vendorLinks[$key]
|
||||
$found = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (-not $found) {
|
||||
$item | Add-Member -NotePropertyName "DownloadURL" -NotePropertyValue "Search manually"
|
||||
}
|
||||
}
|
||||
|
||||
# ===========================
|
||||
# STEP 4: FIND LOCAL INSTALLER FILES
|
||||
# ===========================
|
||||
Write-Host "Scanning for local installers..."
|
||||
$searchTerms = ($map.OdbcDriverName | Sort-Object -Unique)
|
||||
$installerHits = @()
|
||||
foreach ($p in $InstallerHuntPaths) {
|
||||
Get-ChildItem -Path $p -Recurse -ErrorAction SilentlyContinue -Include *.msi,*.exe |
|
||||
ForEach-Object {
|
||||
$fileNorm = Normalize $_.Name
|
||||
foreach ($term in $searchTerms) {
|
||||
$t = Normalize $term
|
||||
if ($fileNorm -match ($t -replace '\s+','.*')) {
|
||||
$installerHits += [PSCustomObject]@{
|
||||
Term = $term
|
||||
FileName = $_.Name
|
||||
FullPath = $_.FullName
|
||||
SizeMB = [math]::Round($_.Length/1MB,2)
|
||||
LastWrite = $_.LastWriteTime
|
||||
SearchRoot = $p
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# ===========================
|
||||
# STEP 5: REPORT OUTPUT
|
||||
# ===========================
|
||||
$mapCsv = Join-Path $ExportDir "odbc_driver_product_map.csv"
|
||||
$map | Export-Csv -Path $mapCsv -NoTypeInformation -Encoding UTF8
|
||||
$hitsCsv = Join-Path $ExportDir "odbc_installer_hits.csv"
|
||||
$installerHits | Export-Csv -Path $hitsCsv -NoTypeInformation -Encoding UTF8
|
||||
|
||||
$reportMd = Join-Path $ExportDir "ODBC_Migration_Report.md"
|
||||
@"
|
||||
# ODBC Migration Report
|
||||
|
||||
**Generated:** $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
|
||||
**Machine:** $env:COMPUTERNAME
|
||||
|
||||
## Summary
|
||||
- Drivers detected: $($drivers.Count)
|
||||
- DSNs exported: $((Get-OdbcDsn).Count)
|
||||
- Installer hits: $($installerHits.Count)
|
||||
|
||||
## Drivers & Product Mapping
|
||||
| ODBC Driver | Platform | Version | Product | Publisher | Download Link |
|
||||
|---|---:|---|---|---|---|
|
||||
$(
|
||||
($map | ForEach-Object {
|
||||
$dn = if ($_.OdbcDriverName) { $_.OdbcDriverName.Replace('|','-') } else { '' }
|
||||
$pf = $_.Platform
|
||||
$dv = $_.DriverVersion
|
||||
$pn = ($_.ProductName -replace '\|','-')
|
||||
$pu = ($_.Publisher -replace '\|','-')
|
||||
$dl = if ($_.DownloadURL -match '^https?') { "[Download]($($_.DownloadURL))" } else { $_.DownloadURL }
|
||||
"| $dn | $pf | $dv | $pn | $pu | $dl |"
|
||||
}) -join "`r`n"
|
||||
)
|
||||
|
||||
## Likely Local Installer Files
|
||||
| Matches Term | File | Size (MB) | Modified | Path |
|
||||
|---|---|---:|---|---|
|
||||
$(
|
||||
($installerHits | Sort-Object Term,FileName | ForEach-Object {
|
||||
"| $($_.Term) | $($_.FileName) | $($_.SizeMB) | $($_.LastWrite.ToString('yyyy-MM-dd')) | $($_.FullPath) |"
|
||||
}) -join "`r`n"
|
||||
)
|
||||
|
||||
## Next Steps
|
||||
1. On the **target PC**, install matching ODBC driver packages using the links above or your local installers.
|
||||
2. Then run **Restore-ODBC.ps1** to import DSNs and registry settings.
|
||||
3. Verify DSNs in *ODBC Data Source Administrator* (both 32-bit and 64-bit).
|
||||
"@ | Out-File -FilePath $reportMd -Encoding UTF8
|
||||
|
||||
# ===========================
|
||||
# STEP 6: ZIP PACKAGE
|
||||
# ===========================
|
||||
if (Test-Path $ZipFile) { Remove-Item $ZipFile -Force }
|
||||
Compress-Archive -Path "$ExportDir\*" -DestinationPath $ZipFile -Force
|
||||
|
||||
Write-Host "Export complete. ZIP created at: $ZipFile" -ForegroundColor Green
|
||||
Stop-Transcript
|
||||
115
restore-ODBC.ps1
Normal file
115
restore-ODBC.ps1
Normal file
@@ -0,0 +1,115 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Restore ODBC DSNs and registry keys, and identify missing drivers.
|
||||
|
||||
.DESCRIPTION
|
||||
- Extracts ODBC_Backup.zip into C:\ODBC_Migration\restore
|
||||
- Imports all .reg and .xml files
|
||||
- Recreates DSNs
|
||||
- Compares exported vs installed ODBC drivers
|
||||
- Displays missing drivers with official vendor download links
|
||||
- Logs all operations
|
||||
#>
|
||||
|
||||
# ===========================
|
||||
# CONFIGURATION
|
||||
# ===========================
|
||||
$BaseDir = "C:\ODBC_Migration"
|
||||
$ZipFile = Join-Path $BaseDir "ODBC_Backup.zip"
|
||||
$ExtractDir = Join-Path $BaseDir "restore"
|
||||
$LogFile = Join-Path $BaseDir ("restore_log_" + (Get-Date -Format "yyyyMMdd_HHmm") + ".txt")
|
||||
|
||||
# ===========================
|
||||
# PREP
|
||||
# ===========================
|
||||
New-Item -ItemType Directory -Path $ExtractDir -Force | Out-Null
|
||||
Start-Transcript -Path $LogFile -Append
|
||||
Write-Host "`n=== ODBC RESTORE STARTED ===`n" -ForegroundColor Cyan
|
||||
|
||||
# ===========================
|
||||
# STEP 1: EXTRACT ZIP PACKAGE
|
||||
# ===========================
|
||||
if (-not (Test-Path $ZipFile)) {
|
||||
Write-Error "Cannot find ODBC_Backup.zip in $BaseDir"
|
||||
Stop-Transcript
|
||||
exit 1
|
||||
}
|
||||
Write-Host "Extracting archive..."
|
||||
Expand-Archive -Path $ZipFile -DestinationPath $ExtractDir -Force
|
||||
|
||||
# ===========================
|
||||
# STEP 2: IMPORT REGISTRY KEYS
|
||||
# ===========================
|
||||
Write-Host "Importing registry keys..."
|
||||
$regFiles = Get-ChildItem $ExtractDir -Filter *.reg
|
||||
foreach ($reg in $regFiles) {
|
||||
Write-Host " -> $($reg.Name)"
|
||||
reg import $reg.FullName | Out-Null
|
||||
}
|
||||
|
||||
# ===========================
|
||||
# STEP 3: RESTORE DSNs
|
||||
# ===========================
|
||||
$xmlPath = Join-Path $ExtractDir "odbc_dsns.xml"
|
||||
if (Test-Path $xmlPath) {
|
||||
Write-Host "Recreating DSNs from XML..."
|
||||
$dsns = Import-Clixml $xmlPath
|
||||
foreach ($dsn in $dsns) {
|
||||
try {
|
||||
Add-OdbcDsn @dsn -ErrorAction Stop
|
||||
Write-Host " + Added DSN: $($dsn.Name)" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Warning " ! Failed to add DSN: $($dsn.Name) - $_"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Warning "No odbc_dsns.xml found in package."
|
||||
}
|
||||
|
||||
# ===========================
|
||||
# STEP 4: VERIFY DRIVER PRESENCE
|
||||
# ===========================
|
||||
Write-Host "`nChecking for missing ODBC drivers..." -ForegroundColor Yellow
|
||||
$exportCsv = Join-Path $ExtractDir "odbc_driver_product_map.csv"
|
||||
if (-not (Test-Path $exportCsv)) {
|
||||
Write-Warning "No driver map CSV found — skipping driver comparison."
|
||||
} else {
|
||||
$needed = Import-Csv $exportCsv
|
||||
$installed = Get-OdbcDriver | Select-Object -ExpandProperty Name
|
||||
|
||||
$missing = @()
|
||||
foreach ($n in $needed) {
|
||||
if ($n.OdbcDriverName -and ($installed -notcontains $n.OdbcDriverName)) {
|
||||
$missing += $n
|
||||
}
|
||||
}
|
||||
|
||||
if ($missing.Count -gt 0) {
|
||||
Write-Host "`n=== Missing ODBC Drivers Detected ===`n" -ForegroundColor Red
|
||||
foreach ($m in $missing) {
|
||||
$dl = $m.DownloadURL
|
||||
if ($dl -match '^https?') {
|
||||
Write-Host (" - {0} ({1})`n Download: {2}" -f $m.OdbcDriverName, $m.Platform, $dl) -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host (" - {0} ({1})`n Download: [Manual search required]" -f $m.OdbcDriverName, $m.Platform) -ForegroundColor DarkYellow
|
||||
}
|
||||
}
|
||||
Write-Host "`nSee the detailed Markdown report for clickable links:" -ForegroundColor Cyan
|
||||
Write-Host " $($ExtractDir)\ODBC_Migration_Report.md`n" -ForegroundColor White
|
||||
} else {
|
||||
Write-Host "All previously detected drivers are installed." -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
|
||||
# ===========================
|
||||
# STEP 5: SUMMARY
|
||||
# ===========================
|
||||
Write-Host "`n=== RESTORE COMPLETE ===`n" -ForegroundColor Cyan
|
||||
Write-Host "✔ Registry and DSNs restored"
|
||||
Write-Host "✔ Logs saved to: $LogFile"
|
||||
Write-Host "✔ Extracted files in: $ExtractDir"
|
||||
Write-Host "`nNext Steps:"
|
||||
Write-Host "1️⃣ Verify DSNs in ODBC Administrator (32-bit and 64-bit)."
|
||||
Write-Host "2️⃣ Install any missing drivers listed above."
|
||||
Write-Host "3️⃣ Re-run this script if needed after driver installation.`n"
|
||||
Stop-Transcript
|
||||
Reference in New Issue
Block a user