Add ROA Oracle Database Windows setup scripts with old client support
PowerShell scripts for setting up Oracle 21c/XE with ROA application: - Automated tablespace, user creation and imports - sqlnet.ora config for Instant Client 11g/ODBC compatibility - Oracle 21c read-only Home path handling (homes/OraDB21Home1) - Listener restart + 10G password verifier for legacy auth - Tested on VM 302 with CONTAFIN_ORACLE schema import Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,300 @@
|
||||
#Requires -Version 5.1
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Logging utility functions for ROA Oracle setup scripts.
|
||||
|
||||
.DESCRIPTION
|
||||
Provides standardized logging functions with timestamps, colors, and file output.
|
||||
All log messages are written to both console and optional log file.
|
||||
|
||||
.NOTES
|
||||
File Name : logging-functions.ps1
|
||||
Prerequisite : PowerShell 5.1 or higher
|
||||
Copyright 2024 : ROMFAST
|
||||
#>
|
||||
|
||||
# Script-level variables for logging
|
||||
$script:LogFile = $null
|
||||
$script:LogLevel = 'Info'
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Initialize the log file with a header.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates or clears a log file and writes a header with timestamp and script info.
|
||||
|
||||
.PARAMETER LogPath
|
||||
Path to the log file.
|
||||
|
||||
.PARAMETER ScriptName
|
||||
Name of the calling script for the header.
|
||||
|
||||
.EXAMPLE
|
||||
Initialize-LogFile -LogPath "C:\logs\setup.log" -ScriptName "01-setup-database.ps1"
|
||||
#>
|
||||
function Initialize-LogFile {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$LogPath,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$ScriptName = "ROA Setup"
|
||||
)
|
||||
|
||||
$script:LogFile = $LogPath
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
$logDir = Split-Path -Path $LogPath -Parent
|
||||
if ($logDir -and -not (Test-Path -Path $logDir)) {
|
||||
New-Item -ItemType Directory -Path $logDir -Force | Out-Null
|
||||
}
|
||||
|
||||
# Write header
|
||||
$header = @"
|
||||
================================================================================
|
||||
ROA Oracle Setup Log
|
||||
Script: $ScriptName
|
||||
Started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
|
||||
Computer: $env:COMPUTERNAME
|
||||
User: $env:USERNAME
|
||||
================================================================================
|
||||
|
||||
"@
|
||||
|
||||
Set-Content -Path $LogPath -Value $header -Encoding UTF8
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write a log message with timestamp.
|
||||
|
||||
.DESCRIPTION
|
||||
Writes a timestamped message to console and log file. Supports different
|
||||
message types (Info, Warning, Error, Success, Debug).
|
||||
|
||||
.PARAMETER Message
|
||||
The message to log.
|
||||
|
||||
.PARAMETER Level
|
||||
The log level: Info, Warning, Error, Success, Debug.
|
||||
|
||||
.PARAMETER NoConsole
|
||||
If specified, only writes to log file.
|
||||
|
||||
.EXAMPLE
|
||||
Write-Log "Starting database setup" -Level Info
|
||||
#>
|
||||
function Write-Log {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Message,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet('Info', 'Warning', 'Error', 'Success', 'Debug')]
|
||||
[string]$Level = 'Info',
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$NoConsole
|
||||
)
|
||||
|
||||
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
|
||||
$logMessage = "[$timestamp] [$Level] $Message"
|
||||
|
||||
# Write to log file if initialized
|
||||
if ($script:LogFile) {
|
||||
Add-Content -Path $script:LogFile -Value $logMessage -Encoding UTF8
|
||||
}
|
||||
|
||||
# Write to console with appropriate color
|
||||
if (-not $NoConsole) {
|
||||
$color = switch ($Level) {
|
||||
'Info' { 'White' }
|
||||
'Warning' { 'Yellow' }
|
||||
'Error' { 'Red' }
|
||||
'Success' { 'Green' }
|
||||
'Debug' { 'Cyan' }
|
||||
default { 'White' }
|
||||
}
|
||||
|
||||
$prefix = switch ($Level) {
|
||||
'Info' { '[INFO] ' }
|
||||
'Warning' { '[WARN] ' }
|
||||
'Error' { '[ERROR] ' }
|
||||
'Success' { '[OK] ' }
|
||||
'Debug' { '[DEBUG] ' }
|
||||
default { '[INFO] ' }
|
||||
}
|
||||
|
||||
Write-Host "$prefix$Message" -ForegroundColor $color
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write an error message in red.
|
||||
|
||||
.DESCRIPTION
|
||||
Convenience function for logging error messages.
|
||||
|
||||
.PARAMETER Message
|
||||
The error message to log.
|
||||
|
||||
.EXAMPLE
|
||||
Write-LogError "Failed to connect to database"
|
||||
#>
|
||||
function Write-LogError {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Message
|
||||
)
|
||||
|
||||
Write-Log -Message $Message -Level Error
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write a success message in green.
|
||||
|
||||
.DESCRIPTION
|
||||
Convenience function for logging success messages.
|
||||
|
||||
.PARAMETER Message
|
||||
The success message to log.
|
||||
|
||||
.EXAMPLE
|
||||
Write-LogSuccess "Database created successfully"
|
||||
#>
|
||||
function Write-LogSuccess {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Message
|
||||
)
|
||||
|
||||
Write-Log -Message $Message -Level Success
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write a warning message in yellow.
|
||||
|
||||
.DESCRIPTION
|
||||
Convenience function for logging warning messages.
|
||||
|
||||
.PARAMETER Message
|
||||
The warning message to log.
|
||||
|
||||
.EXAMPLE
|
||||
Write-LogWarning "User already exists, skipping creation"
|
||||
#>
|
||||
function Write-LogWarning {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Message
|
||||
)
|
||||
|
||||
Write-Log -Message $Message -Level Warning
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write a debug message in cyan.
|
||||
|
||||
.DESCRIPTION
|
||||
Convenience function for logging debug messages.
|
||||
|
||||
.PARAMETER Message
|
||||
The debug message to log.
|
||||
|
||||
.EXAMPLE
|
||||
Write-LogDebug "SQL command: SELECT * FROM dual"
|
||||
#>
|
||||
function Write-LogDebug {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Message
|
||||
)
|
||||
|
||||
Write-Log -Message $Message -Level Debug
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Write a section header to the log.
|
||||
|
||||
.DESCRIPTION
|
||||
Writes a formatted section header for visual separation in logs.
|
||||
|
||||
.PARAMETER Title
|
||||
The section title.
|
||||
|
||||
.EXAMPLE
|
||||
Write-LogSection "Creating Tablespace ROA"
|
||||
#>
|
||||
function Write-LogSection {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0)]
|
||||
[string]$Title
|
||||
)
|
||||
|
||||
$separator = "=" * 60
|
||||
$message = @"
|
||||
|
||||
$separator
|
||||
$Title
|
||||
$separator
|
||||
"@
|
||||
|
||||
if ($script:LogFile) {
|
||||
Add-Content -Path $script:LogFile -Value $message -Encoding UTF8
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host $separator -ForegroundColor Cyan
|
||||
Write-Host " $Title" -ForegroundColor Cyan
|
||||
Write-Host $separator -ForegroundColor Cyan
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Close the log file with a footer.
|
||||
|
||||
.DESCRIPTION
|
||||
Writes a closing footer to the log file with completion status.
|
||||
|
||||
.PARAMETER Success
|
||||
Indicates if the script completed successfully.
|
||||
|
||||
.EXAMPLE
|
||||
Close-LogFile -Success $true
|
||||
#>
|
||||
function Close-LogFile {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[bool]$Success = $true
|
||||
)
|
||||
|
||||
if ($script:LogFile) {
|
||||
$status = if ($Success) { "COMPLETED SUCCESSFULLY" } else { "COMPLETED WITH ERRORS" }
|
||||
$footer = @"
|
||||
|
||||
================================================================================
|
||||
$status
|
||||
Finished: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')
|
||||
================================================================================
|
||||
"@
|
||||
Add-Content -Path $script:LogFile -Value $footer -Encoding UTF8
|
||||
}
|
||||
}
|
||||
|
||||
# Note: Functions are available when dot-sourced (. .\logging-functions.ps1)
|
||||
# Do NOT use Export-ModuleMember - it only works inside .psm1 modules
|
||||
@@ -0,0 +1,952 @@
|
||||
#Requires -Version 5.1
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Oracle connectivity and operations functions for ROA setup scripts.
|
||||
|
||||
.DESCRIPTION
|
||||
Provides functions for Oracle database connectivity, SQL*Plus execution,
|
||||
version detection, and Data Pump operations.
|
||||
|
||||
.NOTES
|
||||
File Name : oracle-functions.ps1
|
||||
Prerequisite : PowerShell 5.1 or higher, Oracle Client installed
|
||||
Copyright 2024 : ROMFAST
|
||||
#>
|
||||
|
||||
# Source logging functions
|
||||
. "$PSScriptRoot\logging-functions.ps1"
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Find Oracle Home directory.
|
||||
|
||||
.DESCRIPTION
|
||||
Auto-detects Oracle Home from registry, environment variable, or common paths.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Optional explicit Oracle Home path. If not specified, auto-detects.
|
||||
|
||||
.OUTPUTS
|
||||
String. The Oracle Home path.
|
||||
|
||||
.EXAMPLE
|
||||
$oracleHome = Get-OracleHome
|
||||
#>
|
||||
function Get-OracleHome {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome
|
||||
)
|
||||
|
||||
# If explicitly provided, validate and return
|
||||
if ($OracleHome) {
|
||||
if (Test-Path -Path "$OracleHome\bin\sqlplus.exe") {
|
||||
return $OracleHome
|
||||
}
|
||||
throw "Invalid Oracle Home: sqlplus.exe not found at $OracleHome\bin\sqlplus.exe"
|
||||
}
|
||||
|
||||
# Try ORACLE_HOME environment variable
|
||||
if ($env:ORACLE_HOME -and (Test-Path -Path "$env:ORACLE_HOME\bin\sqlplus.exe")) {
|
||||
return $env:ORACLE_HOME
|
||||
}
|
||||
|
||||
# Try registry for Oracle XE
|
||||
$regPaths = @(
|
||||
'HKLM:\SOFTWARE\Oracle\KEY_OraDB21Home1',
|
||||
'HKLM:\SOFTWARE\Oracle\KEY_OraDB18Home1',
|
||||
'HKLM:\SOFTWARE\Oracle\KEY_XE',
|
||||
'HKLM:\SOFTWARE\Wow6432Node\Oracle\KEY_OraDB21Home1',
|
||||
'HKLM:\SOFTWARE\Wow6432Node\Oracle\KEY_OraDB18Home1'
|
||||
)
|
||||
|
||||
foreach ($regPath in $regPaths) {
|
||||
if (Test-Path -Path $regPath) {
|
||||
$oraHome = (Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue).ORACLE_HOME
|
||||
if ($oraHome -and (Test-Path -Path "$oraHome\bin\sqlplus.exe")) {
|
||||
return $oraHome
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Try common installation paths (including user-specific paths)
|
||||
$currentUser = $env:USERNAME
|
||||
$commonPaths = @(
|
||||
"C:\app\$currentUser\product\21c\dbhomeXE",
|
||||
"C:\app\$currentUser\product\21c\dbhome_1",
|
||||
"C:\app\$currentUser\product\18c\dbhomeXE",
|
||||
'C:\app\oracle\product\21c\dbhomeXE',
|
||||
'C:\app\oracle\product\21c\dbhome_1',
|
||||
'C:\app\oracle\product\18c\dbhomeXE',
|
||||
'C:\app\romfast\product\21c\dbhomeXE',
|
||||
'C:\app\romfast\product\21c\dbhome_1',
|
||||
'C:\oraclexe\app\oracle\product\11.2.0\server',
|
||||
"D:\app\$currentUser\product\21c\dbhomeXE",
|
||||
'D:\app\oracle\product\21c\dbhomeXE',
|
||||
'D:\app\oracle\product\18c\dbhomeXE'
|
||||
)
|
||||
|
||||
foreach ($path in $commonPaths) {
|
||||
if (Test-Path -Path "$path\bin\sqlplus.exe") {
|
||||
return $path
|
||||
}
|
||||
}
|
||||
|
||||
throw "Oracle Home not found. Please specify -OracleHome parameter or set ORACLE_HOME environment variable."
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get Oracle version information.
|
||||
|
||||
.DESCRIPTION
|
||||
Detects Oracle version (XE vs SE), edition, and whether it's a Container Database (CDB).
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Username
|
||||
Username for connection (default: SYSTEM).
|
||||
|
||||
.PARAMETER Password
|
||||
Password for connection.
|
||||
|
||||
.OUTPUTS
|
||||
PSCustomObject with Version, Edition, IsCDB, IsXE properties.
|
||||
|
||||
.EXAMPLE
|
||||
$version = Get-OracleVersion -ServiceName "XE" -Password "oracle"
|
||||
#>
|
||||
function Get-OracleVersion {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Username = "SYSTEM",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password
|
||||
)
|
||||
|
||||
$oraHome = Get-OracleHome -OracleHome $OracleHome
|
||||
|
||||
$sql = @"
|
||||
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
|
||||
SELECT 'VERSION:' || version_full FROM v`$instance;
|
||||
SELECT 'EDITION:' || edition FROM v`$instance;
|
||||
SELECT 'CDB:' || CDB FROM v`$database;
|
||||
EXIT;
|
||||
"@
|
||||
|
||||
$result = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
|
||||
-Username $Username -Password $Password -SqlCommand $sql -Silent
|
||||
|
||||
$versionInfo = [PSCustomObject]@{
|
||||
Version = ""
|
||||
Edition = ""
|
||||
IsCDB = $false
|
||||
IsXE = $false
|
||||
FullInfo = $result
|
||||
}
|
||||
|
||||
foreach ($line in $result -split "`n") {
|
||||
if ($line -match "^VERSION:(.+)$") {
|
||||
$versionInfo.Version = $Matches[1].Trim()
|
||||
}
|
||||
elseif ($line -match "^EDITION:(.+)$") {
|
||||
$versionInfo.Edition = $Matches[1].Trim()
|
||||
$versionInfo.IsXE = $versionInfo.Edition -match "XE|Express"
|
||||
}
|
||||
elseif ($line -match "^CDB:(.+)$") {
|
||||
$versionInfo.IsCDB = $Matches[1].Trim() -eq "YES"
|
||||
}
|
||||
}
|
||||
|
||||
return $versionInfo
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the default service name based on Oracle configuration.
|
||||
|
||||
.DESCRIPTION
|
||||
Auto-detects the appropriate service name. Returns XEPDB1 for Oracle XE CDB,
|
||||
or ROA for traditional non-CDB installations.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER SystemPassword
|
||||
SYSTEM user password.
|
||||
|
||||
.OUTPUTS
|
||||
String. The service name.
|
||||
|
||||
.EXAMPLE
|
||||
$serviceName = Get-ServiceName -SystemPassword "oracle"
|
||||
#>
|
||||
function Get-ServiceName {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SystemPassword
|
||||
)
|
||||
|
||||
$oraHome = Get-OracleHome -OracleHome $OracleHome
|
||||
|
||||
# First try to connect to XE and check if it's CDB
|
||||
try {
|
||||
$version = Get-OracleVersion -OracleHome $oraHome -ServiceName "XE" `
|
||||
-Password $SystemPassword -ErrorAction Stop
|
||||
|
||||
if ($version.IsCDB) {
|
||||
# For CDB, use XEPDB1 (the default pluggable database)
|
||||
return "XEPDB1"
|
||||
}
|
||||
else {
|
||||
return "XE"
|
||||
}
|
||||
}
|
||||
catch {
|
||||
# Try ROA as service name
|
||||
try {
|
||||
$null = Test-OracleConnection -OracleHome $oraHome -ServiceName "ROA" `
|
||||
-Username "SYSTEM" -Password $SystemPassword -ErrorAction Stop
|
||||
return "ROA"
|
||||
}
|
||||
catch {
|
||||
# Default to XEPDB1 for modern XE installations
|
||||
return "XEPDB1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Test Oracle database connection.
|
||||
|
||||
.DESCRIPTION
|
||||
Attempts to connect to Oracle and verifies the connection is successful.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Username
|
||||
Username for connection.
|
||||
|
||||
.PARAMETER Password
|
||||
Password for connection.
|
||||
|
||||
.OUTPUTS
|
||||
Boolean. True if connection successful.
|
||||
|
||||
.EXAMPLE
|
||||
if (Test-OracleConnection -ServiceName "XEPDB1" -Username "SYSTEM" -Password "oracle") {
|
||||
Write-Host "Connected!"
|
||||
}
|
||||
#>
|
||||
function Test-OracleConnection {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Username = "SYSTEM",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$AsSysdba
|
||||
)
|
||||
|
||||
$oraHome = Get-OracleHome -OracleHome $OracleHome
|
||||
|
||||
$sql = "SELECT 'CONNECTED' FROM dual; EXIT;"
|
||||
|
||||
try {
|
||||
$result = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
|
||||
-Username $Username -Password $Password -SqlCommand $sql -AsSysdba:$AsSysdba -Silent
|
||||
|
||||
return $result -match "CONNECTED"
|
||||
}
|
||||
catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Test if connected to a PDB or non-CDB.
|
||||
|
||||
.DESCRIPTION
|
||||
Checks the current container type to determine if connected to a PDB,
|
||||
the CDB root, or a non-CDB database.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Username
|
||||
Username for connection.
|
||||
|
||||
.PARAMETER Password
|
||||
Password for connection.
|
||||
|
||||
.OUTPUTS
|
||||
PSCustomObject with ContainerName, IsPDB, IsCDBRoot, IsNonCDB properties.
|
||||
|
||||
.EXAMPLE
|
||||
$containerInfo = Test-PDB -ServiceName "XEPDB1" -Password "oracle"
|
||||
#>
|
||||
function Test-PDB {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Username = "SYSTEM",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password
|
||||
)
|
||||
|
||||
$oraHome = Get-OracleHome -OracleHome $OracleHome
|
||||
|
||||
$sql = @"
|
||||
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
|
||||
SELECT 'CONTAINER:' || SYS_CONTEXT('USERENV', 'CON_NAME') FROM dual;
|
||||
SELECT 'CON_ID:' || SYS_CONTEXT('USERENV', 'CON_ID') FROM dual;
|
||||
EXIT;
|
||||
"@
|
||||
|
||||
$result = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
|
||||
-Username $Username -Password $Password -SqlCommand $sql -Silent
|
||||
|
||||
$containerInfo = [PSCustomObject]@{
|
||||
ContainerName = ""
|
||||
ConId = 0
|
||||
IsPDB = $false
|
||||
IsCDBRoot = $false
|
||||
IsNonCDB = $false
|
||||
}
|
||||
|
||||
foreach ($line in $result -split "`n") {
|
||||
if ($line -match "^CONTAINER:(.+)$") {
|
||||
$containerInfo.ContainerName = $Matches[1].Trim()
|
||||
}
|
||||
elseif ($line -match "^CON_ID:(.+)$") {
|
||||
$containerInfo.ConId = [int]$Matches[1].Trim()
|
||||
}
|
||||
}
|
||||
|
||||
if ($containerInfo.ConId -eq 0) {
|
||||
$containerInfo.IsNonCDB = $true
|
||||
}
|
||||
elseif ($containerInfo.ConId -eq 1) {
|
||||
$containerInfo.IsCDBRoot = $true
|
||||
}
|
||||
else {
|
||||
$containerInfo.IsPDB = $true
|
||||
}
|
||||
|
||||
return $containerInfo
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Execute SQL via SQL*Plus.
|
||||
|
||||
.DESCRIPTION
|
||||
Runs a SQL command or file using SQL*Plus and returns the output.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Username
|
||||
Username for connection.
|
||||
|
||||
.PARAMETER Password
|
||||
Password for connection.
|
||||
|
||||
.PARAMETER SqlCommand
|
||||
SQL command(s) to execute.
|
||||
|
||||
.PARAMETER SqlFile
|
||||
Path to SQL file to execute.
|
||||
|
||||
.PARAMETER AsSysdba
|
||||
Connect as SYSDBA.
|
||||
|
||||
.PARAMETER Silent
|
||||
Suppress console output.
|
||||
|
||||
.OUTPUTS
|
||||
String. The SQL*Plus output.
|
||||
|
||||
.EXAMPLE
|
||||
Invoke-SqlPlus -ServiceName "XEPDB1" -Username "SYSTEM" -Password "oracle" -SqlCommand "SELECT * FROM dual;"
|
||||
|
||||
.EXAMPLE
|
||||
Invoke-SqlPlus -ServiceName "XEPDB1" -Username "SYS" -Password "oracle" -SqlFile "C:\scripts\setup.sql" -AsSysdba
|
||||
#>
|
||||
function Invoke-SqlPlus {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Username = "SYSTEM",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$SqlCommand,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$SqlFile,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$AsSysdba,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$Silent
|
||||
)
|
||||
|
||||
$oraHome = Get-OracleHome -OracleHome $OracleHome
|
||||
$sqlplus = Join-Path $oraHome "bin\sqlplus.exe"
|
||||
|
||||
if (-not (Test-Path -Path $sqlplus)) {
|
||||
throw "SQL*Plus not found at: $sqlplus"
|
||||
}
|
||||
|
||||
# Build connection string
|
||||
$sysdba = if ($AsSysdba) { " as sysdba" } else { "" }
|
||||
$connString = "$Username/`"$Password`"@$ServiceName$sysdba"
|
||||
|
||||
$tempFile = $null
|
||||
|
||||
try {
|
||||
if ($SqlFile) {
|
||||
# Execute SQL file
|
||||
if (-not (Test-Path -Path $SqlFile)) {
|
||||
throw "SQL file not found: $SqlFile"
|
||||
}
|
||||
|
||||
$arguments = "-S `"$connString`" @`"$SqlFile`""
|
||||
}
|
||||
else {
|
||||
# Create temp file for SQL command
|
||||
$tempFile = [System.IO.Path]::GetTempFileName()
|
||||
$tempFile = [System.IO.Path]::ChangeExtension($tempFile, ".sql")
|
||||
Set-Content -Path $tempFile -Value $SqlCommand -Encoding ASCII
|
||||
|
||||
$arguments = "-S `"$connString`" @`"$tempFile`""
|
||||
}
|
||||
|
||||
# Set Oracle environment
|
||||
$env:ORACLE_HOME = $oraHome
|
||||
$env:PATH = "$oraHome\bin;$env:PATH"
|
||||
$env:NLS_LANG = "AMERICAN_AMERICA.AL32UTF8"
|
||||
|
||||
# Execute SQL*Plus
|
||||
$processInfo = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$processInfo.FileName = $sqlplus
|
||||
$processInfo.Arguments = "-S `"$connString`""
|
||||
$processInfo.RedirectStandardInput = $true
|
||||
$processInfo.RedirectStandardOutput = $true
|
||||
$processInfo.RedirectStandardError = $true
|
||||
$processInfo.UseShellExecute = $false
|
||||
$processInfo.CreateNoWindow = $true
|
||||
|
||||
$process = New-Object System.Diagnostics.Process
|
||||
$process.StartInfo = $processInfo
|
||||
$process.Start() | Out-Null
|
||||
|
||||
# Send SQL
|
||||
if ($SqlFile) {
|
||||
$process.StandardInput.WriteLine("@`"$SqlFile`"")
|
||||
}
|
||||
else {
|
||||
$process.StandardInput.WriteLine($SqlCommand)
|
||||
}
|
||||
$process.StandardInput.Close()
|
||||
|
||||
$output = $process.StandardOutput.ReadToEnd()
|
||||
$errorOutput = $process.StandardError.ReadToEnd()
|
||||
$process.WaitForExit()
|
||||
|
||||
if ($errorOutput) {
|
||||
$output += "`n$errorOutput"
|
||||
}
|
||||
|
||||
# Check for Oracle errors
|
||||
if ($output -match "ORA-\d{5}:|SP2-\d{4}:") {
|
||||
if (-not $Silent) {
|
||||
Write-LogWarning "SQL*Plus returned errors:"
|
||||
Write-Host $output -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
return $output
|
||||
}
|
||||
finally {
|
||||
if ($tempFile -and (Test-Path -Path $tempFile)) {
|
||||
Remove-Item -Path $tempFile -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Create Oracle directory object for Data Pump.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates a directory object in Oracle for Data Pump operations if it doesn't exist.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Password
|
||||
SYS or SYSTEM password.
|
||||
|
||||
.PARAMETER DirectoryName
|
||||
Oracle directory object name (default: DMPDIR).
|
||||
|
||||
.PARAMETER DirectoryPath
|
||||
File system path for the directory (default: C:\DMPDIR).
|
||||
|
||||
.EXAMPLE
|
||||
New-OracleDirectory -ServiceName "XEPDB1" -Password "oracle" -DirectoryPath "D:\Dumps"
|
||||
#>
|
||||
function New-OracleDirectory {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$DirectoryName = "DMPDIR",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$DirectoryPath = "C:\DMPDIR"
|
||||
)
|
||||
|
||||
# Create physical directory if it doesn't exist
|
||||
if (-not (Test-Path -Path $DirectoryPath)) {
|
||||
New-Item -ItemType Directory -Path $DirectoryPath -Force | Out-Null
|
||||
Write-Log "Created directory: $DirectoryPath"
|
||||
}
|
||||
|
||||
$sql = @"
|
||||
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
|
||||
CREATE OR REPLACE DIRECTORY $DirectoryName AS '$DirectoryPath';
|
||||
GRANT READ, WRITE ON DIRECTORY $DirectoryName TO PUBLIC;
|
||||
COMMIT;
|
||||
SELECT 'DIRECTORY_CREATED' FROM dual;
|
||||
EXIT;
|
||||
"@
|
||||
|
||||
$result = Invoke-SqlPlus -OracleHome $OracleHome -ServiceName $ServiceName `
|
||||
-Username "SYS" -Password $Password -SqlCommand $sql -AsSysdba -Silent
|
||||
|
||||
if ($result -match "DIRECTORY_CREATED") {
|
||||
Write-Log "Oracle directory $DirectoryName created pointing to $DirectoryPath"
|
||||
return $true
|
||||
}
|
||||
else {
|
||||
Write-LogWarning "Could not verify directory creation"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get the default datafile path based on Oracle installation.
|
||||
|
||||
.DESCRIPTION
|
||||
Determines the appropriate datafile location based on Oracle Home and version.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Password
|
||||
SYSTEM password.
|
||||
|
||||
.OUTPUTS
|
||||
String. The datafile directory path.
|
||||
|
||||
.EXAMPLE
|
||||
$datafilePath = Get-DatafilePath -ServiceName "XEPDB1" -Password "oracle"
|
||||
#>
|
||||
function Get-DatafilePath {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password
|
||||
)
|
||||
|
||||
$oraHome = Get-OracleHome -OracleHome $OracleHome
|
||||
|
||||
# Query Oracle for default datafile location
|
||||
$sql = @"
|
||||
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF LINESIZE 500
|
||||
SELECT 'DATAFILE_PATH:' || SUBSTR(file_name, 1, INSTR(file_name, '\', -1))
|
||||
FROM dba_data_files
|
||||
WHERE tablespace_name = 'SYSTEM'
|
||||
AND ROWNUM = 1;
|
||||
EXIT;
|
||||
"@
|
||||
|
||||
$result = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
|
||||
-Username "SYSTEM" -Password $Password -SqlCommand $sql -Silent
|
||||
|
||||
foreach ($line in $result -split "`n") {
|
||||
if ($line -match "^DATAFILE_PATH:(.+)$") {
|
||||
$path = $Matches[1].Trim()
|
||||
# Remove trailing backslash if present
|
||||
return $path.TrimEnd('\')
|
||||
}
|
||||
}
|
||||
|
||||
# Fallback to common paths based on Oracle Home
|
||||
$version = Get-OracleVersion -OracleHome $oraHome -ServiceName $ServiceName -Password $Password
|
||||
|
||||
if ($version.IsXE) {
|
||||
if ($version.Version -match "^21") {
|
||||
return "C:\app\oracle\oradata\XE\XEPDB1"
|
||||
}
|
||||
elseif ($version.Version -match "^18") {
|
||||
return "C:\app\oracle\oradata\XE"
|
||||
}
|
||||
}
|
||||
|
||||
# Default fallback
|
||||
return "C:\app\oracle\oradata"
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Execute Data Pump import.
|
||||
|
||||
.DESCRIPTION
|
||||
Runs impdp with specified parameters.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Username
|
||||
Username for connection (default: SYSTEM).
|
||||
|
||||
.PARAMETER Password
|
||||
Password for connection.
|
||||
|
||||
.PARAMETER DumpFile
|
||||
Name of the dump file (in DMPDIR).
|
||||
|
||||
.PARAMETER LogFile
|
||||
Name of the log file.
|
||||
|
||||
.PARAMETER Schemas
|
||||
Schema(s) to import.
|
||||
|
||||
.PARAMETER RemapSchema
|
||||
Remap schema mapping (e.g., "OLD_SCHEMA:NEW_SCHEMA").
|
||||
|
||||
.PARAMETER DirectoryName
|
||||
Oracle directory object name (default: DMPDIR).
|
||||
|
||||
.PARAMETER TableExists
|
||||
Table exists action: SKIP, APPEND, TRUNCATE, REPLACE (default: REPLACE).
|
||||
|
||||
.PARAMETER AdditionalParams
|
||||
Additional impdp parameters.
|
||||
|
||||
.OUTPUTS
|
||||
PSCustomObject with Success, LogContent, ErrorMessage properties.
|
||||
|
||||
.EXAMPLE
|
||||
Invoke-DataPumpImport -ServiceName "XEPDB1" -Password "oracle" -DumpFile "CONTAFIN_ORACLE.dmp" -Schemas "CONTAFIN_ORACLE"
|
||||
#>
|
||||
function Invoke-DataPumpImport {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$Username = "SYSTEM",
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$DumpFile,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$LogFile,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string[]]$Schemas,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$RemapSchema,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$DirectoryName = "DMPDIR",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet('SKIP', 'APPEND', 'TRUNCATE', 'REPLACE')]
|
||||
[string]$TableExists = "REPLACE",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$AdditionalParams
|
||||
)
|
||||
|
||||
$oraHome = Get-OracleHome -OracleHome $OracleHome
|
||||
$impdp = Join-Path $oraHome "bin\impdp.exe"
|
||||
|
||||
if (-not (Test-Path -Path $impdp)) {
|
||||
throw "impdp not found at: $impdp"
|
||||
}
|
||||
|
||||
# Build impdp command
|
||||
if (-not $LogFile) {
|
||||
$LogFile = [System.IO.Path]::GetFileNameWithoutExtension($DumpFile) + "_import.log"
|
||||
}
|
||||
|
||||
$connString = "$Username/`"$Password`"@$ServiceName"
|
||||
|
||||
$params = @(
|
||||
"`"$connString`"",
|
||||
"directory=$DirectoryName",
|
||||
"dumpfile=$DumpFile",
|
||||
"logfile=$LogFile",
|
||||
"table_exists_action=$TableExists"
|
||||
)
|
||||
|
||||
if ($Schemas) {
|
||||
$params += "schemas=$($Schemas -join ',')"
|
||||
}
|
||||
|
||||
if ($RemapSchema) {
|
||||
$params += "remap_schema=$RemapSchema"
|
||||
}
|
||||
|
||||
if ($AdditionalParams) {
|
||||
$params += $AdditionalParams
|
||||
}
|
||||
|
||||
$arguments = $params -join " "
|
||||
|
||||
Write-Log "Executing: impdp $($params -join ' ' -replace $Password, '****')"
|
||||
|
||||
# Set Oracle environment
|
||||
$env:ORACLE_HOME = $oraHome
|
||||
$env:PATH = "$oraHome\bin;$env:PATH"
|
||||
$env:NLS_LANG = "AMERICAN_AMERICA.AL32UTF8"
|
||||
|
||||
# Execute impdp
|
||||
$process = Start-Process -FilePath $impdp -ArgumentList $arguments -Wait -NoNewWindow -PassThru `
|
||||
-RedirectStandardOutput "$env:TEMP\impdp_out.txt" -RedirectStandardError "$env:TEMP\impdp_err.txt"
|
||||
|
||||
$stdout = Get-Content -Path "$env:TEMP\impdp_out.txt" -Raw -ErrorAction SilentlyContinue
|
||||
$stderr = Get-Content -Path "$env:TEMP\impdp_err.txt" -Raw -ErrorAction SilentlyContinue
|
||||
|
||||
$result = [PSCustomObject]@{
|
||||
Success = $process.ExitCode -eq 0
|
||||
ExitCode = $process.ExitCode
|
||||
Output = $stdout
|
||||
ErrorOutput = $stderr
|
||||
LogFile = $LogFile
|
||||
}
|
||||
|
||||
# Clean up temp files
|
||||
Remove-Item -Path "$env:TEMP\impdp_out.txt" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -Path "$env:TEMP\impdp_err.txt" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Check if a user/schema exists in the database.
|
||||
|
||||
.DESCRIPTION
|
||||
Queries DBA_USERS to check if a user exists.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Password
|
||||
SYSTEM password.
|
||||
|
||||
.PARAMETER SchemaName
|
||||
Name of the schema/user to check.
|
||||
|
||||
.OUTPUTS
|
||||
Boolean. True if user exists.
|
||||
|
||||
.EXAMPLE
|
||||
if (Test-OracleUser -ServiceName "XEPDB1" -Password "oracle" -SchemaName "CONTAFIN_ORACLE") {
|
||||
Write-Host "User exists"
|
||||
}
|
||||
#>
|
||||
function Test-OracleUser {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SchemaName
|
||||
)
|
||||
|
||||
$sql = @"
|
||||
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
|
||||
SELECT 'USER_EXISTS' FROM dba_users WHERE username = UPPER('$SchemaName');
|
||||
EXIT;
|
||||
"@
|
||||
|
||||
$result = Invoke-SqlPlus -OracleHome $OracleHome -ServiceName $ServiceName `
|
||||
-Username "SYSTEM" -Password $Password -SqlCommand $sql -Silent
|
||||
|
||||
return $result -match "USER_EXISTS"
|
||||
}
|
||||
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Get object count for a schema.
|
||||
|
||||
.DESCRIPTION
|
||||
Counts objects in a schema grouped by type.
|
||||
|
||||
.PARAMETER OracleHome
|
||||
Oracle Home directory.
|
||||
|
||||
.PARAMETER ServiceName
|
||||
Database service name.
|
||||
|
||||
.PARAMETER Password
|
||||
SYSTEM password.
|
||||
|
||||
.PARAMETER SchemaName
|
||||
Name of the schema.
|
||||
|
||||
.OUTPUTS
|
||||
Hashtable with object types and counts.
|
||||
|
||||
.EXAMPLE
|
||||
$counts = Get-SchemaObjectCount -ServiceName "XEPDB1" -Password "oracle" -SchemaName "CONTAFIN_ORACLE"
|
||||
#>
|
||||
function Get-SchemaObjectCount {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$OracleHome,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$ServiceName,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Password,
|
||||
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$SchemaName
|
||||
)
|
||||
|
||||
$sql = @"
|
||||
SET PAGESIZE 1000 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF LINESIZE 200
|
||||
SELECT object_type || ':' || COUNT(*)
|
||||
FROM dba_objects
|
||||
WHERE owner = UPPER('$SchemaName')
|
||||
GROUP BY object_type
|
||||
ORDER BY object_type;
|
||||
SELECT 'TOTAL:' || COUNT(*) FROM dba_objects WHERE owner = UPPER('$SchemaName');
|
||||
SELECT 'INVALID:' || COUNT(*) FROM dba_objects WHERE owner = UPPER('$SchemaName') AND status = 'INVALID';
|
||||
EXIT;
|
||||
"@
|
||||
|
||||
$result = Invoke-SqlPlus -OracleHome $OracleHome -ServiceName $ServiceName `
|
||||
-Username "SYSTEM" -Password $Password -SqlCommand $sql -Silent
|
||||
|
||||
$counts = @{}
|
||||
|
||||
foreach ($line in $result -split "`n") {
|
||||
if ($line -match "^([A-Z_ ]+):(\d+)$") {
|
||||
$counts[$Matches[1].Trim()] = [int]$Matches[2]
|
||||
}
|
||||
}
|
||||
|
||||
return $counts
|
||||
}
|
||||
|
||||
# Note: Functions are available when dot-sourced (. .\oracle-functions.ps1)
|
||||
# Do NOT use Export-ModuleMember - it only works inside .psm1 modules
|
||||
Reference in New Issue
Block a user