diff --git a/CLAUDE.md b/CLAUDE.md index d11f408..cceba89 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -47,6 +47,7 @@ input/ # Oracle DMP files for import - **Disaster recovery**: `proxmox/vm109-windows-dr/README.md` - **Instalare/migrare Oracle — care director se folosește**: `proxmox/lxc108-oracle/docs/instalare-si-migrare-oracle.md` - **ROA Windows setup scripts (XE/SE 21c)**: `proxmox/lxc108-oracle/roa-windows-setup/README.md` +- **Conectarea clienților vechi (Instant Client 10/11) la 21c — ORA-28040 / ORA-01017 / ORA-12514**: `docs/lectii-conectare-client-oracle.md` - **Kit de instalare pentru client (DMP-uri șablon + scripturi, gata de dus la client)**: `proxmox/lxc108-oracle/scripts/build-client-kit.ps1` - **VM 302 test environment for ROA setup**: `proxmox/vm302-oracle-test/README.md` - **Diagnostic spațiu Oracle la clienți (job zilnic + emailuri)**: `docs/diagnostic-spatiu-clienti.md` diff --git a/docs/lectii-conectare-client-oracle.md b/docs/lectii-conectare-client-oracle.md new file mode 100644 index 0000000..fba12e9 --- /dev/null +++ b/docs/lectii-conectare-client-oracle.md @@ -0,0 +1,247 @@ +# Lecții — conectarea clienților vechi (Instant Client 10/11) la Oracle 21c + +Scris pe 2026-08-25, după migrarea VADECO pe server nou. Toate lucrurile de mai +jos au fost **observate direct**, nu deduse din documentație, iar fiecare a fost +verificat pe serverul clientului (`WIN-16COB435C1E`, `192.168.101.111`, +Oracle XE 21.3, CDB `XE` + PDB `XEPDB1`). + +Numitorul comun al tuturor: **niciuna dintre erori nu arată spre cauza ei.** +`ORA-01017` pare parolă greșită, `ORA-12514` pare baza oprită, `ORA-28040` pare o +problemă de client. De aceea au ajuns aici, într-un fișier separat. + +--- + +## 1. `TNS_ADMIN` de mașină bate Oracle Home — și pentru instanță, nu doar pentru clienți + +ROAClient își pune `TNS_ADMIN` de mașină pe folderul propriului Instant Client +(la VADECO: `d:\roa\instantclient_11_2_0_2`). Variabila nu e citită doar de +`sqlplus`-ul din folderul acela: **serviciul Oracle o moștenește la pornire**, +iar procesele bazei citesc de acolo și `sqlnet.ora`, și `tnsnames.ora`. + +Capcana e de timp, nu de conținut. O instanță pornită **înainte** ca `TNS_ADMIN` +să existe nu o vede, deci continuă să citească din Oracle Home și totul pare în +regulă. Efectul apare **abia la primul restart al serviciului** — adică la primul +reboot al serverului, de obicei după ce am plecat de la client. + +### 1a. Fără `sqlnet.ora` acolo → `ORA-28040` la toți clienții vechi + +`SQLNET.ALLOWED_LOGON_VERSION_SERVER=8` scris frumos în +`ORACLE_BASE_HOME\network\admin\sqlnet.ora` devine irelevant: instanța citește din +`TNS_ADMIN`, nu găsește nimic, cade pe implicitul 21c (`12`) și refuză orice +client pre-12c. + +### 1b. Fără `tnsnames.ora` acolo → `ORA-12514` la **toți** clienții + +Asta e cea gravă, și e cea pe care am prins-o efectiv. La Oracle XE, +`LOCAL_LISTENER` e implicit **aliasul** `LISTENER_XE`, definit numai în +`tnsnames.ora` din Oracle Home. După restart, instanța încearcă să rezolve +aliasul din `TNS_ADMIN`-ul nou, nu-l găsește, **nu se mai înregistrează la +listener** — și atunci: + +- baza e sus (`v$instance` = `OPEN`, `v$pdbs` = `READ WRITE`); +- serviciul Windows e `Running`; +- listenerul e `Running` și ascultă pe `0.0.0.0:1521`; +- `lsnrctl status` arată **doar** `CLRExtProc`; +- **absolut orice** client primește `ORA-12514`. + +Adică: server aparent perfect, aplicație complet moartă. Exact ce s-ar fi +întâmplat la VADECO la primul reboot. + +### Reparația + +Trei lucruri, toate făcute acum de `01-setup-database.ps1`: + +1. `sqlnet.ora` scris **și** în `TNS_ADMIN`, identic cu cel din Oracle Home; +2. `tnsnames.ora` scris în `TNS_ADMIN`, cu aliasul `ROA` (pentru ROAClient) **și** + `LISTENER_XE` (pentru instanță); +3. `LOCAL_LISTENER` fixat pe **adresă literală**, ca să nu mai depindă de niciun + fișier de rețea: + +```sql +ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.101.111)(PORT=1521))' SCOPE=BOTH; +ALTER SYSTEM REGISTER; +``` + +Punctul 3 e singurul care rezistă și dacă ROAClient se instalează **după** kit, +sau dacă cineva mută folderul Instant Client. Punctele 1 și 2 rămân necesare +pentru `sqlnet.ora` și pentru aliasul `ROA`, dar au aceeași fragilitate: sunt +corecte doar față de valoarea lui `TNS_ADMIN` din momentul rulării. De asta pasul +07 le reverifică. + +### Diagnostic rapid + +```powershell +[Environment]::GetEnvironmentVariable('TNS_ADMIN','Machine') +Test-Path "$([Environment]::GetEnvironmentVariable('TNS_ADMIN','Machine'))\sqlnet.ora" +& "$env:ORACLE_HOME\bin\lsnrctl.exe" status | Select-String 'Service "' +``` + +Dacă `lsnrctl status` nu listează serviciul PDB-ului dar baza e `OPEN`, e exact +cazul 1b. Confirmarea: + +```sql +SELECT value FROM v$parameter WHERE name = 'local_listener'; +``` + +Un alias (`LISTENER_XE`) în loc de un `(ADDRESS=...)` = bombă cu ceas. + +--- + +## 2. `ALLOWED_LOGON_VERSION_SERVER=8` cere verificator **10G**, altfel `ORA-01017` + +Cu setarea asta, serverul autentifică orice client pre-12c pe baza +verificatorului **10G**. Un cont care nu are `10G` în `PASSWORD_VERSIONS` nu se +mai poate conecta din Instant Client 10/11 — și eroarea **nu** e `ORA-28040`, e: + +``` +ORA-01017: invalid username/password; logon denied +``` + +Adică fix eroarea care te trimite să verifici parola. Parola e corectă: același +cont, aceeași parolă, se conectează perfect din `sqlplus`-ul 21c de pe server. + +După o instalare curată de 21c, `SYSTEM` are doar `11G 12C`. `CONTAFIN_ORACLE` +are `10G 11G 12C` **doar pentru că** pasul 01 îi rescrie parola *după* ce a scris +`sqlnet.ora` — verificatoarele se generează după setarea activă în momentul +`CREATE`/`ALTER USER`, nu retroactiv. + +### Reparația + +Rescrierea **aceleiași** parole. Nu se schimbă nimic pentru nimeni, doar se +regenerează verificatoarele: + +```sql +-- utilizator local (schemele de firmă, CONTAFIN_ORACLE) — din PDB +ALTER USER CONTAFIN_ORACLE IDENTIFIED BY "ROMFASTSOFT"; + +-- utilizator comun (SYSTEM) — obligatoriu din CDB$ROOT +ALTER USER SYSTEM IDENTIFIED BY "romfastsoft" CONTAINER=ALL; +``` + +Pasul 01 face acum ambele. + +### Sub-capcană: `PASSWORD_VERSIONS` minte pentru utilizatorii comuni + +Interogat **din PDB**, `DBA_USERS.PASSWORD_VERSIONS` pentru `SYSTEM` rămâne +`11G 12C` și după `ALTER USER ... CONTAINER=ALL` din root. Rândul local nu se +împrospătează, dar autentificarea folosește definiția din root — și funcționează. + +Măsurat la VADECO, în aceeași secundă: + +| | `PASSWORD_VERSIONS` | +|---|---| +| `CDB$ROOT` | `10G 11G 12C` | +| `XEPDB1` | `11G 12C` | +| conectare reală din Instant Client 11.2 | **merge** | + +Concluzie: pentru utilizatorii comuni, coloana nu e o dovadă. Singura verificare +validă e o conectare adevărată. De asta pasul 07 nu se mai uită la coloană pentru +`SYSTEM`, ci îl probează. + +--- + +## 3. `listener.ora` legat de un nume care depinde de Tailscale + +Instalarea de Oracle a pus în `listener.ora` și `tnsnames.ora`: + +``` +(ADDRESS = (PROTOCOL = TCP)(HOST = vadeco-server.tailf7372d.ts.net)(PORT = 1521)) +``` + +Adică numele MagicDNS al mașinii în tailnet. Ascultarea în sine e corectă +(listenerul se leagă tot pe `0.0.0.0:1521`, deci LAN-ul e servit), dar **pornirea +listenerului ajunge să depindă de Tailscale**: la boot, dacă `tailscaled` nu a +ridicat încă resolverul, numele nu se rezolvă. + +Înlocuit cu numele mașinii, care se rezolvă local întotdeauna: + +``` +(ADDRESS = (PROTOCOL = TCP)(HOST = WIN-16COB435C1E)(PORT = 1521)) +``` + +Verificat după restartul listenerului: tot `0.0.0.0:1521`, toate serviciile +înregistrate, clienții se conectează. + +**Regulă:** pe serverele la care intrăm prin Tailscale, niciun fișier de +configurare Oracle nu are voie să conțină un nume `*.ts.net` sau o adresă +`100.64.0.0/10`. Din același motiv, `Get-ServerLanIPv4` (în +`scripts/lib/oracle-functions.ps1`) sare peste intervalul Tailscale când alege +IP-ul pentru `tnsnames.ora` și `LOCAL_LISTENER` — un `tnsnames.ora` cu `100.x` +copiat pe o stație nu duce nicăieri, stația nu e în tailnet. + +--- + +## 4. Proba de conectare cu clientul vechi e obligatorie + +Toate cele trei probleme de mai sus trec de verificările „pe hârtie": fișierul +există, parametrul e setat, contul e `OPEN`, obiectele sunt valide. Singurul +lucru care le prinde pe toate e o conectare adevărată, cu **clientul vechi**, nu +cu `sqlplus`-ul 21c de pe server. + +```powershell +$ic = 'D:\ROA\instantclient_11_2_0_2' +'select ''PROBA_OK '' || user from dual;' , 'exit' | Set-Content -Encoding ascii C:\Windows\Temp\t.sql + +# prin aliasul din tnsnames.ora — asa se conecteaza ROAClient +& "$ic\sqlplus.exe" -S -L "CONTAFIN_ORACLE/ROMFASTSOFT@ROA" '@C:\Windows\Temp\t.sql' + +# prin EZConnect, pe IP-ul din LAN — ocoleste tnsnames.ora, izoleaza cauza +& "$ic\sqlplus.exe" -S -L "CONTAFIN_ORACLE/ROMFASTSOFT@//192.168.101.111:1521/XEPDB1" '@C:\Windows\Temp\t.sql' +``` + +`-L` (o singură încercare) nu e opțional: fără el, la o parolă refuzată `sqlplus` +cere parola de la tastatură și **agață** o sesiune neinteractivă până la timeout. + +Diferența dintre cele două forme e utilă la diagnostic: dacă EZConnect merge și +aliasul nu, problema e în `tnsnames.ora`; dacă niciuna nu merge, problema e la +server (verificator de parolă, `sqlnet.ora` sau înregistrarea la listener). + +--- + +## 5. Ce verifică acum pasul 07 + +`07-verify-installation.ps1` a primit secțiunea **„Conectivitate client vechi +(Instant Client)"**, care acoperă toate lecțiile de mai sus: + +| Verificare | Prinde | +|---|---| +| `ALLOWED_LOGON_VERSION_SERVER` din `sqlnet.ora` de Oracle Home | valoare > 11 | +| `sqlnet.ora` există în `TNS_ADMIN` de mașină | 1a — `ORA-28040` la primul reboot | +| `tnsnames.ora` din `TNS_ADMIN`: alias `ROA`, `LISTENER_XE`, urme de șablon (`SERVER_ROA`) | 1b — `ORA-12514` la primul reboot; stații care nu găsesc baza | +| `LOCAL_LISTENER` e adresă literală, nu alias | 1b, cazul de fond | +| `PASSWORD_VERSIONS` conține `10G` pentru `CONTAFIN_ORACLE` și schemele de firmă | 2 — `ORA-01017` | +| conectare reală cu Instant Client-ul găsit pe mașină: `CONTAFIN_ORACLE` prin alias și prin EZConnect, `SYSTEM` prin EZConnect | tot ce a scăpat | + +La eșec, raportul spune și unde să te uiți: `ORA-01017` → verificatorul 10G, +`ORA-28040` → `TNS_ADMIN`, `ORA-12514` → `LOCAL_LISTENER`. + +Parametri noi: `-ContafinPassword` (implicit `ROMFASTSOFT`) și +`-InstantClientDir` (implicit: din `TNS_ADMIN`, altfel căutat sub `D:\ROA`, +`C:\ROA`, `D:\`, `C:\`). Dacă nu există Instant Client pe server, proba se +raportează ca sărită, nu ca eșec. + +--- + +## 6. Capcane de mediu, plătite deja + +- **`powershell -Command -` prin SSH trunchiază scriptul.** Un script cu blocuri + pe mai multe linii trimis pe stdin se execută parțial: comenzile de după primul + bloc multi-linie pur și simplu nu rulează, fără nicio eroare. Se pierde timp + crezând că o comandă a eșuat. Soluția: `scp` fișierul `.ps1` și + `ssh ... powershell -NoProfile -ExecutionPolicy Bypass -File C:\Windows\Temp\x.ps1`. +- **`sqlplus / as sysdba` nu merge într-o sesiune SSH** pe serverul ăsta + (`ORA-01017`) — autentificarea pe sistem de operare nu primește token-ul de + grup. Se folosește `sys/@//localhost:1521/XE as sysdba`, sau bequeath + cu `ORACLE_SID` setat și parolă explicită. +- **Un `Restart-Service OracleServiceXE` durează 2–4 minute** (oprire + pornire + + înregistrare). Comenzile de la distanță au nevoie de timeout pe măsură; + altfel timeout-ul taie sesiunea în mijlocul unui restart. + +--- + +## Legături + +- Kit și flux complet: `proxmox/lxc108-oracle/roa-windows-setup/README.md` +- Migrarea VADECO: `docs/handoff_vadeco-migrare.md` (nu intră în git) +- Capcana cu discul `C:` de pe același server: aceeași migrare, secțiune separată + în handoff — procesul Oracle nu ajunge la nicio cale de pe `C:` diff --git a/proxmox/lxc108-oracle/roa-windows-setup/README.md b/proxmox/lxc108-oracle/roa-windows-setup/README.md index d200d7f..ea23451 100644 --- a/proxmox/lxc108-oracle/roa-windows-setup/README.md +++ b/proxmox/lxc108-oracle/roa-windows-setup/README.md @@ -61,7 +61,7 @@ Ce se întâmplă, în ordine: | Pas | Script | Ce face | |---|---|---| | 1 | — | copiază DMP-urile în `C:\DMPDIR` + drepturi pentru serviciul Oracle | -| 2 | `01-setup-database.ps1` | tablespace `ROA`, profil, user `CONTAFIN_ORACLE`, `sqlnet.ora` | +| 2 | `01-setup-database.ps1` | tablespace `ROA`, profil, user `CONTAFIN_ORACLE`, `sqlnet.ora` + `tnsnames.ora` în `TNS_ADMIN`, `LOCAL_LISTENER` literal | | 3 | `02-create-sys-objects.ps1` | obiectele SYS: `AUTH_PACK`, `NEWSCHEMA`, `INFO`, `AUTH_SERII`… | | 4 | `03-import-contafin.ps1` | importă `CONTAFIN_ORACLE` **al clientului** | | 5 | `04-create-synonyms-grants.ps1` | sinonime publice, granturi, `sys-grants.sql` | @@ -175,13 +175,13 @@ Run.cmd 11-setup-backup-export.ps1 | Script | Ce face | Când | |---|---|---| -| `01-setup-database.ps1` | tablespace `ROA`, profil, user `CONTAFIN_ORACLE`, `sqlnet.ora` | mereu | +| `01-setup-database.ps1` | tablespace `ROA`, profil, user `CONTAFIN_ORACLE`, configurarea de rețea pentru clienți vechi | mereu | | `02-create-sys-objects.ps1` | `AUTH_PACK`, `NEWSCHEMA`, `EXECUTESCRIPTOS`, `INFO`, `UTL_MAIL` | mereu | | `03-import-contafin.ps1` | import `CONTAFIN_ORACLE` din DMP | mereu | | `04-create-synonyms-grants.ps1` | sinonime publice, granturi, `sys-grants.sql` | mereu | | `05-import-companies.ps1` | schemele de firmă, citind parolele din `NOM_FIRME` | migrare | | `06-add-company.ps1` | adaugă o firmă pe un server deja instalat | ocazional | -| `07-verify-installation.ps1` | verificare completă; cod 0 = instalare bună | mereu | +| `07-verify-installation.ps1` | verificare completă, inclusiv **probă de conectare cu Instant Client-ul vechi**; cod 0 = instalare bună | mereu | | `08-post-install-config.ps1` | `ROAUPDATE`, `SERVER_INFO`, joburi, SMTP, Id client | mereu | | `09-copy-licenses.ps1` | `AUTH_SERII` + `AUTH_DETALII` de pe serverul vechi | migrare | | `10-setup-roaupdate-iis.ps1` | directoare de modul + publicare `/roaupdate` în IIS | mereu | @@ -507,39 +507,71 @@ $f = "C:\app\romfast\product\21c\homes\OraDB21Home1\network\admin\sqlnet.ora" Importul care „a eșuat" nu trebuie refăcut dacă logul spune `completed`; rulează doar `07-verify-installation.ps1`. -### ORA-28040: No matching authentication protocol +### ORA-28040 / ORA-01017 / ORA-12514 — cele trei erori de conectare -Clienții vechi (Instant Client 10/11) nu se pot conecta la 21c. +Toate trei au fost întâlnite la VADECO și **niciuna nu arată spre cauza ei**. +Ghidul complet, cu dovezile: [`../../../docs/lectii-conectare-client-oracle.md`](../../../docs/lectii-conectare-client-oracle.md). +Rezumatul: + +**Verifică întâi unde se citește `sqlnet.ora`.** Dacă `TNS_ADMIN` de mașină e +setat (ROAClient îl pune pe folderul propriului Instant Client), acela câștigă — +și pentru clienți, și pentru procesele bazei, de la următoarea pornire a +serviciului Oracle. Fișierul din Oracle Home devine irelevant. ```powershell -Copy-Item config\sqlnet.ora $env:ORACLE_HOME\network\admin\sqlnet.ora -lsnrctl reload +[Environment]::GetEnvironmentVariable('TNS_ADMIN','Machine') +``` + +### ORA-28040: No matching authentication protocol + +`sqlnet.ora` lipsește din locul de unde citește instanța, deci +`ALLOWED_LOGON_VERSION_SERVER` cade pe implicitul 21c (`12`). + +```powershell +.\scripts\01-setup-database.ps1 # scrie sqlnet.ora in ambele locuri ``` ### ORA-01017: invalid username/password -După configurarea lui `sqlnet.ora` pentru clienți vechi, parolele trebuie rescrise -ca să se genereze verificatorul vechi: +Cu `ALLOWED_LOGON_VERSION_SERVER=8`, serverul autentifică orice client pre-12c pe +baza verificatorului **10G**. Un cont fără `10G` în `PASSWORD_VERSIONS` primește +`ORA-01017` — **parola e corectă**, lipsește verificatorul. Se repară rescriind +aceeași parolă: ```sql -ALTER USER CONTAFIN_ORACLE IDENTIFIED BY ROMFASTSOFT; -ALTER USER IDENTIFIED BY ; +-- utilizatori locali (din PDB) +ALTER USER CONTAFIN_ORACLE IDENTIFIED BY "ROMFASTSOFT"; +ALTER USER IDENTIFIED BY ""; + +-- utilizatori comuni (din CDB$ROOT) +ALTER USER SYSTEM IDENTIFIED BY "romfastsoft" CONTAINER=ALL; ``` +Pentru `SYSTEM`, `PASSWORD_VERSIONS` citit din PDB rămâne `11G 12C` chiar și după +reparație — rândul local nu se împrospătează. Singura verificare validă e o +conectare adevărată. + ### ORA-12514: listener does not know of service -```powershell -lsnrctl status -lsnrctl services -``` - -Pentru XE, PDB-ul trebuie deschis: +Întâi PDB-ul — pentru XE trebuie deschis și starea salvată: ```sql ALTER PLUGGABLE DATABASE XEPDB1 OPEN; ALTER PLUGGABLE DATABASE XEPDB1 SAVE STATE; ``` +Dacă baza e `OPEN`, listenerul e pornit și totuși `lsnrctl status` arată doar +`CLRExtProc`, atunci **instanța nu s-a înregistrat**. La XE, `LOCAL_LISTENER` e +implicit aliasul `LISTENER_XE`, care se rezolvă din `tnsnames.ora` — deci depinde +de `TNS_ADMIN`. După un restart cu alt `TNS_ADMIN`, aliasul nu se mai rezolvă și +**toți** clienții primesc `ORA-12514`. + +```sql +SELECT value FROM v$parameter WHERE name = 'local_listener'; -- alias = fragil +ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=)(PORT=1521))' SCOPE=BOTH; +ALTER SYSTEM REGISTER; +``` + ### Erori la import | Eroare | Rezolvare | diff --git a/proxmox/lxc108-oracle/roa-windows-setup/scripts/01-setup-database.ps1 b/proxmox/lxc108-oracle/roa-windows-setup/scripts/01-setup-database.ps1 index f0ae4e7..c6c9ae7 100644 --- a/proxmox/lxc108-oracle/roa-windows-setup/scripts/01-setup-database.ps1 +++ b/proxmox/lxc108-oracle/roa-windows-setup/scripts/01-setup-database.ps1 @@ -10,8 +10,11 @@ - Auto-detects CDB vs non-CDB configuration - Configures DEFAULT_PROFILE (disables password expiry) - Configures sqlnet.ora for Instant Client 10/11 compatibility + - Writes sqlnet.ora and tnsnames.ora into the machine TNS_ADMIN as well + - Pins LOCAL_LISTENER to a literal address (no tnsnames alias dependency) - Creates tablespace ROA - Creates user CONTAFIN_ORACLE with required privileges + - Rewrites the CONTAFIN_ORACLE and SYSTEM passwords so both get a 10G verifier .PARAMETER OracleHome Oracle home directory. If not specified, auto-detects from registry or environment. @@ -362,13 +365,18 @@ NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT) Write-Log "Old client compatibility enabled (SQLNET.ALLOWED_LOGON_VERSION=8)" # Daca exista TNS_ADMIN la nivel de masina, ACELA castiga - si pentru - # clienti, si pentru serviciul Oracle, care mosteneste variabilele de - # masina. Instalarea ROAClient il pune sa arate spre instantclient-ul - # ei (D:\ROA\instantclient_11_2_0_2), unde de obicei nu exista niciun - # sqlnet.ora: atunci serverul cade pe valorile implicite, adica - # ALLOWED_LOGON_VERSION_SERVER=12, si clientii vechi primesc ORA-28040 - # desi fisierul de mai sus a fost scris corect. Scriem acelasi continut - # si acolo, altfel toata configurarea de compatibilitate e degeaba. + # clienti, si pentru procesele bazei, care mostenesc variabilele de + # masina la pornirea serviciului. Instalarea ROAClient il pune sa arate + # spre instantclient-ul ei (D:\ROA\instantclient_11_2_0_2), unde de + # obicei nu exista niciun sqlnet.ora: atunci serverul cade pe valorile + # implicite, adica ALLOWED_LOGON_VERSION_SERVER=12, si clientii vechi + # primesc ORA-28040 desi fisierul de mai sus a fost scris corect. + # Scriem acelasi continut si acolo, altfel toata configurarea de + # compatibilitate e degeaba. + # Atentie: efectul apare abia la primul restart al serviciului Oracle - + # instanta pornita INAINTE ca TNS_ADMIN sa existe nu il vede. De aceea + # instalarea poate parea perfecta si sa cada la primul reboot. Detalii + # in docs/lectii-conectare-client-oracle.md. $tnsAdmin = [Environment]::GetEnvironmentVariable('TNS_ADMIN', 'Machine') if ($tnsAdmin) { $tnsAdminFull = [IO.Path]::GetFullPath($tnsAdmin.TrimEnd('\')) @@ -377,12 +385,62 @@ NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT) if (-not (Test-Path $tnsAdminFull)) { New-Item -ItemType Directory -Path $tnsAdminFull -Force | Out-Null } + $stampTns = Get-Date -Format 'yyyyMMdd_HHmmss' + $tnsSqlnet = Join-Path $tnsAdminFull "sqlnet.ora" if (Test-Path $tnsSqlnet) { - Copy-Item $tnsSqlnet "$tnsSqlnet.bak_$(Get-Date -Format 'yyyyMMdd_HHmmss')" -Force + Copy-Item $tnsSqlnet "$tnsSqlnet.bak_$stampTns" -Force } Set-Content -Path $tnsSqlnet -Value $sqlnetContent -Encoding ASCII Write-LogSuccess "sqlnet.ora scris si in TNS_ADMIN: $tnsSqlnet" + + # tnsnames.ora din TNS_ADMIN - doua motive, amandoua serioase: + # 1. ROAClient cauta aici aliasul ROA. Sablonul livrat cu el + # arata spre HOST=SERVER_ROA / SID=ROA, care nu exista. + # 2. instanta rezolva LOCAL_LISTENER tot de aici dupa un + # restart. La Oracle XE, LOCAL_LISTENER e implicit aliasul + # LISTENER_XE, definit doar in tnsnames.ora din Oracle + # Home. Cand instanta reporneste cu TNS_ADMIN pe folderul + # instantclient-ului, aliasul nu se mai rezolva, instanta + # nu se inregistreaza la listener si TOTI clientii iau + # ORA-12514 - cu baza sus si listenerul pornit. + $gazdaTns = Get-ServerLanIPv4 + if (-not $gazdaTns) { + $gazdaTns = $env:COMPUTERNAME + Write-LogWarning "Nu am putut determina IP-ul din LAN; folosesc numele masinii ($gazdaTns) in tnsnames.ora." + } + + $tnsNames = Join-Path $tnsAdminFull "tnsnames.ora" + if (Test-Path $tnsNames) { + $aliasuriVechi = @([regex]::Matches((Get-Content $tnsNames -Raw), + '(?m)^\s*([A-Za-z0-9_\.]+)\s*=') | + ForEach-Object { $_.Groups[1].Value }) + Copy-Item $tnsNames "$tnsNames.bak_$stampTns" -Force + Write-LogWarning "Rescriu $tnsNames (aliasuri existente: $($aliasuriVechi -join ', ')). Copia veche: tnsnames.ora.bak_$stampTns" + } + + $tnsContent = @" +# tnsnames.ora - generat de 01-setup-database.ps1 pe $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') +# +# HOST e IP-ul serverului din LAN, nu localhost: acelasi fisier trebuie sa +# functioneze si copiat pe statiile de lucru. + +ROA = + (DESCRIPTION = + (ADDRESS = (PROTOCOL = TCP)(HOST = $gazdaTns)(PORT = $Port)) + (CONNECT_DATA = + (SERVER = DEDICATED) + (SERVICE_NAME = $ServiceName) + ) + ) + +# Folosit de instanta pentru LOCAL_LISTENER. Fara el, o instanta care +# porneste cu TNS_ADMIN aici nu se mai inregistreaza la listener. +LISTENER_XE = + (ADDRESS = (PROTOCOL = TCP)(HOST = $gazdaTns)(PORT = $Port)) +"@ + Set-Content -Path $tnsNames -Value $tnsContent -Encoding ASCII + Write-LogSuccess "tnsnames.ora scris in TNS_ADMIN: alias ROA -> ${gazdaTns}:$Port/$ServiceName" } } @@ -421,6 +479,60 @@ NAMES.DIRECTORY_PATH = (TNSNAMES, EZCONNECT) Write-Log "Please restart listener manually: lsnrctl stop && lsnrctl start" } } + + # -------------------------------------------------------------------- + # LOCAL_LISTENER ca adresa literala, nu ca alias + # -------------------------------------------------------------------- + # La Oracle XE, LOCAL_LISTENER e implicit aliasul LISTENER_XE, care se + # rezolva din tnsnames.ora - deci depinde de TNS_ADMIN. Daca cineva + # instaleaza ROAClient dupa noi (sau muta folderul instantclient), + # aliasul nu se mai rezolva la urmatoarea pornire a instantei, aceasta + # nu se mai inregistreaza la listener si toti clientii iau ORA-12514. + # Adresa literala e in spfile si nu depinde de niciun fisier de retea. + Write-LogSection "LOCAL_LISTENER" + + $gazdaListener = Get-ServerLanIPv4 + if (-not $gazdaListener) { + $gazdaListener = $env:COMPUTERNAME + Write-LogWarning "Nu am putut determina IP-ul din LAN; pun $gazdaListener in LOCAL_LISTENER." + } + + $numeDbSql = @" +SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF +SELECT 'DBNAME:' || name FROM v`$database; +EXIT; +"@ + $numeDbOut = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName -DbHost $DbHost -Port $Port ` + -Username "SYSTEM" -Password $SystemPassword -SqlCommand $numeDbSql -Silent + + # LOCAL_LISTENER e parametru de instanta: intr-un CDB se pune din root, + # al carui serviciu poarta numele bazei (XE la Oracle XE). + $serviciiDeIncercat = @() + if ($numeDbOut -match 'DBNAME:(\S+)') { $serviciiDeIncercat += $Matches[1].Trim() } + if ($serviciiDeIncercat -notcontains $ServiceName) { $serviciiDeIncercat += $ServiceName } + + $llSql = @" +SET FEEDBACK OFF VERIFY OFF HEADING OFF PAGESIZE 0 +ALTER SYSTEM SET LOCAL_LISTENER='(ADDRESS=(PROTOCOL=TCP)(HOST=$gazdaListener)(PORT=$Port))' SCOPE=BOTH; +ALTER SYSTEM REGISTER; +SELECT 'LL_DONE' FROM DUAL; +EXIT; +"@ + $llPus = $false + foreach ($srv in $serviciiDeIncercat) { + $llOut = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $srv -DbHost $DbHost -Port $Port ` + -Username "SYSTEM" -Password $SystemPassword -SqlCommand $llSql -Silent + if ($llOut -match 'LL_DONE') { + Write-LogSuccess "LOCAL_LISTENER = (ADDRESS=(PROTOCOL=TCP)(HOST=$gazdaListener)(PORT=$Port)), pus prin serviciul $srv" + $llPus = $true + break + } + Write-LogDebug "LOCAL_LISTENER prin serviciul ${srv}: $llOut" + } + if (-not $llPus) { + Write-LogWarning "Nu am putut seta LOCAL_LISTENER. Ramane pe alias (LISTENER_XE)." + Write-LogWarning "Risc: dupa un restart al instantei cu alt TNS_ADMIN, inregistrarea la listener poate esua (ORA-12514)." + } } else { Write-Log "Skipping sqlnet.ora configuration as requested" @@ -602,6 +714,47 @@ EXIT; else { Write-LogWarning "Could not verify password reset" } + + # SYSTEM are nevoie de acelasi tratament, si nu e o rafinare. + # Cu SQLNET.ALLOWED_LOGON_VERSION_SERVER=8, serverul autentifica orice + # client pre-12c pe baza verificatorului 10G. Un cont care nu are 10G + # in PASSWORD_VERSIONS (SYSTEM, dupa o instalare 21c, are doar 11G 12C) + # nu se mai poate conecta din Instant Client 10/11 - si eroarea NU e + # ORA-28040, ci ORA-01017 "invalid username/password", care trimite pe + # o pista gresita ore intregi. Aceeasi parola, doar rescrisa, produce + # verificatorul care lipseste. + $sysPwdSql = if ($versionInfo.IsCDB) { + @" +SET ECHO OFF FEEDBACK OFF VERIFY OFF HEADING OFF PAGESIZE 0 +ALTER USER SYSTEM IDENTIFIED BY "$SystemPassword" CONTAINER=ALL; +SELECT 'SYS_PWD_DONE' FROM DUAL; +EXIT; +"@ + } else { + @" +SET ECHO OFF FEEDBACK OFF VERIFY OFF HEADING OFF PAGESIZE 0 +ALTER USER SYSTEM IDENTIFIED BY "$SystemPassword"; +SELECT 'SYS_PWD_DONE' FROM DUAL; +EXIT; +"@ + } + + # Utilizator comun => se modifica din root, al carui serviciu poarta + # numele bazei. Reutilizam lista construita pentru LOCAL_LISTENER. + $sysPwdPus = $false + foreach ($srv in $serviciiDeIncercat) { + $sysOut = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $srv -DbHost $DbHost -Port $Port ` + -Username "SYSTEM" -Password $SystemPassword -SqlCommand $sysPwdSql -Silent + if ($sysOut -match 'SYS_PWD_DONE') { + Write-LogSuccess "SYSTEM a primit verificator 10G (parola nu se schimba, doar se rescrie)" + $sysPwdPus = $true + break + } + Write-LogDebug "Rescrierea parolei SYSTEM prin serviciul ${srv}: $sysOut" + } + if (-not $sysPwdPus) { + Write-LogWarning "Nu am putut rescrie parola lui SYSTEM. Conturile fara verificator 10G dau ORA-01017 din Instant Client 10/11." + } } # Summary diff --git a/proxmox/lxc108-oracle/roa-windows-setup/scripts/07-verify-installation.ps1 b/proxmox/lxc108-oracle/roa-windows-setup/scripts/07-verify-installation.ps1 index 59413f3..06ed867 100644 --- a/proxmox/lxc108-oracle/roa-windows-setup/scripts/07-verify-installation.ps1 +++ b/proxmox/lxc108-oracle/roa-windows-setup/scripts/07-verify-installation.ps1 @@ -67,7 +67,17 @@ param( [string]$RoaUpdatePath = "D:\ROAUPDATE", [Parameter(Mandatory = $false)] - [string]$ExportPath = "D:\ROA\EXPORT_ORADMP" + [string]$ExportPath = "D:\ROA\EXPORT_ORADMP", + + # Parola CONTAFIN_ORACLE, folosita pentru proba de conectare cu Instant + # Client-ul vechi. Daca e gresita, proba raporteaza esec - nu instalarea. + [Parameter(Mandatory = $false)] + [string]$ContafinPassword = "ROMFASTSOFT", + + # Folderul Instant Client-ului vechi (cel al ROAClient). Implicit se + # deduce din TNS_ADMIN sau se cauta sub D:\ROA si C:\ROA. + [Parameter(Mandatory = $false)] + [string]$InstantClientDir ) $ErrorActionPreference = 'Stop' @@ -835,6 +845,225 @@ EXIT; $extraIssues += "Scheduled task 'ROA Export Oracle' missing" } + # ------------------------------------------------------------------------ + # Conectivitate pentru clientii vechi (Instant Client 10/11) + # ------------------------------------------------------------------------ + # Sectiunea asta exista pentru ca toate esecurile de aici arata, la prima + # vedere, ca altceva: ORA-01017 pare parola gresita, ORA-12514 pare baza + # oprita. Vezi docs/lectii-conectare-client-oracle.md. + Add-ReportSection "Conectivitate client vechi (Instant Client)" + + # --- unde se citeste, de fapt, sqlnet.ora + $oraBaseRoot = Split-Path (Split-Path (Split-Path $oraHome -Parent) -Parent) -Parent + $homesRoot = Join-Path $oraBaseRoot "product\21c\homes" + $adminOh = $null + if (Test-Path $homesRoot) { + $bh = Get-ChildItem -Path $homesRoot -Directory -ErrorAction SilentlyContinue | + Where-Object { $_.Name -match "OraDB" } | Select-Object -First 1 + if ($bh) { $adminOh = Join-Path $bh.FullName "network\admin" } + } + if (-not $adminOh) { $adminOh = Join-Path $oraHome "network\admin" } + + $sqlnetOh = Join-Path $adminOh "sqlnet.ora" + if (Test-Path $sqlnetOh) { + $continutOh = Get-Content $sqlnetOh -Raw + $verOh = if ($continutOh -match '(?im)^\s*SQLNET\.ALLOWED_LOGON_VERSION_SERVER\s*=\s*(\d+)') { $Matches[1] } else { $null } + Add-ReportLine "sqlnet.ora (Oracle Home): $sqlnetOh" + if ($verOh) { + Add-ReportLine " ALLOWED_LOGON_VERSION_SERVER = $verOh" + if ([int]$verOh -gt 11) { + Add-ReportLine "[WARNING] Valoare peste 11: clientii 10/11 vor primi ORA-28040." + $extraIssues += "ALLOWED_LOGON_VERSION_SERVER=$verOh in $sqlnetOh" + } + } + else { + Add-ReportLine "[WARNING] Nu contine ALLOWED_LOGON_VERSION_SERVER." + $extraIssues += "ALLOWED_LOGON_VERSION_SERVER missing from $sqlnetOh" + } + } + else { + Add-ReportLine "sqlnet.ora (Oracle Home): LIPSA ($sqlnetOh)" + $extraIssues += "sqlnet.ora missing from $adminOh" + } + + # --- TNS_ADMIN de masina: castiga in fata Oracle Home, si pentru clienti, + # si pentru instanta - dar abia de la urmatoarea pornire a serviciului. + $tnsAdminM = [Environment]::GetEnvironmentVariable('TNS_ADMIN', 'Machine') + Add-ReportLine "" + if ($tnsAdminM) { + $tnsAdminM = [IO.Path]::GetFullPath($tnsAdminM.TrimEnd('\')) + Add-ReportLine "TNS_ADMIN (masina): $tnsAdminM" + + if ($tnsAdminM -ne [IO.Path]::GetFullPath($adminOh.TrimEnd('\'))) { + $sqlnetTns = Join-Path $tnsAdminM "sqlnet.ora" + if (Test-Path $sqlnetTns) { + Add-ReportLine " sqlnet.ora acolo: OK" + } + else { + Add-ReportLine " sqlnet.ora acolo: LIPSA" + Add-ReportLine "[WARNING] Instanta citeste TNS_ADMIN-ul de masina de la urmatorul restart." + Add-ReportLine " Fara sqlnet.ora acolo, dupa primul reboot toti clientii vechi" + Add-ReportLine " iau ORA-28040. Ruleaza din nou 01-setup-database.ps1." + $extraIssues += "sqlnet.ora missing from TNS_ADMIN ($tnsAdminM)" + } + + $tnsFile = Join-Path $tnsAdminM "tnsnames.ora" + if (Test-Path $tnsFile) { + $tnsTxt = Get-Content $tnsFile -Raw + $areRoa = $tnsTxt -match '(?im)^\s*ROA\s*=' + $areLsn = $tnsTxt -match '(?im)^\s*LISTENER_XE\s*=' + $areSablon = $tnsTxt -match 'SERVER_ROA' + Add-ReportLine (" tnsnames.ora acolo: alias ROA={0}, LISTENER_XE={1}" -f ` + $(if ($areRoa) { 'da' } else { 'NU' }), $(if ($areLsn) { 'da' } else { 'NU' })) + if ($areSablon) { + Add-ReportLine "[WARNING] tnsnames.ora e inca sablonul (HOST=SERVER_ROA). Statiile nu se pot conecta." + $extraIssues += "tnsnames.ora still template (SERVER_ROA) in $tnsAdminM" + } + elseif (-not $areRoa) { + Add-ReportLine "[WARNING] Lipseste aliasul ROA. ROAClient nu stie unde e baza." + $extraIssues += "TNS alias ROA missing from $tnsFile" + } + } + else { + Add-ReportLine " tnsnames.ora acolo: LIPSA" + $extraIssues += "tnsnames.ora missing from TNS_ADMIN ($tnsAdminM)" + } + } + else { + Add-ReportLine " (coincide cu Oracle Home - nimic de dublat)" + } + } + else { + Add-ReportLine "TNS_ADMIN (masina): nesetat (se citeste din Oracle Home)" + Add-ReportLine "[NOTA] Daca se instaleaza ROAClient dupa asta, TNS_ADMIN va aparea si" + Add-ReportLine " va trebui rulat din nou 01-setup-database.ps1." + } + + # --- LOCAL_LISTENER: alias sau adresa literala + $llSql = @" +SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF LINESIZE 300 +SELECT 'LL:' || value FROM v`$parameter WHERE name = 'local_listener'; +EXIT; +"@ + $llOut = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName ` + -Username "SYSTEM" -Password $SystemPassword -SqlCommand $llSql -Silent + + Add-ReportLine "" + if ($llOut -match 'LL:(.*)') { + $llVal = $Matches[1].Trim() + Add-ReportLine "LOCAL_LISTENER: $(if ($llVal) { $llVal } else { '(gol - implicit)' })" + if ($llVal -and $llVal -notmatch '\(ADDRESS') { + Add-ReportLine "[WARNING] LOCAL_LISTENER e un alias ($llVal), deci depinde de tnsnames.ora." + Add-ReportLine " Daca aliasul nu se rezolva la urmatoarea pornire a instantei, aceasta" + Add-ReportLine " nu se mai inregistreaza la listener si toti clientii iau ORA-12514." + Add-ReportLine " Ruleaza din nou 01-setup-database.ps1 ca sa il fixeze pe adresa literala." + $extraIssues += "LOCAL_LISTENER is an alias ($llVal), not a literal address" + } + } + + # --- verificatoare de parola: fara 10G, clientii vechi iau ORA-01017 + # SYSTEM lipseste intentionat din lista: fiind utilizator comun, randul lui + # din DBA_USERS al PDB-ului ramane cu vechile PASSWORD_VERSIONS chiar dupa + # ce parola a fost rescrisa din root, iar autentificarea foloseste oricum + # definitia din root. Verificarea care conteaza pentru el e proba de + # conectare de mai jos, nu coloana asta. + $pvSql = @" +SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF LINESIZE 300 +SELECT 'PV:' || username || '|' || password_versions + FROM dba_users + WHERE username = 'CONTAFIN_ORACLE' + OR username IN (SELECT UPPER(schema) FROM CONTAFIN_ORACLE.NOM_FIRME + WHERE sters = 0 AND schema IS NOT NULL) + ORDER BY username; +EXIT; +"@ + $pvOut = Invoke-SqlPlus -OracleHome $oraHome -ServiceName $ServiceName ` + -Username "SYSTEM" -Password $SystemPassword -SqlCommand $pvSql -Silent + + Add-ReportLine "" + Add-ReportLine "Verificatoare de parola (10G e obligatoriu pentru Instant Client 10/11):" + $fara10G = @() + foreach ($line in $pvOut -split "`n") { + if ($line -match '^PV:([^|]+)\|(.*)$') { + $u = $Matches[1].Trim(); $v = $Matches[2].Trim() + $are = $v -match '10G' + Add-ReportLine (" {0,-24} {1,-16} {2}" -f $u, $v, $(if ($are) { 'OK' } else { 'FARA 10G' })) + if (-not $are) { $fara10G += $u } + } + } + if ($fara10G.Count -gt 0) { + Add-ReportLine "[WARNING] Conturi fara verificator 10G: $($fara10G -join ', ')" + Add-ReportLine " Din Instant Client 10/11 vor da ORA-01017, care pare parola gresita." + Add-ReportLine " Se repara rescriind aceeasi parola: ALTER USER IDENTIFIED BY ;" + $extraIssues += "Accounts without 10G password verifier: $($fara10G -join ', ')" + } + + # --- proba adevarata: o conectare cu Instant Client-ul vechi + Add-ReportLine "" + $icDir = $InstantClientDir + if (-not $icDir -and $tnsAdminM -and (Test-Path (Join-Path $tnsAdminM "sqlplus.exe"))) { + $icDir = $tnsAdminM + } + if (-not $icDir) { + foreach ($radacina in @('D:\ROA', 'C:\ROA', 'D:\', 'C:\')) { + if (-not (Test-Path $radacina)) { continue } + $g = Get-ChildItem -Path $radacina -Directory -Filter 'instantclient*' -ErrorAction SilentlyContinue | + Where-Object { Test-Path (Join-Path $_.FullName 'sqlplus.exe') } | Select-Object -First 1 + if ($g) { $icDir = $g.FullName; break } + } + } + + if (-not $icDir) { + Add-ReportLine "Proba de conectare: nu am gasit Instant Client pe masina (sarita)" + Add-ReportLine "[NOTA] Fara ROAClient instalat aici, proba se face de pe o statie." + } + else { + $icSqlplus = Join-Path $icDir "sqlplus.exe" + Add-ReportLine "Instant Client: $icSqlplus" + + $probaSql = Join-Path $env:TEMP "roa_proba_client.sql" + Set-Content -Path $probaSql -Encoding ASCII -Value @( + 'SET FEEDBACK OFF PAGESIZE 0 LINESIZE 200', + "SELECT 'PROBA_OK ' || USER FROM DUAL;", + 'EXIT') + + $ipLan = Get-ServerLanIPv4 + $tinte = @() + $areAliasRoa = $tnsAdminM -and (Test-Path (Join-Path $tnsAdminM 'tnsnames.ora')) -and + ((Get-Content (Join-Path $tnsAdminM 'tnsnames.ora') -Raw) -match '(?im)^\s*ROA\s*=') + if ($areAliasRoa) { + $tinte += @{ Nume = 'CONTAFIN_ORACLE / alias ROA'; Sir = "CONTAFIN_ORACLE/$ContafinPassword@ROA" } + } + if ($ipLan) { + $tinte += @{ Nume = "CONTAFIN_ORACLE / $ipLan"; Sir = "CONTAFIN_ORACLE/$ContafinPassword@//${ipLan}:1521/$ServiceName" } + } + if ($tinte.Count -eq 0) { + $tinte += @{ Nume = 'CONTAFIN_ORACLE / localhost'; Sir = "CONTAFIN_ORACLE/$ContafinPassword@//localhost:1521/$ServiceName" } + } + # SYSTEM: singura verificare valida a verificatorului lui de parola. + $gazdaSys = if ($ipLan) { $ipLan } else { 'localhost' } + $tinte += @{ Nume = "SYSTEM / $gazdaSys"; Sir = "SYSTEM/$SystemPassword@//${gazdaSys}:1521/$ServiceName" } + + foreach ($t in $tinte) { + $iesire = (& $icSqlplus -S -L $t.Sir "@$probaSql" 2>&1 | Where-Object { $_ -match '\S' }) -join ' ' + if ($iesire -match 'PROBA_OK') { + Add-ReportLine (" {0,-32} OK" -f $t.Nume) + } + else { + $eroare = if ($iesire -match '(ORA-\d+|TNS-\d+|SP2-\d+)') { $Matches[1] } else { 'esec' } + Add-ReportLine (" {0,-32} ESEC ({1})" -f $t.Nume, $eroare) + Add-ReportLine " $iesire" + switch ($eroare) { + 'ORA-01017' { Add-ReportLine " Verifica intai verificatorul 10G, nu parola: ALTER USER ... IDENTIFIED BY ;" } + 'ORA-28040' { Add-ReportLine " sqlnet.ora nu e citit de unde crezi. Verifica TNS_ADMIN de mai sus." } + 'ORA-12514' { Add-ReportLine " Instanta nu e inregistrata la listener. Verifica LOCAL_LISTENER de mai sus." } + } + $extraIssues += "Instant Client connect test failed via $($t.Nume): $eroare" + } + } + Remove-Item $probaSql -Force -ErrorAction SilentlyContinue + } + # Final Summary Add-ReportSection "Verification Summary" diff --git a/proxmox/lxc108-oracle/roa-windows-setup/scripts/lib/oracle-functions.ps1 b/proxmox/lxc108-oracle/roa-windows-setup/scripts/lib/oracle-functions.ps1 index 1e7b342..09307b5 100644 --- a/proxmox/lxc108-oracle/roa-windows-setup/scripts/lib/oracle-functions.ps1 +++ b/proxmox/lxc108-oracle/roa-windows-setup/scripts/lib/oracle-functions.ps1 @@ -17,6 +17,65 @@ # Source logging functions . "$PSScriptRoot\logging-functions.ps1" +<# +.SYNOPSIS + IP-ul din LAN al serverului - cel pe care il vad statiile de lucru. + +.DESCRIPTION + Alege adresa IPv4 a interfetei care are ruta implicita, sarind peste: + - loopback (127.x) si APIPA (169.254.x); + - intervalul Tailscale (100.64.0.0/10). Pe serverele la care intram prin + Tailscale, adresa 100.x exista si e perfect functionala pentru noi, dar + e inutila intr-un tnsnames.ora dus pe statii: statia nu e in tailnet. + Daca nu gaseste nimic potrivit, intoarce sirul gol - apelantul decide. + +.OUTPUTS + String. Adresa IPv4 din LAN, sau "" daca nu poate fi determinata. + +.EXAMPLE + $ip = Get-ServerLanIPv4 +#> +function Get-ServerLanIPv4 { + [CmdletBinding()] + param() + + $eTailscale = { param($ip) $ip -match '^100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.' } + + $adrese = @() + try { + $adrese = @(Get-NetIPAddress -AddressFamily IPv4 -ErrorAction Stop | + Where-Object { + $_.IPAddress -notmatch '^(127\.|169\.254\.)' -and + -not (& $eTailscale $_.IPAddress) + }) + } + catch { + # Masini fara modulul NetTCPIP: cadem pe rezolvarea numelui propriu. + $ipuri = @([Net.Dns]::GetHostAddresses([Net.Dns]::GetHostName()) | + Where-Object { $_.AddressFamily -eq 'InterNetwork' } | + ForEach-Object { $_.IPAddressToString } | + Where-Object { $_ -notmatch '^(127\.|169\.254\.)' -and -not (& $eTailscale $_) }) + if ($ipuri.Count -gt 0) { return $ipuri[0] } + return "" + } + + if ($adrese.Count -eq 0) { return "" } + if ($adrese.Count -eq 1) { return $adrese[0].IPAddress } + + # Mai multe placi: o alegem pe cea cu ruta implicita. + try { + $rute = @(Get-NetRoute -DestinationPrefix '0.0.0.0/0' -ErrorAction Stop | + Sort-Object RouteMetric, ifMetric) + foreach ($r in $rute) { + $potrivire = $adrese | Where-Object { $_.InterfaceIndex -eq $r.ifIndex } | Select-Object -First 1 + if ($potrivire) { return $potrivire.IPAddress } + } + } + catch { } + + return $adrese[0].IPAddress +} + <# .SYNOPSIS Get the listener host address. @@ -64,9 +123,7 @@ function Get-ListenerHost { # If listener is bound to 0.0.0.0, try to get actual IP if ($listenerHost -eq "0.0.0.0") { - $ip = (Get-NetIPAddress -AddressFamily IPv4 | - Where-Object { $_.IPAddress -notmatch "^127\." -and $_.PrefixOrigin -ne "WellKnown" } | - Select-Object -First 1).IPAddress + $ip = Get-ServerLanIPv4 if ($ip) { return $ip } return "localhost" }