673 lines
32 KiB
PowerShell
673 lines
32 KiB
PowerShell
# diag_spatiu.ps1 - diagnostic de spatiu pe serverul Oracle al unui client ROA.
|
|
# Raspunde "cat spatiu mai am si ce ocupa unde": tablespace/datafile (cat mai poate creste),
|
|
# plafonul de date al editiei XE, audit Oracle (tabele + fisiere .aud), alert log/trace/ADR,
|
|
# archivelog/FRA, spatiu pe discurile
|
|
# fizice ale serverului, si alti mancatori de spatiu (recyclebin, UNDO, istoric statistici/
|
|
# scheduler, TEMP, top segmente generic - fara nume de tabele ROA hardcodate).
|
|
# STRICT READ-ONLY pe baza: doar select/agregate si UTL_FILE in mod 'R'. Actiunile de curatare
|
|
# din verdict sunt doar AFISATE ca sugestie, niciodata executate (niciun purge/truncate/alter).
|
|
# Singura scriere e sub -Disc: un .ps1 temporar in DMPDIR pe server (prin sys.ExecuteScriptOS),
|
|
# sters la final cu verificare.
|
|
# -SysPassword e optional, fara valoare implicita, nesalvat nicaieri (parola SYS difera per
|
|
# server). Sectiunile care o cer (MAX_PDB_STORAGE din CDB$ROOT, audit intern sys.aud$/fga_log$,
|
|
# recyclebin la nivel de baza) se sar curat, cu mesaj, daca nu e data - diagnosticul de baza
|
|
# merge complet fara ea.
|
|
#
|
|
# Utilizare:
|
|
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA
|
|
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA -Disc
|
|
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA -SysPassword ...
|
|
# powershell -File COMUN\utile\diag_spatiu.ps1 -Alias ROA_SIGMA -Top 30 -Disc
|
|
param(
|
|
[Parameter(Mandatory=$true)][string]$Alias,
|
|
[string]$User = 'contafin_oracle',
|
|
[string]$Password = 'ROMFASTSOFT',
|
|
[string]$SysPassword,
|
|
[string]$SqlPlus = 'D:\ROA\instantclient_19_18\sqlplus.exe',
|
|
[switch]$Disc,
|
|
[int]$Top = 20
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
# praguri de alerta, aceleasi ca in PACK_DIAG_SPATIU (jobul zilnic de la clienti): tablespace-ul
|
|
# intra in atentie sub pragul absolut SAU sub procentul din maximul lui, ca sa existe timp de reactie
|
|
$PragTsMb = 2048
|
|
$PragTsPct = 15
|
|
$PragFraPct = 75
|
|
|
|
if (-not (Test-Path $SqlPlus)) {
|
|
Write-Output ('EROARE: nu gasesc sqlplus la ' + $SqlPlus)
|
|
exit 1
|
|
}
|
|
|
|
$env:TNS_ADMIN = Split-Path $SqlPlus -Parent
|
|
$ConnStr = $User + '/' + $Password + '@' + $Alias
|
|
$ConnStrSys = if ($SysPassword) { 'sys/' + $SysPassword + '@' + $Alias + ' as sysdba' } else { $null }
|
|
|
|
$TempDir = Join-Path $env:TEMP ('diag_spatiu_' + [guid]::NewGuid().ToString('N'))
|
|
New-Item -ItemType Directory -Force -Path $TempDir | Out-Null
|
|
|
|
function Remove-TempDir {
|
|
if (Test-Path $TempDir) { Remove-Item -LiteralPath $TempDir -Recurse -Force -ErrorAction SilentlyContinue }
|
|
}
|
|
|
|
function Invoke-SqlAs {
|
|
param([string]$Sql, [string]$Connect)
|
|
$sqlFile = Join-Path $TempDir ('q_' + [guid]::NewGuid().ToString('N') + '.sql')
|
|
[System.IO.File]::WriteAllText($sqlFile, $Sql, [System.Text.Encoding]::ASCII)
|
|
try {
|
|
$out = & $SqlPlus -L -S $Connect ('@' + $sqlFile) 2>&1
|
|
$code = $LASTEXITCODE
|
|
} catch {
|
|
$out = 'EROARE lansare sqlplus: ' + $_.Exception.Message
|
|
$code = -1
|
|
}
|
|
Remove-Item -LiteralPath $sqlFile -Force -ErrorAction SilentlyContinue
|
|
[PSCustomObject]@{ Text = ($out -join "`n"); Code = $code }
|
|
}
|
|
|
|
function Invoke-Sql {
|
|
param([string]$Sql)
|
|
Invoke-SqlAs -Sql $Sql -Connect $ConnStr
|
|
}
|
|
|
|
function Invoke-SqlSys {
|
|
# ruleaza doar daca -SysPassword a fost dat; altfel intoarce $null (apelantul trebuie sa verifice)
|
|
param([string]$Sql)
|
|
if (-not $ConnStrSys) { return $null }
|
|
Invoke-SqlAs -Sql $Sql -Connect $ConnStrSys
|
|
}
|
|
|
|
function Show-Section {
|
|
param([string]$Title, [string]$Text)
|
|
Write-Output ''
|
|
Write-Output ('===== ' + $Title + ' =====')
|
|
Write-Output $Text
|
|
if ($Text -match 'ORA-00942|ORA-01031') {
|
|
Write-Output '[AVERTISMENT] lipsesc probabil drepturi de acces (ORA-00942/ORA-01031) - pasul de mai sus poate fi incomplet cu acest utilizator.'
|
|
}
|
|
}
|
|
|
|
function Wait-RemoteFile {
|
|
# asteapta aparitia unui fisier scris de sys.ExecuteScriptOS (asincron) - polling, nu instant
|
|
param([string]$Directory, [string]$FileName, [int]$TimeoutSec = 60)
|
|
$deadline = (Get-Date).AddSeconds($TimeoutSec)
|
|
while ((Get-Date) -lt $deadline) {
|
|
$r = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 100 trimspool on feedback off heading off
|
|
select dbms_lob.fileexists(bfilename('$Directory','$FileName')) from dual;
|
|
exit
|
|
"@
|
|
if ($r.Text -match '1') { return $true }
|
|
Start-Sleep -Seconds 2
|
|
}
|
|
return $false
|
|
}
|
|
|
|
# ---------- 1. Test conexiune + versiune + CDB/PDB ----------
|
|
Write-Output '===== 1. TEST CONEXIUNE ====='
|
|
Write-Output ('Alias=' + $Alias + ' User=' + $User + ' TNS_ADMIN=' + $env:TNS_ADMIN)
|
|
$r1 = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'CONEXIUNE_OK' from dual;
|
|
select 'VERSIUNE DB: ' || banner from v`$version where rownum = 1;
|
|
select 'SCHEMA CONECTATA: ' || sys_context('userenv','session_user') || ' DB: ' || sys_context('userenv','db_name') from dual;
|
|
exit
|
|
"@
|
|
Write-Output $r1.Text
|
|
if ($r1.Code -ne 0 -or $r1.Text -notmatch 'CONEXIUNE_OK') {
|
|
Write-Output ''
|
|
Write-Output 'EROARE: conexiunea a esuat. Verifica:'
|
|
Write-Output ' - tunelul SSH pe 1521 e deschis?'
|
|
Write-Output (' - aliasul TNS ' + $Alias + ' exista in ' + $env:TNS_ADMIN + '\tnsnames.ora si tinteste 127.0.0.1?')
|
|
Write-Output ' - user/parola corecte? (implicit contafin_oracle/ROMFASTSOFT)'
|
|
Remove-TempDir
|
|
exit 1
|
|
}
|
|
|
|
$verMajor = 0
|
|
if ($r1.Text -match 'Release\s+(\d+)\.') { $verMajor = [int]$Matches[1] }
|
|
elseif ($r1.Text -match 'Database\s+(\d+)[gc]\b') { $verMajor = [int]$Matches[1] }
|
|
if ($verMajor -eq 0) {
|
|
Write-Output '[AVERTISMENT] nu am putut determina versiunea majora din banner - presupun 11 (fara facilitati 12c+).'
|
|
$verMajor = 11
|
|
}
|
|
$ver12plus = ($verMajor -ge 12)
|
|
$ver11plus = ($verMajor -ge 11)
|
|
Write-Output ('Versiune majora detectata: ' + $verMajor + ' (CDB/PDB si unified_audit_trail: ' + $(if ($ver12plus) {'da'} else {'nu, sarite mai jos'}) + ')')
|
|
|
|
if ($ver12plus) {
|
|
$rCdb = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 200 trimspool on feedback off heading off
|
|
select 'CDB=' || cdb from v`$database;
|
|
select 'CONTAINER ' || con_id || ' ' || name || ' ' || open_mode from v`$containers order by con_id;
|
|
exit
|
|
"@
|
|
Show-Section -Title '1b. CDB/PDB' -Text $rCdb.Text
|
|
} else {
|
|
Write-Output ''
|
|
Write-Output '===== 1b. CDB/PDB ====='
|
|
Write-Output 'Sarit - baza sub versiunea 12c (CDB/PDB nu se aplica pe 10.2/11g).'
|
|
}
|
|
|
|
# ---------- 2. Tablespace / datafile ----------
|
|
$r2 = Invoke-Sql -Sql @"
|
|
set pagesize 100 linesize 250 trimspool on feedback off
|
|
column tablespace_name format a15
|
|
column file_name format a55
|
|
column autoext format a4
|
|
select f.tablespace_name, f.file_name,
|
|
round(f.bytes/1048576) mb_curent,
|
|
round(f.maxbytes/1048576) mb_max,
|
|
f.autoextensible autoext,
|
|
round(f.increment_by * t.block_size / 1048576) mb_increment
|
|
from dba_data_files f, dba_tablespaces t
|
|
where f.tablespace_name = t.tablespace_name
|
|
order by f.tablespace_name, f.file_name;
|
|
column tablespace_name format a15
|
|
column stare format a26
|
|
with ts_free as (
|
|
select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name
|
|
), agg as (
|
|
select f.tablespace_name, sum(f.bytes) alocat_bytes, sum(f.maxbytes) max_bytes,
|
|
sum(greatest(f.maxbytes - f.bytes, 0)) creste_bytes
|
|
from dba_data_files f
|
|
group by f.tablespace_name
|
|
)
|
|
select a.tablespace_name,
|
|
round(a.alocat_bytes/1048576) mb_alocat,
|
|
round(a.max_bytes/1048576) mb_max,
|
|
round(nvl(tf.free_bytes,0)/1048576) mb_liber,
|
|
round((nvl(tf.free_bytes,0) + a.creste_bytes)/1048576) mb_poate_creste,
|
|
case when a.max_bytes > 0 and (nvl(tf.free_bytes,0) + a.creste_bytes) <
|
|
greatest($PragTsMb * 1048576, a.max_bytes * $PragTsPct / 100)
|
|
then 'ATENTIE: APROAPE FARA LOC' end stare
|
|
from agg a, ts_free tf
|
|
where a.tablespace_name = tf.tablespace_name(+)
|
|
order by a.tablespace_name;
|
|
exit
|
|
"@
|
|
Show-Section -Title '2. SPATIU TABLESPACE (detaliu pe datafile + cat mai poate creste)' -Text ('mb_poate_creste = liber curent + (maxbytes - alocat) - spatiul real disponibil inainte de ORA-01653, nu doar liberul de acum.' + "`n" + ('Prag de atentie: sub ' + $PragTsMb + ' MB ramasi sau sub ' + $PragTsPct + '% din maximul tablespace-ului.') + "`n`n" + $r2.Text)
|
|
|
|
# tablespace-urile care au trecut pragul de atentie - top segmente acolo
|
|
$r2m = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 100 trimspool on feedback off heading off
|
|
with ts_free as (
|
|
select tablespace_name, sum(bytes) free_bytes from dba_free_space group by tablespace_name
|
|
), agg as (
|
|
select f.tablespace_name, sum(f.maxbytes) max_bytes, sum(greatest(f.maxbytes - f.bytes, 0)) creste_bytes
|
|
from dba_data_files f
|
|
group by f.tablespace_name
|
|
)
|
|
select 'TS_ATENTIE|' || a.tablespace_name
|
|
from agg a, ts_free tf
|
|
where a.tablespace_name = tf.tablespace_name(+)
|
|
and a.max_bytes > 0
|
|
and (nvl(tf.free_bytes,0) + a.creste_bytes) <
|
|
greatest($PragTsMb * 1048576, a.max_bytes * $PragTsPct / 100);
|
|
exit
|
|
"@
|
|
$tsProblema = @($r2m.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('TS_ATENTIE|') } | ForEach-Object { $_.Substring(11) } | Where-Object { $_ -match '^[A-Z0-9_]+$' })
|
|
|
|
if ($tsProblema.Count -gt 0) {
|
|
$sbSeg = New-Object System.Text.StringBuilder
|
|
[void]$sbSeg.AppendLine('set pagesize 0 linesize 250 trimspool on feedback off heading off')
|
|
foreach ($ts in $tsProblema) {
|
|
[void]$sbSeg.AppendLine("select 'Tablespace $ts - top $Top segmente:' from dual;")
|
|
[void]$sbSeg.AppendLine(@"
|
|
select rpad(owner,20) || rpad(segment_name,35) || rpad(segment_type,18) || round(bytes/1048576) || ' MB'
|
|
from (select owner, segment_name, segment_type, bytes from dba_segments where tablespace_name = '$ts' order by bytes desc)
|
|
where rownum <= $Top;
|
|
"@)
|
|
if ($ts -eq 'SYSTEM') {
|
|
[void]$sbSeg.AppendLine("select 'NOTA: privilegiile ANY (ex. DROP ANY TABLE/TRUNCATE ANY TABLE) nu se aplica pe obiecte din schema SYS cand O7_DICTIONARY_ACCESSIBILITY=FALSE - curatarea unui tabel din SYS cere conectare SYSDBA, nu contafin_oracle.' from dual;")
|
|
}
|
|
}
|
|
[void]$sbSeg.AppendLine('exit')
|
|
$r2s = Invoke-Sql -Sql $sbSeg.ToString()
|
|
Write-Output ''
|
|
Write-Output ('--- Top segmente pe tablespace-urile marcate ATENTIE (' + ($tsProblema -join ', ') + ') ---')
|
|
Write-Output $r2s.Text
|
|
}
|
|
|
|
# MAX_PDB_STORAGE - doar daca CDB si -SysPassword dat
|
|
Write-Output ''
|
|
Write-Output '===== 2b. MAX_PDB_STORAGE (CDB$ROOT) ====='
|
|
if (-not $ver12plus) {
|
|
Write-Output 'Sarit - baza sub versiunea 12c, nu are CDB/PDB.'
|
|
} elseif (-not $ConnStrSys) {
|
|
Write-Output 'Sarit - necesita -SysPassword (conectare SYSDBA + alter session set container=CDB$ROOT; contafin_oracle nu vede limita din PDB).'
|
|
} else {
|
|
$rPdb = Invoke-SqlSys -Sql @"
|
|
set serveroutput on size 1000000
|
|
set feedback off
|
|
begin
|
|
execute immediate 'alter session set container = CDB`$ROOT';
|
|
for r in (select con_id, name, open_mode from v`$pdbs order by con_id) loop
|
|
dbms_output.put_line('PDB con_id=' || r.con_id || ' name=' || r.name || ' open_mode=' || r.open_mode);
|
|
end loop;
|
|
begin
|
|
for r in (select p.con_id, p.name, round(nvl(c.max_size,0)/1048576) mb_max
|
|
from v`$pdbs p, v`$containers c
|
|
where p.con_id = c.con_id(+)
|
|
order by p.con_id) loop
|
|
dbms_output.put_line(' ' || r.name || ' MAX_PDB_STORAGE(MB)=' || case when r.mb_max = 0 then 'nelimitat/necunoscut' else to_char(r.mb_max) end);
|
|
end loop;
|
|
exception when others then
|
|
dbms_output.put_line('MAX_PDB_STORAGE: interogare v`$containers.max_size esuata (' || sqlerrm || ').');
|
|
dbms_output.put_line('Verifica manual: ALTER PLUGGABLE DATABASE <pdb> STORAGE; sau interogheaza dba_pdbs/v`$pdbs direct pe server.');
|
|
end;
|
|
exception
|
|
when others then
|
|
if sqlcode = -1031 then
|
|
dbms_output.put_line('EROARE la comutarea pe CDB`$ROOT: ORA-01031 (privilegii insuficiente). Aliasul TNS dat tinteste probabil un serviciu de PDB (ex. XEPDB1), nu serviciul radacina al CDB - de pe un serviciu de PDB, SYSDBA nu poate comuta pe CDB`$ROOT. Necesita un alias/serviciu separat care tinteste radacina (de obicei numele instantei, nu al PDB-ului).');
|
|
else
|
|
dbms_output.put_line('EROARE la comutarea pe CDB`$ROOT: ' || sqlerrm);
|
|
end if;
|
|
end;
|
|
/
|
|
exit
|
|
"@
|
|
Write-Output $rPdb.Text
|
|
}
|
|
|
|
# ---------- 2c. Plafonul de date al editiei XE ----------
|
|
# limita editiei, independenta de maxbytes-ul tablespace-urilor: extinderea poate fi refuzata cu
|
|
# ORA-12952 desi tablespace-ul mai are loc
|
|
Write-Output ''
|
|
Write-Output '===== 2c. PLAFON DE DATE XE ====='
|
|
$xeCritic = $false
|
|
if ($r1.Text -notmatch 'Express Edition') {
|
|
Write-Output 'Sarit - editia nu e Express Edition, nu exista plafon de date pe editie.'
|
|
} else {
|
|
$xePlafonGb = if ($verMajor -le 10) { 4 } elseif ($verMajor -eq 11) { 11 } else { 12 }
|
|
$rXe = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 200 trimspool on feedback off heading off
|
|
select 'XEFOLOSIT|' || round(nvl(sum(f.bytes),0)/1048576, 2)
|
|
from dba_data_files f
|
|
where f.tablespace_name not in ('SYSTEM','SYSAUX')
|
|
and f.tablespace_name not in (select t.tablespace_name from dba_tablespaces t
|
|
where t.contents in ('UNDO','TEMPORARY'));
|
|
exit
|
|
"@
|
|
$xeFolositMb = $null
|
|
foreach ($line in ($rXe.Text -split "`r?`n")) {
|
|
if ($line.Trim() -match '^XEFOLOSIT\|([\d.]+)$') { $xeFolositMb = [double]$Matches[1] }
|
|
}
|
|
if ($null -eq $xeFolositMb) {
|
|
Write-Output 'Nu am putut masura datele de utilizator (dba_data_files) - vezi erorile de mai sus.'
|
|
Write-Output $rXe.Text
|
|
} else {
|
|
$xePlafonMb = $xePlafonGb * 1024
|
|
$xeLiberMb = $xePlafonMb - $xeFolositMb
|
|
$xePragMb = [math]::Max($PragTsMb, $xePlafonMb * $PragTsPct / 100)
|
|
$xeCritic = ($xeLiberMb -lt $xePragMb)
|
|
Write-Output ('Editie Express, plafon de date ' + $xePlafonGb + ' GB (masurat pe dba_data_files, fara SYSTEM/SYSAUX/UNDO/TEMP).')
|
|
Write-Output (' folosit = ' + [math]::Round($xeFolositMb/1024, 2) + ' GB liber pana la plafon = ' + [math]::Round($xeLiberMb, 0) + ' MB')
|
|
if ($xeCritic) {
|
|
Write-Output ('[ATENTIE] sub pragul de ' + [math]::Round($xePragMb, 0) + ' MB. Cand plafonul e atins, baza refuza extinderea cu ORA-12952 si nu se mai poate face nimic din baza - elibereaza date sau treci pe alta editie.')
|
|
}
|
|
}
|
|
}
|
|
|
|
# ---------- 3. Audit Oracle ----------
|
|
$r3 = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'AUD`$ (contafin_oracle): ' || count(*) from sys.aud`$;
|
|
select 'FGA_LOG`$ (contafin_oracle): ' || count(*) from sys.fga_log`$;
|
|
select 'audit_file_dest = ' || value from v`$parameter where name = 'audit_file_dest';
|
|
select 'audit_trail = ' || value from v`$parameter where name = 'audit_trail';
|
|
exit
|
|
"@
|
|
Show-Section -Title '3. AUDIT ORACLE (tabele, din contafin_oracle)' -Text $r3.Text
|
|
|
|
if ($ver12plus) {
|
|
$r3u = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'unified_audit_trail: ' || count(*) || ' randuri' from unified_audit_trail;
|
|
exit
|
|
"@
|
|
Show-Section -Title '3b. UNIFIED AUDIT TRAIL' -Text $r3u.Text
|
|
} else {
|
|
Write-Output ''
|
|
Write-Output '===== 3b. UNIFIED AUDIT TRAIL ====='
|
|
Write-Output 'Sarit - baza sub versiunea 12c, nu are unified auditing.'
|
|
}
|
|
|
|
if (-not $ConnStrSys) {
|
|
Write-Output ''
|
|
Write-Output '===== 3c. AUDIT INTERN (SYSDBA) ====='
|
|
Write-Output 'Sarit - necesita -SysPassword. sys.aud$/fga_log$ sunt obiecte SYS: privilegiile ANY nu se aplica pe ele (O7_DICTIONARY_ACCESSIBILITY=FALSE), deci contafin_oracle poate primi ORA-01031 mai sus chiar daca are rol DBA.'
|
|
} else {
|
|
$r3s = Invoke-SqlSys -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'AUD`$ (sysdba): ' || count(*) from sys.aud`$;
|
|
select 'FGA_LOG`$ (sysdba): ' || count(*) from sys.fga_log`$;
|
|
exit
|
|
"@
|
|
Show-Section -Title '3c. AUDIT INTERN (rezultat garantat, conectat SYSDBA)' -Text $r3s.Text
|
|
}
|
|
Write-Output 'Fisierele fizice .aud din audit_file_dest (numar + MB reale): vezi sectiunea 6 (-Disc).'
|
|
Write-Output 'Curatare (doar sugestie, niciodata executata automat): oprire viitoare = alter system set audit_trail=NONE scope=spfile (cere restart instanta); golire sys.aud$/fga_log$ = DBMS_AUDIT_MGMT.CLEAN_AUDIT_TRAIL sau delete direct, ambele SYSDBA; fisierele .aud se pot sterge direct de pe disc (independente de dictionar).'
|
|
|
|
# ---------- 4. Alert log / trace / ADR ----------
|
|
Write-Output ''
|
|
Write-Output '===== 4. ALERT LOG / TRACE / ADR (cai) ====='
|
|
$diagPaths = @()
|
|
if ($ver11plus) {
|
|
$r4 = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 300 trimspool on feedback off heading off
|
|
select 'DIAG|' || name || '|' || value from v`$diag_info where name in ('Diag Trace','Diag Alert','Diag Incident','Diag Cdump');
|
|
exit
|
|
"@
|
|
Write-Output $r4.Text
|
|
$diagPaths = @($r4.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('DIAG|') } | ForEach-Object {
|
|
$parts = $_.Substring(5) -split '\|', 2
|
|
[PSCustomObject]@{ Label = ('DIAG_' + ($parts[0] -replace '[^A-Za-z0-9]','_')).ToUpper(); Path = $parts[1] }
|
|
})
|
|
} else {
|
|
$r4 = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 300 trimspool on feedback off heading off
|
|
select 'DIAG|BACKGROUND|' || value from v`$parameter where name = 'background_dump_dest';
|
|
select 'DIAG|USER|' || value from v`$parameter where name = 'user_dump_dest';
|
|
select 'DIAG|CORE|' || value from v`$parameter where name = 'core_dump_dest';
|
|
exit
|
|
"@
|
|
Write-Output '(baza sub 11g - fara ADR/diagnostic_dest, foloseste background_dump_dest/user_dump_dest/core_dump_dest)'
|
|
Write-Output $r4.Text
|
|
$diagPaths = @($r4.Text -split "`r?`n" | ForEach-Object { $_.Trim() } | Where-Object { $_.StartsWith('DIAG|') } | ForEach-Object {
|
|
$parts = $_.Substring(5) -split '\|', 2
|
|
[PSCustomObject]@{ Label = ('DIAG_' + $parts[0]); Path = $parts[1] }
|
|
})
|
|
}
|
|
Write-Output 'Marimea reala a acestor foldere (alert log, trace, incident, cdump): vezi sectiunea 6 (-Disc) - SQL nu vede sistemul de fisiere.'
|
|
Write-Output 'Curatare (doar sugestie): adrci exec="set homepath <path>; purge -age <minute> -type ALERT/INCIDENT/TRACE" rulat ca proces extern (prin ExecuteScriptOS) - purjeaza doar diagnostic vechi, nu afecteaza baza.'
|
|
|
|
# ---------- 5. Archivelog / Fast Recovery Area ----------
|
|
$r5 = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'log_mode = ' || log_mode from v`$database;
|
|
select 'db_recovery_file_dest = ' || nvl(value,'(neconfigurat)') from v`$parameter where name = 'db_recovery_file_dest';
|
|
select 'db_recovery_file_dest_size(MB) = ' || round(to_number(value)/1048576) from v`$parameter where name = 'db_recovery_file_dest_size';
|
|
exit
|
|
"@
|
|
Show-Section -Title '5. ARCHIVELOG / FAST RECOVERY AREA' -Text $r5.Text
|
|
|
|
$r5b = Invoke-Sql -Sql @"
|
|
set pagesize 100 linesize 250 trimspool on feedback off
|
|
column name format a60
|
|
select round(space_limit/1048576) mb_limita, round(space_used/1048576) mb_folosit,
|
|
round(space_reclaimable/1048576) mb_recuperabil, number_of_files
|
|
from v`$recovery_file_dest;
|
|
column file_type format a20
|
|
select file_type, percent_space_used, percent_space_reclaimable, number_of_files
|
|
from v`$flash_recovery_area_usage
|
|
order by percent_space_used desc;
|
|
exit
|
|
"@
|
|
Show-Section -Title '5b. FRA - utilizare pe tip de fisier' -Text $r5b.Text
|
|
|
|
# linie separata, fara ambiguitate de coloane, doar pentru pragul de alarma (nu pentru afisare)
|
|
$r5c = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 100 trimspool on feedback off heading off
|
|
select 'FRAPCT|' || round(space_used*100/nullif(space_limit,0),1) from v`$recovery_file_dest;
|
|
exit
|
|
"@
|
|
$fraCritic = $false
|
|
foreach ($line in ($r5c.Text -split "`r?`n")) {
|
|
if ($line.Trim() -match '^FRAPCT\|([\d.]+)$') {
|
|
if ([double]$Matches[1] -ge $PragFraPct) { $fraCritic = $true }
|
|
}
|
|
}
|
|
if ($fraCritic) {
|
|
Write-Output ''
|
|
Write-Output ('[ATENTIE] FRA peste ' + $PragFraPct + '% din spatiul alocat. Daca log_mode=ARCHIVELOG si FRA se umple complet, baza se blocheaza pe scriere (ORA-19809/ORA-00257).')
|
|
Write-Output 'Ce se poate face fara backup: marire db_recovery_file_dest_size (daca discul are loc) - imediat, fara pierdere.'
|
|
Write-Output 'Ce NU se face fara backup real: sterge archivelog-uri neaplicate-la-backup ar rupe recuperarea (RMAN DELETE ARCHIVELOG ... BACKED UP 1 TIMES TO DISK, doar daca exista backup real configurat).'
|
|
}
|
|
|
|
# ---------- 6. Spatiu pe discurile serverului (optional, scrie un .ps1 temporar in DMPDIR) ----------
|
|
Write-Output ''
|
|
Write-Output '===== 6. SPATIU DISC (server) ====='
|
|
if (-not $Disc) {
|
|
Write-Output 'Sarit implicit - ruleaza cu -Disc pentru spatiul liber pe discurile fizice si marimea reala a folderelor oradata/audit/diag/DMPDIR/FRA.'
|
|
Write-Output 'Este singura parte a scriptului care NU e strict read-only: scrie un .ps1 temporar in DMPDIR (prin sys.ExecuteScriptOS) si il sterge la final.'
|
|
} else {
|
|
$rFolders = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 300 trimspool on feedback off heading off
|
|
select 'ORADATA|' || substr(file_name,1,instr(file_name,'\',-1)-1)
|
|
from (select distinct substr(file_name,1,instr(file_name,'\',-1)-1) file_name from dba_data_files);
|
|
select 'AUDITDIR|' || value from v`$parameter where name = 'audit_file_dest';
|
|
select 'DMPDIR|' || directory_path from all_directories where directory_name = 'DMPDIR';
|
|
select 'FRADIR|' || value from v`$parameter where name = 'db_recovery_file_dest' and value is not null;
|
|
exit
|
|
"@
|
|
$folders = New-Object System.Collections.ArrayList
|
|
$seen = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase)
|
|
foreach ($line in ($rFolders.Text -split "`r?`n")) {
|
|
$line = $line.Trim()
|
|
foreach ($prefix in @('ORADATA','AUDITDIR','DMPDIR','FRADIR')) {
|
|
if ($line.StartsWith($prefix + '|')) {
|
|
$p = $line.Substring($prefix.Length + 1).Trim()
|
|
if ($p -and $seen.Add($prefix + '::' + $p.ToUpper())) {
|
|
[void]$folders.Add([PSCustomObject]@{ Label = $prefix; Path = $p })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
foreach ($dp in $diagPaths) {
|
|
if ($dp.Path -and $seen.Add($dp.Label + '::' + $dp.Path.ToUpper())) {
|
|
[void]$folders.Add($dp)
|
|
}
|
|
}
|
|
|
|
$psTemplate = @'
|
|
$dOut = 'C:\DMPDIR\diag_spatiu_out.txt'
|
|
Get-WmiObject Win32_LogicalDisk -Filter "DriveType=3" | ForEach-Object {
|
|
$pct = 0
|
|
if ($_.Size -gt 0) { $pct = [math]::Round($_.FreeSpace/$_.Size*100,1) }
|
|
"DISC {0} {1} {2} {3}" -f $_.DeviceID, [math]::Round($_.Size/1GB,2), [math]::Round($_.FreeSpace/1GB,2), $pct
|
|
} | Out-File -Encoding ascii $dOut
|
|
__FOLDERS__
|
|
'@
|
|
$folderLines = foreach ($f in $folders) {
|
|
$escaped = $f.Path.Replace("'", "''")
|
|
$lbl = $f.Label
|
|
@"
|
|
if (Test-Path -LiteralPath '$escaped') {
|
|
`$items = Get-ChildItem -LiteralPath '$escaped' -Recurse -File -ErrorAction SilentlyContinue
|
|
`$cnt = @(`$items).Count
|
|
`$sum = (`$items | Measure-Object -Property Length -Sum).Sum
|
|
if (-not `$sum) { `$sum = 0 }
|
|
"FOLDER $lbl|$escaped|{0}|{1}" -f `$cnt, [math]::Round(`$sum/1MB,1) | Out-File -Encoding ascii -Append `$dOut
|
|
`$aud = @(`$items | Where-Object { `$_.Extension -ieq '.aud' })
|
|
if (`$aud.Count -gt 0) {
|
|
`$audSum = (`$aud | Measure-Object -Property Length -Sum).Sum
|
|
"AUDFILES $lbl|{0}|{1}" -f `$aud.Count, [math]::Round(`$audSum/1MB,1) | Out-File -Encoding ascii -Append `$dOut
|
|
}
|
|
} else {
|
|
"FOLDER $lbl|$escaped|MISSING" | Out-File -Encoding ascii -Append `$dOut
|
|
}
|
|
"@
|
|
}
|
|
$psScript = $psTemplate.Replace('__FOLDERS__', ([string]::Join("`n", $folderLines)))
|
|
$psScriptSql = $psScript.Replace("'", "''")
|
|
|
|
$rLaunch = Invoke-Sql -Sql @"
|
|
set serveroutput on size 1000000
|
|
set feedback off
|
|
declare
|
|
lcPS server_info.value%type;
|
|
begin
|
|
select value into lcPS from server_info where upper(name) = 'POWERSHELLPATH';
|
|
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu_out.txt'); exception when others then null; end;
|
|
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu.ps1'); exception when others then null; end;
|
|
pack_utils_file.clob2fileX('$psScriptSql', 'DMPDIR', 'diag_spatiu.ps1');
|
|
sys.ExecuteScriptOS(lcPS, 'C:\DMPDIR\diag_spatiu.ps1');
|
|
dbms_output.put_line('Lansat pe server (' || lcPS || '), astept rezultatul...');
|
|
exception when others then
|
|
dbms_output.put_line('EROARE la lansare: ' || sqlerrm);
|
|
end;
|
|
/
|
|
exit
|
|
"@
|
|
Write-Output $rLaunch.Text
|
|
|
|
if ($rLaunch.Text -notmatch 'EROARE la lansare') {
|
|
$gata = Wait-RemoteFile -Directory 'DMPDIR' -FileName 'diag_spatiu_out.txt' -TimeoutSec 60
|
|
if (-not $gata) {
|
|
Write-Output 'EROARE: rezultatul nu a aparut in 60s. Posibile cauze: server_info.POWERSHELLPATH gresit, politica de executie PowerShell blocheaza scriptul, sys.ExecuteScriptOS nu are drept de executie, sau serverul nu e Windows (DMPDIR pe cale Linux - mecanismul ExecuteScriptOS e specific Windows/PowerShell). Verifica manual C:\DMPDIR\diag_spatiu.ps1 pe server.'
|
|
Invoke-Sql -Sql @"
|
|
set feedback off
|
|
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu.ps1'); exception when others then null; end;
|
|
/
|
|
exit
|
|
"@ | Out-Null
|
|
Write-Output 'Curatare: am incercat oricum stergerea diag_spatiu.ps1 din DMPDIR (best-effort, fara confirmare de succes daca serverul nu a raspuns).'
|
|
} else {
|
|
$rRead = Invoke-Sql -Sql @"
|
|
set serveroutput on size 1000000
|
|
set feedback off
|
|
declare
|
|
lf utl_file.file_type;
|
|
lc_line varchar2(32767);
|
|
begin
|
|
lf := utl_file.fopen('DMPDIR','diag_spatiu_out.txt','R',32767);
|
|
begin
|
|
loop
|
|
utl_file.get_line(lf, lc_line, 32767);
|
|
dbms_output.put_line(lc_line);
|
|
end loop;
|
|
exception when no_data_found then null;
|
|
end;
|
|
utl_file.fclose(lf);
|
|
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu_out.txt'); exception when others then null; end;
|
|
begin pack_utils_file.filedelete('DMPDIR','diag_spatiu.ps1'); exception when others then null; end;
|
|
exception when others then
|
|
dbms_output.put_line('EROARE citire: ' || sqlerrm);
|
|
end;
|
|
/
|
|
exit
|
|
"@
|
|
$discLines = @()
|
|
$folderLinesOut = @()
|
|
foreach ($line in ($rRead.Text -split "`r?`n")) {
|
|
if ($line -match '^DISC\s+(\S+)\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)') {
|
|
$discLines += (' disc {0}: total {1} GB, liber {2} GB ({3}%)' -f $Matches[1], $Matches[2], $Matches[3], $Matches[4])
|
|
} elseif ($line -match '^FOLDER\s+(\S+)\|(.+)\|MISSING\s*$') {
|
|
$folderLinesOut += (' {0} ({1}): nu exista pe server' -f $Matches[1], $Matches[2])
|
|
} elseif ($line -match '^FOLDER\s+(\S+)\|(.+)\|(\d+)\|([\d.]+)\s*$') {
|
|
$folderLinesOut += (' {0} ({1}): {2} fisiere, {3} MB' -f $Matches[1], $Matches[2], $Matches[3], $Matches[4])
|
|
} elseif ($line -match '^AUDFILES\s+(\S+)\|(\d+)\|([\d.]+)\s*$') {
|
|
$folderLinesOut += (' din care .aud: {0} fisiere, {1} MB' -f $Matches[2], $Matches[3])
|
|
} elseif ($line -match '\S') {
|
|
$discLines += (' ' + $line)
|
|
}
|
|
}
|
|
Write-Output 'Discuri fixe:'
|
|
Write-Output ($discLines -join "`n")
|
|
Write-Output 'Foldere (oradata / audit / diag / DMPDIR / FRA):'
|
|
Write-Output ($folderLinesOut -join "`n")
|
|
}
|
|
}
|
|
}
|
|
|
|
# ---------- 7. Alti mancatori de spatiu ----------
|
|
Write-Output ''
|
|
Write-Output '===== 7. ALTI MANCATORI DE SPATIU ====='
|
|
|
|
$r7a = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'user_recyclebin (schema ' || sys_context('userenv','session_user') || '): ' || count(*) || ' obiecte, ' ||
|
|
round(sum(space)*8192/1048576) || ' MB (aprox, space in blocuri)'
|
|
from user_recyclebin;
|
|
exit
|
|
"@
|
|
Show-Section -Title '7a. RECYCLEBIN (schema conectata)' -Text $r7a.Text
|
|
|
|
if ($ConnStrSys) {
|
|
$r7as = Invoke-SqlSys -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'dba_recyclebin (toata baza): ' || count(*) || ' obiecte, ' ||
|
|
round(sum(space)*8192/1048576) || ' MB (aprox)'
|
|
from dba_recyclebin;
|
|
exit
|
|
"@
|
|
Show-Section -Title '7a-bis. RECYCLEBIN (toata baza, SYSDBA)' -Text $r7as.Text
|
|
} else {
|
|
Write-Output 'RECYCLEBIN la nivel de baza (dba_recyclebin): sarit - necesita -SysPassword.'
|
|
}
|
|
|
|
$r7b = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'UNDO tablespace = ' || value from v`$parameter where name = 'undo_tablespace';
|
|
select 'UNDO alocat(MB) = ' || round(sum(bytes)/1048576)
|
|
from dba_data_files
|
|
where tablespace_name = (select value from v`$parameter where name = 'undo_tablespace');
|
|
select 'tranzactii active = ' || count(*) from v`$transaction;
|
|
exit
|
|
"@
|
|
Show-Section -Title '7b. UNDO' -Text ($r7b.Text + "`nResize UNDO poate da ORA-03297 daca extenturile nu au expirat inca - de incercat doar dupa ce activitatea scade, niciodata automat.")
|
|
|
|
$r7c = Invoke-Sql -Sql @"
|
|
set pagesize 0 linesize 250 trimspool on feedback off heading off
|
|
select 'dba_tab_stats_history: ' || count(*) || ' randuri, cel mai vechi = ' || to_char(min(stats_update_time),'yyyy-mm-dd')
|
|
from dba_tab_stats_history;
|
|
select 'dba_scheduler_job_run_details: ' || count(*) || ' randuri, cel mai vechi = ' || to_char(min(log_date),'yyyy-mm-dd')
|
|
from dba_scheduler_job_run_details;
|
|
exit
|
|
"@
|
|
Show-Section -Title '7c. ISTORIC STATISTICI / SCHEDULER' -Text ($r7c.Text + "`nCuratare (doar sugestie): DBMS_STATS.PURGE_STATS(<data>); DBMS_SCHEDULER.PURGE_LOG(log_history => <zile>).")
|
|
|
|
$r7d = Invoke-Sql -Sql @"
|
|
set pagesize 100 linesize 250 trimspool on feedback off
|
|
column tablespace_name format a20
|
|
select tablespace_name, round(sum(bytes)/1048576) mb_alocat from dba_temp_files group by tablespace_name;
|
|
column tablespace_name format a20
|
|
select tablespace_name, round(sum(bytes_used)/1048576) mb_folosit, round(sum(bytes_free)/1048576) mb_liber
|
|
from v`$temp_space_header group by tablespace_name;
|
|
exit
|
|
"@
|
|
Show-Section -Title '7d. TEMP (alocat vs folosit)' -Text $r7d.Text
|
|
|
|
$r7e = Invoke-Sql -Sql @"
|
|
set pagesize 100 linesize 250 trimspool on feedback off
|
|
column owner format a20
|
|
column segment_name format a35
|
|
column segment_type format a18
|
|
column tablespace_name format a15
|
|
select * from (
|
|
select owner, segment_name, segment_type, tablespace_name, round(bytes/1048576) mb
|
|
from dba_segments
|
|
order by bytes desc
|
|
) where rownum <= $Top;
|
|
exit
|
|
"@
|
|
Show-Section -Title ('7e. TOP ' + $Top + ' SEGMENTE DIN TOATA BAZA (generic, fara nume hardcodate)') -Text $r7e.Text
|
|
|
|
# ---------- 8. Verdict ----------
|
|
Write-Output ''
|
|
Write-Output '===== 8. VERDICT ====='
|
|
if ($tsProblema.Count -gt 0) {
|
|
Write-Output ('Tablespace-uri aproape fara loc: ' + ($tsProblema -join ', ') + '. Vezi sectiunea 2 pentru top segmente acolo - candidatii de curatare/crestere maxbytes sunt acolo.')
|
|
} else {
|
|
Write-Output ('Niciun tablespace sub pragul de atentie (' + $PragTsMb + ' MB sau ' + $PragTsPct + '% din maxim, sectiunea 2).')
|
|
}
|
|
if ($xeCritic) {
|
|
Write-Output ('Plafonul de date al editiei XE e aproape atins (sectiunea 2c) - la ORA-12952 nu se mai poate face nimic din baza. Prioritate maxima: eliberare de date sau trecere pe alta editie.')
|
|
}
|
|
if ($fraCritic) {
|
|
Write-Output ('FRA peste ' + $PragFraPct + '% din spatiul alocat (sectiunea 5b) - risc de blocaj pe scriere daca log_mode=ARCHIVELOG. Prioritate: verifica arhivarea/backup-ul inainte sa se umple complet.')
|
|
}
|
|
Write-Output 'Ordine tipica de curatare (cea mai sigura primul): fisiere .aud vechi din audit_file_dest (sters direct pe disc, fara privilegii DB) -> adrci purge pe alert/trace/incident vechi -> istoric statistici/scheduler (DBMS_STATS.PURGE_STATS / DBMS_SCHEDULER.PURGE_LOG) -> recyclebin -> resize UNDO dupa ce scade activitatea -> curatare SYS.aud$/fga_log$ sau alte tabele interne (cere SYSDBA) -> ca ultima solutie, recreare PDB (export/import).'
|
|
if (-not $ConnStrSys) {
|
|
Write-Output 'Fara -SysPassword: sectiunile 2b (MAX_PDB_STORAGE), 3c (audit intern sys.aud$/fga_log$) si 7a-bis (dba_recyclebin) au fost sarite - ruleaza cu -SysPassword daca ai parola SYS a acestui client pentru imaginea completa.'
|
|
}
|
|
if (-not $Disc) {
|
|
Write-Output 'Fara -Disc: marimile reale pe disc (audit_file_dest, alert/trace/ADR, oradata, FRA, discuri fizice) nu au fost masurate - ruleaza cu -Disc pentru ele.'
|
|
}
|
|
|
|
Remove-TempDir
|
|
exit 0
|