Files
ROMFASTSQL/proxmox/lxc108-oracle/roa-windows-setup/scripts/05-import-companies.ps1
Marius ec66377e0f fix(oracle): calea DMPDIR devine parametru; sqlnet.ora ajunge unde e citit
Gasite la instalarea de productie VADECO (Oracle 21c XE, Windows Server 2019).

1. Pe serverul VADECO procesul Oracle nu poate atinge nicio cale de pe C:,
   nici macar C:\Windows\Temp, desi ACL-urile sunt corecte si serviciul ruleaza
   ca NT SERVICE\OracleServiceXE. D: merge cu exact acelasi grant. Calea DMP
   era insa hardcodata "C:\DMPDIR" in 01, 02, 05, 06 si in biblioteca, deci
   instalarea nu se putea muta. Acum e parametrul -DmpDir, expus ca /dmpdest:
   in FAZA1.cmd si FAZA2.cmd si transmis tuturor pasilor.

   Cel mai perfid era pasul 02: recrea DIRECTORY DMPDIR pe 'C:\DMPDIR' peste
   valoarea pusa de 01. Chiar cu restul instalarii mutata, SYS.NEWSCHEMA ar fi
   cautat FIRMANOUA.dmp in alta parte, iar adaugarea unei firme noi ar fi picat
   peste luni, fara legatura vizibila cu instalarea.

2. New-OracleDirectory compara doar siruri de caractere: verifica ce scrie in
   dba_directories, nu daca baza chiar poate scrie acolo. Acum face un
   UTL_FILE round-trip si esueaza pe loc, cu explicatia cauzei. Inainte,
   directorul inutilizabil trecea drept bun si importul cadea abia in impdp cu
   ORA-29283, la zeci de linii distanta. Valoarea de retur nici nu era
   verificata in 01/03/06 - de aici si "True" ratacit in log.

3. Instalarea ROAClient seteaza TNS_ADMIN de masina spre instantclient-ul ei.
   Serviciul Oracle mosteneste variabilele de masina, deci citea sqlnet.ora de
   acolo - unde nu exista niciunul - si nu din Oracle Home, unde il scria pasul
   01. Compatibilitatea pentru clienti vechi nu se aplica, iar statiile ar fi
   primit ORA-28040 cu fisierul scris corect, in locul gresit. Pasul 01 scrie
   acum sqlnet.ora si in TNS_ADMIN cand difera.

4. Pasul 05 lega schemele de DMP-uri cu "^$schema[_\.]", deci schema DANUBE
   putea primi DANUBE_20200914.dmp - datele altei firme, fara avertisment.
   Numele exact are acum intaietate, prefixul se accepta doar daca e unic, iar
   ambiguitatea se raporteaza.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SzF1hf4aFS1tmJWpPMiwGp
2026-08-25 21:18:43 +03:00

449 lines
15 KiB
PowerShell

#Requires -Version 5.1
<#
.SYNOPSIS
Batch import company schemas from Data Pump dump files.
.DESCRIPTION
Imports company schemas from dump files. CRITICAL: Reads passwords from
CONTAFIN_ORACLE.NOM_FIRME table to ensure correct authentication.
For each company:
1. Queries NOM_FIRME for schema name and password
2. Finds matching DMP file in DumpDirectory
3. Creates user with password from NOM_FIRME
4. Runs impdp to import schema
5. Logs progress
.PARAMETER DumpDirectory
Directory containing company DMP files. If not specified, defaults to C:\DMPDIR.
.PARAMETER OracleHome
Oracle home directory. If not specified, auto-detects.
.PARAMETER ServiceName
Database service name. Default: XEPDB1
.PARAMETER SystemPassword
SYSTEM user password. Default: romfastsoft
.PARAMETER ParallelJobs
Number of parallel import jobs. Default: 2
.PARAMETER Companies
Optional array of specific company names to import. If not specified, imports all.
.PARAMETER DryRun
Show what would be imported without actually importing.
.EXAMPLE
.\05-import-companies.ps1 -DumpDirectory "C:\dumps\companies"
.EXAMPLE
.\05-import-companies.ps1 -DumpDirectory "D:\backups" -Companies "FIRMA1","FIRMA2"
.EXAMPLE
.\05-import-companies.ps1 -DumpDirectory "C:\dumps" -DryRun
.NOTES
File Name : 05-import-companies.ps1
Prerequisite : Run 04-create-synonyms-grants.ps1 first
Copyright 2024 : ROMFAST
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $false)]
[string]$DumpDirectory = "C:\DMPDIR",
# Calea fizica a directorului Oracle DMPDIR - de acolo citeste baza.
# Implicit e aceeasi cu DumpDirectory, deci nu trebuie data decat cand
# DMP-urile stau in alta parte decat directorul pe care il vede baza.
[Parameter(Mandatory = $false)]
[string]$DmpDir,
[Parameter(Mandatory = $false)]
[string]$OracleHome,
[Parameter(Mandatory = $false)]
[string]$ServiceName = "XEPDB1",
[Parameter(Mandatory = $false)]
[string]$SystemPassword = "romfastsoft",
[Parameter(Mandatory = $false)]
[int]$ParallelJobs = 2,
[Parameter(Mandatory = $false)]
[string[]]$Companies,
[Parameter(Mandatory = $false)]
[switch]$DryRun
)
$ErrorActionPreference = 'Stop'
# Source library functions
. "$PSScriptRoot\lib\logging-functions.ps1"
. "$PSScriptRoot\lib\oracle-functions.ps1"
# Initialize logging
$logPath = Join-Path $PSScriptRoot "..\logs\05-import-companies_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
Initialize-LogFile -LogPath $logPath -ScriptName "05-import-companies.ps1"
try {
Write-LogSection "Batch Import Company Schemas"
# Validate DumpDirectory exists
if (-not (Test-Path $DumpDirectory -PathType Container)) {
throw "DumpDirectory not found: $DumpDirectory"
}
Write-Log "Using dump directory: $DumpDirectory"
if ($DryRun) {
Write-LogWarning "DRY RUN MODE - No changes will be made"
}
# Validate Oracle installation
$oraHome = Get-OracleHome -OracleHome $OracleHome
Write-LogSuccess "Oracle Home: $oraHome"
# Test connection
Write-Log "Testing database connection..."
if (-not (Test-OracleConnection -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword)) {
throw "Cannot connect to database. Please verify ServiceName and SystemPassword."
}
Write-LogSuccess "Database connection successful"
# Get company list from NOM_FIRME
Write-LogSection "Reading Company List from NOM_FIRME"
$companySql = @"
SET PAGESIZE 10000 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF LINESIZE 500
SELECT schema || '|' || parola
FROM CONTAFIN_ORACLE.NOM_FIRME
WHERE sters = 0
AND schema IS NOT NULL
ORDER BY schema;
EXIT;
"@
$companyResult = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
-Username "SYSTEM" -Password $SystemPassword -SqlCommand $companySql -Silent
# Parse company data
$companyData = @{}
foreach ($line in $companyResult -split "`n") {
$line = $line.Trim()
if ($line -match "^([A-Z0-9_]+)\|(.*)$") {
$schema = $Matches[1]
$password = $Matches[2]
if (-not $password) { $password = "ROMFASTSOFT" }
$companyData[$schema] = $password
}
}
Write-Log "Found $($companyData.Count) companies in NOM_FIRME"
if ($companyData.Count -eq 0) {
Write-LogWarning "No companies found in NOM_FIRME"
Close-LogFile -Success $true
exit 0
}
# Filter companies if specified
if ($Companies) {
$filteredData = @{}
foreach ($company in $Companies) {
$companyUpper = $company.ToUpper()
if ($companyData.ContainsKey($companyUpper)) {
$filteredData[$companyUpper] = $companyData[$companyUpper]
}
else {
Write-LogWarning "Company $companyUpper not found in NOM_FIRME"
}
}
$companyData = $filteredData
Write-Log "Filtered to $($companyData.Count) companies"
}
# Find matching dump files
Write-LogSection "Scanning Dump Files"
$dumpFiles = Get-ChildItem -Path $DumpDirectory -Filter "*.dmp" -File
Write-Log "Found $($dumpFiles.Count) DMP files in $DumpDirectory"
# Match companies with dump files
$importList = @()
$notFoundList = @()
foreach ($schema in $companyData.Keys) {
# Numele exact are intaietate. Fara asta, schema DANUBE putea primi
# DANUBE_20200914.dmp - datele altei firme, fara niciun avertisment.
$matchingFile = $dumpFiles | Where-Object { $_.BaseName -ieq $schema } | Select-Object -First 1
if (-not $matchingFile) {
$escaped = [regex]::Escape($schema)
$prefixed = @($dumpFiles | Where-Object { $_.BaseName -imatch "^$escaped[_\.]" })
if ($prefixed.Count -eq 1) {
$matchingFile = $prefixed[0]
}
elseif ($prefixed.Count -gt 1) {
$nume = ($prefixed | ForEach-Object { $_.Name }) -join ', '
Write-LogWarning " - ${schema}: $($prefixed.Count) DMP-uri ambigue ($nume) - redenumeste-l pe cel bun in $schema.dmp"
}
}
if ($matchingFile) {
$importList += [PSCustomObject]@{
Schema = $schema
Password = $companyData[$schema]
DumpFile = $matchingFile.FullName
DumpSize = [math]::Round($matchingFile.Length / 1MB, 2)
}
}
else {
$notFoundList += $schema
}
}
Write-Log "Companies to import: $($importList.Count)"
if ($notFoundList.Count -gt 0) {
Write-LogWarning "Companies without matching dump file: $($notFoundList.Count)"
foreach ($schema in $notFoundList) {
Write-Log " - $schema (no DMP file found)"
}
}
if ($importList.Count -eq 0) {
Write-LogWarning "No companies to import"
Close-LogFile -Success $true
exit 0
}
# Display import plan
Write-LogSection "Import Plan"
$totalSize = ($importList | Measure-Object -Property DumpSize -Sum).Sum
Write-Log "Total data to import: $totalSize MB"
Write-Log ""
Write-Log "Companies to import:"
foreach ($item in $importList) {
Write-Log " - $($item.Schema): $($item.DumpFile) ($($item.DumpSize) MB)"
}
if ($DryRun) {
Write-LogSection "Dry Run Complete"
Write-Log "Would import $($importList.Count) company schemas"
Close-LogFile -Success $true
exit 0
}
# Ensure DMPDIR exists
$dmpDir = if ($DmpDir) { $DmpDir } else { $DumpDirectory }
if (-not (Test-Path -Path $dmpDir)) {
New-Item -ItemType Directory -Path $dmpDir -Force | Out-Null
}
# Process each company
Write-LogSection "Importing Companies"
$successCount = 0
$failCount = 0
$startTime = Get-Date
foreach ($item in $importList) {
Write-LogSection "Importing $($item.Schema)"
try {
# Check if user already exists
$userExists = Test-OracleUser -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -SchemaName $item.Schema
if ($userExists) {
Write-Log "User $($item.Schema) already exists"
# Get current object count
$beforeCounts = Get-SchemaObjectCount -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -SchemaName $item.Schema
$beforeTotal = if ($beforeCounts['TOTAL']) { $beforeCounts['TOTAL'] } else { 0 }
Write-Log "Existing objects: $beforeTotal"
}
else {
# Create user
Write-Log "Creating user $($item.Schema)..."
$createUserSql = @"
SET ECHO OFF FEEDBACK ON VERIFY OFF
CREATE USER $($item.Schema)
IDENTIFIED BY "$($item.Password)"
DEFAULT TABLESPACE ROA
TEMPORARY TABLESPACE TEMP
PROFILE DEFAULT;
GRANT CONNECT TO $($item.Schema);
GRANT RESOURCE TO $($item.Schema);
GRANT CREATE MATERIALIZED VIEW TO $($item.Schema);
GRANT CREATE PROCEDURE TO $($item.Schema);
GRANT CREATE SEQUENCE TO $($item.Schema);
GRANT CREATE TABLE TO $($item.Schema);
GRANT CREATE TRIGGER TO $($item.Schema);
GRANT CREATE VIEW TO $($item.Schema);
GRANT DEBUG CONNECT SESSION TO $($item.Schema);
GRANT SELECT ANY TABLE TO $($item.Schema);
GRANT CREATE TYPE TO $($item.Schema);
GRANT UNLIMITED TABLESPACE TO $($item.Schema);
COMMIT;
SELECT 'USER_CREATED' FROM dual;
EXIT;
"@
$createResult = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
-Username "SYSTEM" -Password $SystemPassword -SqlCommand $createUserSql -Silent
if ($createResult -match "USER_CREATED") {
Write-LogSuccess "User $($item.Schema) created"
}
else {
throw "Failed to create user $($item.Schema)"
}
}
# Copy dump file to DMPDIR if not already there
$dumpFileName = Split-Path -Path $item.DumpFile -Leaf
$targetDumpPath = Join-Path $dmpDir $dumpFileName
if ($item.DumpFile -ne $targetDumpPath) {
Write-Log "Copying dump file to DMPDIR..."
Copy-Item -Path $item.DumpFile -Destination $targetDumpPath -Force
}
# Run import
Write-Log "Running impdp for $($item.Schema)..."
$impdpPath = Join-Path $oraHome "bin\impdp.exe"
$importLogFile = "$($item.Schema)_import_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
# Use EZConnect format for impdp (handles listener bound to specific IP)
$dbHost = Get-ListenerHost -OracleHome $oraHome
$connString = "SYSTEM/`"$SystemPassword`"@${dbHost}:1521/$ServiceName"
# Check if dump has different schema name (remapping needed)
$remapParam = ""
$dumpBaseName = [System.IO.Path]::GetFileNameWithoutExtension($dumpFileName).ToUpper()
if ($dumpBaseName -ne $item.Schema) {
$remapParam = "remap_schema=$dumpBaseName`:$($item.Schema)"
Write-Log "Schema remap: $dumpBaseName -> $($item.Schema)"
}
$impdpParams = @(
"`"$connString`"",
"directory=DMPDIR",
"dumpfile=$dumpFileName",
"logfile=$importLogFile",
"schemas=$($item.Schema)",
"table_exists_action=REPLACE",
"parallel=1" # Required for Oracle XE
)
if ($remapParam) {
$impdpParams += $remapParam
}
$arguments = $impdpParams -join " "
# Set Oracle environment
$env:ORACLE_HOME = $oraHome
$env:PATH = "$oraHome\bin;$env:PATH"
$env:NLS_LANG = "AMERICAN_AMERICA.AL32UTF8"
$importStart = Get-Date
$process = Start-Process -FilePath $impdpPath -ArgumentList $arguments -Wait -NoNewWindow -PassThru
$importDuration = (Get-Date) - $importStart
Write-Log "Import completed in $([math]::Round($importDuration.TotalMinutes, 2)) minutes"
# Verify import
$afterCounts = Get-SchemaObjectCount -OracleHome $oraHome -ServiceName $ServiceName `
-Password $SystemPassword -SchemaName $item.Schema
$afterTotal = if ($afterCounts['TOTAL']) { $afterCounts['TOTAL'] } else { 0 }
$afterInvalid = if ($afterCounts['INVALID']) { $afterCounts['INVALID'] } else { 0 }
Write-Log "Objects after import: $afterTotal"
if ($afterInvalid -gt 0) {
Write-LogWarning "Invalid objects: $afterInvalid"
# Recompile
$recompileSql = @"
BEGIN
DBMS_UTILITY.COMPILE_SCHEMA('$($item.Schema)', FALSE);
END;
/
EXIT;
"@
Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName `
-Username "SYSTEM" -Password $SystemPassword -SqlCommand $recompileSql -Silent
}
if ($process.ExitCode -eq 0) {
Write-LogSuccess "$($item.Schema) imported successfully ($afterTotal objects)"
$successCount++
}
else {
Write-LogWarning "$($item.Schema) import completed with warnings"
$successCount++
}
# Clean up copied dump file
if ($item.DumpFile -ne $targetDumpPath -and (Test-Path -Path $targetDumpPath)) {
Remove-Item -Path $targetDumpPath -Force -ErrorAction SilentlyContinue
}
}
catch {
Write-LogError "Failed to import $($item.Schema): $_"
$failCount++
}
}
$totalDuration = (Get-Date) - $startTime
# Summary
Write-LogSection "Import Complete"
Write-LogSuccess "Company import batch completed!"
Write-Log ""
Write-Log "Summary:"
Write-Log " Total companies: $($importList.Count)"
Write-Log " Successful: $successCount"
Write-Log " Failed: $failCount"
Write-Log " Total duration: $([math]::Round($totalDuration.TotalMinutes, 2)) minutes"
Write-Log ""
if ($notFoundList.Count -gt 0) {
Write-Log "Companies skipped (no dump file):"
foreach ($schema in $notFoundList) {
Write-Log " - $schema"
}
}
Write-Log ""
Write-Log "Next steps:"
Write-Log " 1. Run 07-verify-installation.ps1 to verify all schemas"
Close-LogFile -Success ($failCount -eq 0)
exit $(if ($failCount -eq 0) { 0 } else { 1 })
}
catch {
Write-LogError "Import failed: $_"
Write-LogError $_.ScriptStackTrace
Close-LogFile -Success $false
exit 1
}