Files
ROMFASTSQL/proxmox/lxc108-oracle/roa-windows-setup/scripts/05-import-companies.ps1
Marius 3ba36b6119 fix(oracle): sys-grants.sql muta DMPDIR inapoi pe C:, iar 05 numara esecul drept succes
Gasite la prima rulare reala a FAZA2 la VADECO. Toate trei importurile de firma
au picat, si scriptul a raportat "Successful: 3, Failed: 0".

1. sql/sys-grants.sql facea CREATE OR REPLACE DIRECTORY DMPDIR AS 'C:\DMPDIR'
   neconditionat. Ruleaza in pasul 04, deci DUPA importul contafin-ului din 03:
   importul acela reusea cu calea corecta, iar obiectul era mutat imediat dupa.
   Pe VADECO, unde procesul Oracle nu ajunge la nicio cale de pe C:, esecul a
   aparut abia in faza 2, ca ORA-39002 / ORA-39070 / ORA-29283 - ore mai tarziu
   si fara nicio legatura vizibila cu pasul care il provocase.

   E aceeasi clasa de defect ca cel reparat in ec66377 pentru pasul 02, dar
   ascuns intr-un fisier .sql, deci corectia de atunci l-a ratat. Acum calea
   existenta se pastreaza si se raporteaza, ca in grants-public.sql; se creeaza
   doar daca DMPDIR lipseste cu totul, caz in care se si avertizeaza ca pasul 01
   nu a rulat.

2. 05-import-companies.ps1 incrementa $successCount si pe ramura de cod de
   iesire nenul, iar numarul de obiecte de dupa import nu era verificat deloc.
   Rezultatul: trei scheme goale raportate ca importate cu succes, faza 2
   terminata "cu observatii", si defectul descoperit doar pentru ca schemele
   goale sar in ochi la verificare.

   Acum: 0 obiecte inseamna esec, oricare ar fi codul de iesire - un import care
   lasa schema goala nu e un succes. Codul 5 ramane acceptat (ORA-31684 pe user,
   ORA-39082 pe obiecte compilate, normale la ROA), orice alt cod nenul e esec.
   Sumarul si codul de iesire spun adevarul, deci FAZA2.cmd se opreste pe
   :esec_05 in loc sa continue peste un import inexistent.

3. 07-verify-installation.ps1 verifica acum ca baza chiar poate SCRIE in DMPDIR,
   printr-o runda UTL_FILE (deschide, scrie, sterge). Calea din dba_directories
   e doar un sir de caractere si nu spune nimic despre acces - exact motivul
   pentru care New-OracleDirectory primise deja acelasi tratament in ec66377.
   Verificarea asta ar fi prins defectul de mai sus inainte de faza 2.

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

470 lines
16 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
}
# Codul 5 inseamna "terminat cu avertismente" (ORA-31684 pe user, ORA-39082
# pe obiecte compilate) si e normal la ROA. Orice alt cod nenul e esec.
# Iar numarul de obiecte e criteriul care nu poate fi pacalit: un import
# care lasa schema goala nu e un succes, oricare ar fi codul de iesire.
#
# Pana pe 2026-08-25, ramura "else" de aici incrementa tot $successCount.
# La VADECO, cele trei importuri au picat cu ORA-39070/ORA-29283 (DMPDIR
# mutat de sys-grants.sql), au raportat "Objects after import: 0" - si
# scriptul a anuntat "Successful: 3, Failed: 0".
if ($afterTotal -eq 0) {
Write-LogError "$($item.Schema): importul a lasat schema GOALA (0 obiecte, cod impdp $($process.ExitCode))."
Write-LogError " Verifica logul Data Pump din DIRECTORY DMPDIR si calea acestuia:"
Write-LogError " SELECT directory_path FROM dba_directories WHERE directory_name = 'DMPDIR';"
$failCount++
}
elseif ($process.ExitCode -eq 0 -or $process.ExitCode -eq 5) {
$sufix = if ($process.ExitCode -eq 5) { ", cu avertismente" } else { "" }
Write-LogSuccess "$($item.Schema) imported successfully ($afterTotal objects$sufix)"
$successCount++
}
else {
Write-LogError "$($item.Schema): impdp a iesit cu codul $($process.ExitCode) ($afterTotal obiecte in schema)."
$failCount++
}
# 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"
if ($failCount -eq 0) {
Write-LogSuccess "Company import batch completed!"
}
else {
Write-LogError "Import batch terminat CU ESECURI - $failCount din $($importList.Count) scheme."
}
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
}