@echo off setlocal EnableExtensions DisableDelayedExpansion title SRtecno - Diagnostico e Manutencao v3 set "SRTECNO_SELF=%~f0" powershell.exe -NoProfile -Command "$ErrorActionPreference='Stop'; try { $text=[IO.File]::ReadAllText($env:SRTECNO_SELF); $parts=$text -split '(?m)^# POWERSHELL_PAYLOAD\r?$',2; if($parts.Count -ne 2){throw 'Conteudo incompleto'}; & ([scriptblock]::Create($parts[1])) } catch {Write-Host ('Erro: '+$_.Exception.Message); exit 1}" set "SRTECNO_RC=%errorlevel%" echo. pause exit /b %SRTECNO_RC% # POWERSHELL_PAYLOAD # SRtecno v3 - Windows PowerShell 5.1 / Windows 10 e 11 # Um unico BAT; nao instala modulos nem altera a politica de execucao. $ErrorActionPreference = 'Stop' $admin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) if (-not $admin) { Write-Host 'Clique com o botao direito e escolha Executar como administrador.'; exit 1 } function Ask([string]$text) { return ((Read-Host ($text + ' [S/N; Enter=N]')) -match '^(s|sim)$') } function Section([string]$title, [scriptblock]$action) { Write-Host "`n--- $title ---" -ForegroundColor Cyan try { & $action | Out-Host } catch { Write-Host ('INDISPONIVEL/FALHA: ' + $_.Exception.Message) -ForegroundColor Yellow } } $script:codes = New-Object 'System.Collections.Generic.List[object]' function Run-Native([string]$exe, [string[]]$arguments) { Write-Host "`nExecutando: $exe $($arguments -join ' ')" # Native stderr may be rendered as PowerShell error records; keep draining output. $old = $ErrorActionPreference $ErrorActionPreference = 'Continue' try { & $exe @arguments 2>&1 | Out-Host $code = $LASTEXITCODE $script:codes.Add([pscustomobject]@{Comando=($exe+' '+($arguments -join ' ')); Codigo=$code}) Write-Host "Codigo de saida: $code. Consulte as mensagens; os codigos variam por ferramenta." } finally { $ErrorActionPreference = $old } } function Disk-Free { Get-CimInstance Win32_LogicalDisk -Filter 'DriveType=3' -OperationTimeoutSec 20 | Select-Object DeviceID, FileSystem, @{N='TotalGiB';E={[math]::Round($_.Size/1GB,2)}}, @{N='LivreGiB';E={[math]::Round($_.FreeSpace/1GB,2)}}, FreeSpace } function Reboot-Status { $signals = New-Object 'System.Collections.Generic.List[string]' foreach($entry in @( @('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending','Componentes do Windows'), @('HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired','Windows Update') )) { if(Test-Path $entry[0]) { $signals.Add($entry[1]) } } $pending = Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager' -Name PendingFileRenameOperations -ErrorAction SilentlyContinue if($pending.PendingFileRenameOperations) { $signals.Add('Operacoes de arquivos pendentes') } if($signals.Count) { Write-Output ('Indicios de reinicio pendente: '+($signals -join '; ')) } else { Write-Output 'Nenhum indicio encontrado nos locais consultados; nao e verificacao exaustiva.' } } Write-Host 'SRtecno - Diagnostico e Manutencao v3' -ForegroundColor Cyan Write-Host '1 - Diagnostico: coleta informacoes, sem limpeza, reparo ou instalacao.' Write-Host '2 - Rotina: diagnostico + limpeza + opcoes de atualizacao e antivirus.' Write-Host '3 - Reparo: diagnostico + DISM/SFC + CHKDSK e extras opcionais.' do { $mode = Read-Host 'Escolha 1, 2 ou 3' } until($mode -in @('1','2','3')) $client = Read-Host 'Cliente (opcional)' $order = Read-Host 'Numero da OS (opcional)' $updateSearch = Ask 'Consultar atualizacoes pendentes do Windows pela internet' $cleanup = $mode -eq '2' $upgrade = $false; $scanAV = $false; $openWU = $false; $diskMode = '0' if($mode -ne '1') { Write-Host 'Salve o trabalho, feche os programas e mantenha o notebook na energia.' if($mode -eq '3') { $cleanup = Ask 'Incluir limpeza de temporarios e de disco' } $upgrade = Ask 'Atualizar aplicativos com winget --all' $scanAV = Ask 'Atualizar assinaturas e fazer verificacao rapida do Microsoft Defender' $openWU = Ask 'Abrir Windows Update ao final para voce escolher e instalar atualizacoes' Write-Host 'CHKDSK: 0=nao executar; 1=/scan online; 2=/b profundo, pode levar horas e pedir reinicio.' do { $diskMode = Read-Host 'Escolha 0, 1 ou 2' } until($diskMode -in @('0','1','2')) } $folder = Join-Path $env:ProgramData 'SRtecno\Logs' New-Item -ItemType Directory -Path $folder -Force | Out-Null $log = Join-Path $folder ('Manutencao_'+$env:COMPUTERNAME+'_'+(Get-Date -Format 'yyyyMMdd_HHmmss')+'_'+[guid]::NewGuid().ToString('N').Substring(0,6)+'.txt') $fatalFailure = $false Start-Transcript -Path $log -Force | Out-Null try { Write-Host ('Inicio: '+(Get-Date -Format 'yyyy/MM/dd HH:mm:ss')) Write-Host "Cliente: $client | OS: $order | Modo: $mode" Write-Host "Computador: $env:COMPUTERNAME | Conta executora: $env:USERDOMAIN\$env:USERNAME" Write-Host "Opcoes: limpeza=$cleanup; winget=$upgrade; Defender=$scanAV; CHKDSK=$diskMode; consulta Windows Update=$updateSearch" Write-Host "Relatorio: $log" Section 'Computador e Windows' { Get-CimInstance Win32_ComputerSystem -OperationTimeoutSec 20 | Select-Object Manufacturer,Model,@{N='RAM_GiB';E={[math]::Round($_.TotalPhysicalMemory/1GB,2)}} | Format-List Get-CimInstance Win32_OperatingSystem -OperationTimeoutSec 20 | Select-Object Caption,Version,BuildNumber,OSArchitecture,LastBootUpTime | Format-List Get-CimInstance Win32_Processor -OperationTimeoutSec 20 | Select-Object Name,NumberOfCores,NumberOfLogicalProcessors | Format-Table -AutoSize } Section 'Espaco livre inicial' { Disk-Free | Select-Object DeviceID,FileSystem,TotalGiB,LivreGiB | Format-Table -AutoSize } Section 'Saude do armazenamento' { Write-Output 'Triagem: status Healthy/OK nao garante ausencia de defeitos. Ausencia de dados nao significa disco saudavel.' $disks = @(Get-PhysicalDisk) if(-not $disks.Count) { Write-Output 'Nenhum disco retornado pelo provedor.' } foreach($d in $disks) { $d | Select-Object DeviceId,FriendlyName,MediaType,BusType,HealthStatus,OperationalStatus,@{N='GiB';E={[math]::Round($_.Size/1GB,2)}} | Format-List try { $r = $d | Get-StorageReliabilityCounter -ErrorAction Stop if($null -eq $r) { Write-Output 'Contadores indisponiveis.'; continue } foreach($name in @('Temperature','Wear','PowerOnHours','ReadErrorsUncorrected','WriteErrorsUncorrected')) { $v = $r.$name if($null -eq $v) { $v = 'Nao informado' } Write-Output ($name+': '+$v) } Write-Output 'Valores dependem do dispositivo/controlador; temperatura 0 pode significar nao suportada.' } catch { Write-Output ('Contadores nao disponiveis neste dispositivo: '+$_.Exception.Message) } } } Section 'Antivirus registrados' { $products = @(Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntivirusProduct -OperationTimeoutSec 20) if($products.Count) { $products | Select-Object displayName,productState | Format-Table -AutoSize } else { Write-Output 'Nenhum produto retornado. Conferir Seguranca do Windows.' } Write-Output 'Registro de produto nao comprova protecao ativa. Status detalhado abaixo e do Microsoft Defender.' } Section 'Microsoft Defender' { Get-MpComputerStatus | Select-Object AMRunningMode,AntivirusEnabled,RealTimeProtectionEnabled,AntivirusSignatureLastUpdated,AntivirusSignatureAge,QuickScanEndTime | Format-List } Section 'Inicializacao - somente listagem' { Get-CimInstance Win32_StartupCommand -OperationTimeoutSec 20 | Select-Object Name,Command,Location,User | Format-List Write-Output 'Lista parcial: nao inclui todas as tarefas agendadas e servicos. Nenhum item foi desativado.' } Section 'Erros e eventos criticos do sistema nos ultimos 7 dias - ate 30' { try { Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2; StartTime=(Get-Date).AddDays(-7)} -MaxEvents 30 -ErrorAction Stop | Select-Object TimeCreated,Id,ProviderName,Message | Format-List } catch { if($_.FullyQualifiedErrorId -like 'NoMatchingEventsFound*') { Write-Output 'Nenhum evento correspondente encontrado.' } else { throw } } Write-Output 'Eventos antigos ou isolados nao confirmam defeito atual; interpretar no contexto do atendimento.' } Section 'Reinicio pendente - inicio' { Reboot-Status } if($updateSearch) { Section 'Windows Update - consulta, sem instalar' { Write-Host 'Consultando... limite de 180 segundos. Usa o servico configurado pelo Windows/empresa.' $job = Start-Job -ScriptBlock { $ErrorActionPreference='Stop' $session = New-Object -ComObject Microsoft.Update.Session $result = $session.CreateUpdateSearcher().Search("IsInstalled=0 and IsHidden=0 and Type='Software'") Write-Output ('Codigo da consulta: '+$result.ResultCode+' (2=sucesso; 3=sucesso com erros)') if($result.ResultCode -notin @(2,3)) { throw 'Consulta nao concluida com sucesso.' } Write-Output ('Atualizacoes retornadas: '+$result.Updates.Count) foreach($u in $result.Updates) { Write-Output ('- '+$u.Title) } } try { if(Wait-Job $job -Timeout 180) { Receive-Job $job -ErrorAction Stop if($job.State -eq 'Failed') { throw 'Consulta falhou; verificar Windows Update manualmente.' } } else { Write-Output 'Tempo limite: resultado desconhecido. Verifique Windows Update manualmente.' } } finally { Stop-Job $job -ErrorAction SilentlyContinue; Remove-Job $job -Force -ErrorAction SilentlyContinue } } } else { Write-Host 'Consulta de atualizacoes pendentes: nao solicitada.' } if($mode -ne '1') { Write-Host "`nDiagnostico coletado. Confira saude do disco e backup antes de prosseguir." $proceed = Ask 'Continuar com as acoes selecionadas' if($proceed) { if($diskMode -eq '1') { Section 'CHKDSK online - volume do Windows' { $vol = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='$env:SystemDrive'" -OperationTimeoutSec 20 if($vol.FileSystem -ne 'NTFS') { throw 'Opcao /scan exige NTFS; etapa ignorada.' } Run-Native 'chkdsk.exe' @($env:SystemDrive,'/scan') } } if($mode -eq '3') { Section 'Reparo de componentes do Windows' { Run-Native 'DISM.exe' @('/Online','/Cleanup-Image','/CheckHealth') Run-Native 'DISM.exe' @('/Online','/Cleanup-Image','/ScanHealth') Run-Native 'DISM.exe' @('/Online','/Cleanup-Image','/RestoreHealth') } Section 'Verificacao de arquivos do sistema' { Run-Native 'sfc.exe' @('/scannow') } } if($upgrade) { Section 'Atualizacao de aplicativos' { if(-not (Get-Command winget.exe -ErrorAction SilentlyContinue)) { throw 'Winget indisponivel nesta conta; etapa ignorada.' } Write-Host 'Instaladores podem pedir confirmacoes. Nao foi autorizado reinicio automatico pelo winget.' Run-Native 'winget.exe' @('upgrade','--all') } } if($scanAV) { Section 'Atualizar assinaturas e verificar com Defender' { $mp = Get-MpComputerStatus if(-not $mp.AntivirusEnabled -or $mp.AMRunningMode -ne 'Normal') { throw 'Defender nao esta ativo em modo Normal. Use o antivirus instalado; etapa ignorada.' } try { Update-MpSignature; Write-Output 'Assinaturas atualizadas.' } catch { Write-Output ('Falha ao atualizar assinaturas: '+$_.Exception.Message) } Write-Host 'Iniciando verificacao rapida. O Defender pode tratar ameacas conforme a politica configurada.' Start-MpScan -ScanType QuickScan Get-MpComputerStatus | Select-Object QuickScanStartTime,QuickScanEndTime,AntivirusSignatureLastUpdated | Format-List Write-Output 'Confira o Historico de Protecao para deteccoes e acoes; termino do comando nao significa ausencia de ameacas.' } } if($cleanup) { Section 'Limpeza de temporarios e de disco' { # Measure immediately around cleaning, not around upgrades/repairs. $before = @(Disk-Free) $script:removed=0; $script:skipped=0; $script:bytes=0L $cut=(Get-Date).AddDays(-1) function Clean-Temp([string]$path) { $items = @(Get-ChildItem -LiteralPath $path -Force -ErrorAction SilentlyContinue) foreach($item in $items) { if($item.Attributes -band [IO.FileAttributes]::ReparsePoint) { $script:skipped++; continue } if($item.PSIsContainer) { Clean-Temp $item.FullName try { [IO.Directory]::Delete($item.FullName,$false) } catch { } } elseif($item.LastWriteTime -lt $cut) { try { $size=$item.Length; Remove-Item -LiteralPath $item.FullName -Force -ErrorAction Stop; $script:removed++; $script:bytes+=$size } catch { $script:skipped++ } } } } # Include actual TEMP only if its leaf is Temp/Tmp; reject root/profile misconfiguration. $roots = @((Join-Path $env:LOCALAPPDATA 'Temp'),(Join-Path $env:SystemRoot 'Temp')) if($env:TEMP -and ((Split-Path $env:TEMP.TrimEnd('\') -Leaf) -match '^(Temp|Tmp)$')) { $roots += $env:TEMP } foreach($root in ($roots | Select-Object -Unique)) { $dir=Get-Item -LiteralPath $root -Force -ErrorAction SilentlyContinue if(-not $dir -or -not $dir.PSIsContainer) { Write-Output "Pasta indisponivel: $root"; continue } $parent=$dir; $linked=$false while($null -ne $parent) { if($parent.Attributes -band [IO.FileAttributes]::ReparsePoint){$linked=$true;break}; $parent=$parent.Parent } if($linked) { Write-Output "Pasta com link/junction ignorada: $root"; continue } Write-Output "Limpando arquivos com mais de 24 horas: $root" Clean-Temp $dir.FullName } Write-Output ('Arquivos removidos: '+$script:removed+' | Bloqueados/links ignorados: '+$script:skipped) Write-Output ('Tamanho logico dos temporarios removidos: '+[math]::Round($script:bytes/1MB,2)+' MiB') $cleanmgr=Join-Path $env:SystemRoot 'System32\cleanmgr.exe' if(Test-Path $cleanmgr) { Write-Host 'Escolha categorias na Limpeza de Disco. Confira Lixeira, Downloads e instalacoes anteriores.' Start-Process $cleanmgr -ArgumentList '/sageset:784' -Wait if(Ask 'Executar a Limpeza de Disco com as categorias escolhidas') { Start-Process $cleanmgr -ArgumentList '/sagerun:784' -Wait } else { Write-Output 'Limpeza de Disco cancelada; temporarios ja foram tratados.' } } else { Write-Output 'Cleanmgr indisponivel. Limpeza de Disco ignorada.' } $after=@(Disk-Free) foreach($a in $after) { $b=$before | Where-Object DeviceID -eq $a.DeviceID | Select-Object -First 1 if($null -ne $b) { [pscustomobject]@{Unidade=$a.DeviceID; AntesGiB=$b.LivreGiB; DepoisGiB=$a.LivreGiB; VariacaoGiB=[math]::Round(($a.FreeSpace-$b.FreeSpace)/1GB,3)} | Format-List } } Write-Output 'Variacao positiva = mais espaco livre. Outras atividades do Windows podem afetar a medicao.' } } if($diskMode -eq '2') { Section 'CHKDSK profundo - volume do Windows' { $vol=Get-CimInstance Win32_LogicalDisk -Filter "DeviceID='$env:SystemDrive'" -OperationTimeoutSec 20 if($vol.FileSystem -ne 'NTFS') { throw '/b exige NTFS; etapa ignorada.' } Write-Host 'Pode levar horas. /b inclui /r e /f. Responda S ou Y ao Windows para agendar, se solicitado.' # Direct console input is required for the localized scheduling prompt. & chkdsk.exe $env:SystemDrive /b $script:codes.Add([pscustomobject]@{Comando='chkdsk /b';Codigo=$LASTEXITCODE}) Write-Output 'Confira na tela se o agendamento foi aceito. Codigo sozinho nao comprova agendamento.' Write-Output 'Resultado apos reiniciar fica no Visualizador de Eventos e nao integra este relatorio.' } } if($openWU) { Section 'Windows Update - instalacao manual' { Start-Process 'ms-settings:windowsupdate'; Write-Output 'Painel aberto. Escolha as atualizacoes; instalacao e reinicio ficam sob seu controle.' } } } else { Write-Host 'Acoes canceladas. Somente o diagnostico foi realizado.' } } Section 'Reinicio pendente - final' { Reboot-Status } Section 'Codigos dos comandos executados' { if($script:codes.Count) { $script:codes | Format-Table -Wrap -AutoSize } else { Write-Output 'Nenhum comando de reparo/winget/CHKDSK executado.' } } Write-Host "`nSequencia encerrada. Confira falhas/indisponibilidades e mensagens; isto nao garante que o PC esteja sem problemas." Write-Host 'Nao ha reinicio automatico neste script. Reinicie quando conveniente e teste a queixa do cliente.' Write-Host 'Detalhes de reparos: Windows\Logs\CBS\CBS.log e Windows\Logs\DISM\dism.log.' Write-Host ('Fim: '+(Get-Date -Format 'yyyy/MM/dd HH:mm:ss')) } catch { $fatalFailure = $true Write-Host ('ERRO GERAL: '+$_.Exception.Message) -ForegroundColor Red Write-Host 'Execucao interrompida. O relatorio parcial permanece salvo.' } finally { Stop-Transcript | Out-Null Write-Host "Relatorio local: $log" -ForegroundColor Green } if($fatalFailure) { exit 1 }