diff --git a/optimization.ps1 b/optimization.ps1 index e990994..90476a8 100644 --- a/optimization.ps1 +++ b/optimization.ps1 @@ -1,73 +1,225 @@ -# Function to run process with true live streaming output -function Start-ProcessWithLiveStreaming { +$ScriptResult = @{ + success = $true + system_optimization = @{ + "chkdsk" = @{ + "run" = $false + "success" = $false + "exit_code" = $null + "message" = "" + "reboot_required" = $false + "diskSpace" = "" + "errors" = @() + } + "sfc" = @{ + "run" = $false + "success" = $false + "exit_code" = $null + "message" = "" + "files_repaired" = 0 + "errors" = @() + } + "dism" = @{ + "run" = $false + "success" = $false + "exit_code" = $null + "message" = "" + "component_repaired" = $false + "errors" = @() + } + } +} + +$tempPath = $env:TEMP + +# Function to run process with live output using job +function Start-ProcessWithLiveOutput { param( [string]$FilePath, [string]$Arguments, [string]$Name ) - $tempPath = $env:TEMP $stdoutFile = "$tempPath\${Name}_stdout.txt" $stderrFile = "$tempPath\${Name}_stderr.txt" # Clean up old files - if (Test-Path $stdoutFile) { Remove-Item $stdoutFile -ErrorAction SilentlyContinue } - if (Test-Path $stderrFile) { Remove-Item $stderrFile -ErrorAction SilentlyContinue } - - # Create file handles for immediate reading - $fileStream = [System.IO.File]::Create($stdoutFile) + if (Test-Path $stdoutFile) { Remove-Item $stdoutFile -Force -ErrorAction SilentlyContinue } + if (Test-Path $stderrFile) { Remove-Item $stderrFile -Force -ErrorAction SilentlyContinue } Write-Host "Starting $Name..." - # Start the process + # Start process $process = Start-Process -FilePath $FilePath -ArgumentList $Arguments -NoNewWindow -PassThru -RedirectStandardOutput $stdoutFile -RedirectStandardError $stderrFile -ErrorAction Stop - # Read output while process runs - $lastPosition = 0 - while (-not $process.HasExited) { - Start-Sleep -Milliseconds 500 + # Start background job to read output while process runs + $job = Start-Job -ScriptBlock { + param($stdoutFile, $stderrFile, $processId) - if (Test-Path $stdoutFile) { - $currentLength = (Get-Item $stdoutFile).Length - if ($currentLength -gt $lastPosition) { - $bytesToRead = $currentLength - $lastPosition - $stream = [System.IO.File]::OpenRead($stdoutFile) - $stream.Seek($lastPosition, [System.IO.SeekOrigin]::Begin) | Out-Null - $buffer = New-Object byte[] $bytesToRead - $stream.Read($buffer, 0, $bytesToRead) | Out-Null - $stream.Close() - $text = [System.Text.Encoding]::UTF8.GetString($buffer) - Write-Host $text -NoNewline - $lastPosition = $currentLength + $lastStdoutPos = 0 + $lastStderrPos = 0 + + while ($true) { + # Check if process still running + $proc = Get-Process -Id $processId -ErrorAction SilentlyContinue + if (-not $proc) { break } + + # Read stdout + if (Test-Path $stdoutFile) { + $stdoutSize = (Get-Item $stdoutFile).Length + if ($stdoutSize -gt $lastStdoutPos) { + $content = Get-Content -Path $stdoutFile -Raw + if ($content) { + $newContent = $content.Substring($lastStdoutPos) + if ($newContent) { Write-Host $newContent -NoNewline } + } + $lastStdoutPos = $stdoutSize + } } + + # Read stderr + if (Test-Path $stderrFile) { + $stderrSize = (Get-Item $stderrFile).Length + if ($stderrSize -gt $lastStderrPos) { + $content = Get-Content -Path $stderrFile -Raw + if ($content) { + $newContent = $content.Substring($lastStderrPos) + if ($newContent) { Write-Host $newContent -NoNewline } + } + $lastStderrPos = $stderrSize + } + } + + Start-Sleep -Milliseconds 200 } - } + } -ArgumentList $stdoutFile, $stderrFile, $process.Id # Wait for process to complete $process.WaitForExit() - # Read any remaining output - if (Test-Path $stdoutFile) { - $content = Get-Content -Path $stdoutFile -Raw -ErrorAction SilentlyContinue - if ($content) { Write-Host $content } - } - if (Test-Path $stderrFile) { - $content = Get-Content -Path $stderrFile -Raw -ErrorAction SilentlyContinue - if ($content) { Write-Host $content } - } + # Wait for job to finish + $job | Wait-Job | Out-Null + Receive-Job -Job $job | Out-Null + Remove-Job -Job $job -Force -ErrorAction SilentlyContinue - # Get output for return + # Read final output $outputText = "" if (Test-Path $stdoutFile) { $outputText = Get-Content -Path $stdoutFile -Raw -ErrorAction SilentlyContinue } if (Test-Path $stderrFile) { $outputText += Get-Content -Path $stderrFile -Raw -ErrorAction SilentlyContinue } # Cleanup - Remove-Item $stdoutFile -ErrorAction SilentlyContinue - Remove-Item $stderrFile -ErrorAction SilentlyContinue - $fileStream.Close() + Remove-Item $stdoutFile -Force -ErrorAction SilentlyContinue + Remove-Item $stderrFile -Force -ErrorAction SilentlyContinue return @{ ExitCode = $process.ExitCode Output = $outputText } -} \ No newline at end of file +} + +# Run CHKDSK +Write-Host "==========================================" +Write-Host "Running CHKDSK with /R option..." +Write-Host "==========================================" + +try { + $result = Start-ProcessWithLiveOutput -FilePath "cmd" -Arguments "/c echo Y | chkdsk C: /R" -Name "chkdsk" + $ChkdskExitCode = $result.ExitCode + $outputText = $result.Output + + $ScriptResult.system_optimization.chkdsk.run = $true + $ScriptResult.system_optimization.chkdsk.exit_code = $ChkdskExitCode + + if ($outputText -match "will be checked on next boot|Chkdsk cannot run because the volume is in use") { + $ScriptResult.system_optimization.chkdsk.reboot_required = $true + } + + switch ($ChkdskExitCode) { + 0 { $ScriptResult.system_optimization.chkdsk.success = $true; $ScriptResult.system_optimization.chkdsk.message = "CHKDSK completed successfully." } + 1 { $ScriptResult.system_optimization.chkdsk.success = $true; $ScriptResult.system_optimization.chkdsk.message = "CHKDSK completed successfully. Errors corrected." } + 2 { $ScriptResult.system_optimization.chkdsk.success = $false; $ScriptResult.system_optimization.chkdsk.message = "CHKDSK did not run due to a parameter error." } + 3 { $ScriptResult.system_optimization.chkdsk.success = $true; $ScriptResult.system_optimization.chkdsk.reboot_required = $true; $ScriptResult.system_optimization.chkdsk.message = "CHKDSK completed with errors and requires a reboot." } + 4 { $ScriptResult.system_optimization.chkdsk.success = $false; $ScriptResult.system_optimization.chkdsk.message = "CHKDSK encountered errors but could not fix them." } + 5 { $ScriptResult.system_optimization.chkdsk.success = $false; $ScriptResult.system_optimization.chkdsk.reboot_required = $true; $ScriptResult.system_optimization.chkdsk.message = "CHKDSK found errors but requires a reboot." } + default { $ScriptResult.system_optimization.chkdsk.success = $false; $ScriptResult.system_optimization.chkdsk.message = "CHKDSK completed with exit code: $ChkdskExitCode" } + } + + Write-Host "CHKDSK exit code: $ChkdskExitCode" + +} catch { + $ErrorMsg = "Failed to run CHKDSK: $($_.Exception.Message)" + $ScriptResult.system_optimization.chkdsk.errors += $ErrorMsg + Write-Host $ErrorMsg +} + +# Run SFC +Write-Host "==========================================" +Write-Host "Running System File Checker (SFC /scannow)..." +Write-Host "==========================================" + +try { + $result = Start-ProcessWithLiveOutput -FilePath "sfc" -Arguments "/scannow" -Name "sfc" + $ExitCode = $result.ExitCode + $outputText = $result.Output + + $ScriptResult.system_optimization.sfc.run = $true + $ScriptResult.system_optimization.sfc.exit_code = $ExitCode + + switch ($ExitCode) { + 0 { $ScriptResult.system_optimization.sfc.success = $true; $ScriptResult.system_optimization.sfc.message = "SFC completed successfully."; $ScriptResult.system_optimization.sfc.files_repaired = 0 } + 1 { $ScriptResult.system_optimization.sfc.success = $true; $ScriptResult.system_optimization.sfc.message = "SFC completed successfully. Corrupted files were repaired."; $ScriptResult.system_optimization.sfc.files_repaired = 1 } + 2 { $ScriptResult.system_optimization.sfc.success = $false; $ScriptResult.system_optimization.sfc.message = "SFC could not perform the operation." } + 3 { $ScriptResult.system_optimization.sfc.success = $false; $ScriptResult.system_optimization.sfc.message = "SFC could not fix some files."; $ScriptResult.system_optimization.sfc.files_repaired = -1 } + -1 { $ScriptResult.system_optimization.sfc.success = $false; $ScriptResult.system_optimization.sfc.message = "SFC encountered an error." } + default { $ScriptResult.system_optimization.sfc.success = $false; $ScriptResult.system_optimization.sfc.message = "SFC completed with exit code: $ExitCode" } + } + + Write-Host "SFC exit code: $ExitCode" + +} catch { + $ErrorMsg = "Failed to run SFC: $($_.Exception.Message)" + $ScriptResult.system_optimization.sfc.errors += $ErrorMsg + Write-Host $ErrorMsg +} + +# Run DISM +Write-Host "==========================================" +Write-Host "Running DISM /Online /Cleanup-Image /RestoreHealth..." +Write-Host "==========================================" + +try { + $result = Start-ProcessWithLiveOutput -FilePath "DISM" -Arguments "/Online /Cleanup-Image /RestoreHealth" -Name "dism" + $ExitCode = $result.ExitCode + $outputText = $result.Output + + $ScriptResult.system_optimization.dism.run = $true + $ScriptResult.system_optimization.dism.exit_code = $ExitCode + + switch ($ExitCode) { + 0 { $ScriptResult.system_optimization.dism.success = $true; $ScriptResult.system_optimization.dism.component_repaired = $true; $ScriptResult.system_optimization.dism.message = "DISM completed successfully." } + 87 { $ScriptResult.system_optimization.dism.success = $false; $ScriptResult.system_optimization.dism.message = "DISM failed. A parameter was invalid." } + 3010 { $ScriptResult.system_optimization.dism.success = $true; $ScriptResult.system_optimization.dism.component_repaired = $true; $ScriptResult.system_optimization.dism.message = "DISM completed successfully. A reboot is required." } + default { + if ($ExitCode -ge 0 -and $ExitCode -le 100) { + $ScriptResult.system_optimization.dism.success = $true + $ScriptResult.system_optimization.dism.message = "DISM completed with exit code: $ExitCode" + } else { + $ScriptResult.system_optimization.dism.success = $false + $ScriptResult.system_optimization.dism.message = "DISM completed with exit code: $ExitCode" + } + } + } + + Write-Host "DISM exit code: $ExitCode" + +} catch { + $ErrorMsg = "Failed to run DISM: $($_.Exception.Message)" + $ScriptResult.system_optimization.dism.errors += $ErrorMsg + Write-Host $ErrorMsg +} + +# Output JSON result +Write-Host "==========================================" +Write-Host "System optimization section completed." +Write-Host "==========================================" +$result = $ScriptResult | ConvertTo-Json -Compress -Depth 10 +Write-Output $result \ No newline at end of file