-
This commit is contained in:
parent
21ac65f282
commit
66188144d2
1 changed files with 116 additions and 94 deletions
202
cleanup.ps1
202
cleanup.ps1
|
|
@ -18,7 +18,7 @@ $LogDirectory = "C:\Quest"
|
||||||
$LogDate = Get-Date -Format "yyyy-MM-dd"
|
$LogDate = Get-Date -Format "yyyy-MM-dd"
|
||||||
$RandomSuffix = Get-Random -Minimum 1000 -Maximum 9999
|
$RandomSuffix = Get-Random -Minimum 1000 -Maximum 9999
|
||||||
$LogFile = Join-Path $LogDirectory "cleanup-${LogDate}-${RandomSuffix}.log"
|
$LogFile = Join-Path $LogDirectory "cleanup-${LogDate}-${RandomSuffix}.log"
|
||||||
$WebhookUrl = "https://n8n.questcomputers.be/webhook/99077b7d-140f-477e-9241-2b9581ddaf34"
|
$WebhookUrl = "https://n8n.questcomputers.be/webhook-test/99077b7d-140f-477e-9241-2b9581ddaf34"
|
||||||
$ScriptStartTime = Get-Date
|
$ScriptStartTime = Get-Date
|
||||||
|
|
||||||
# Configuration - Timeout for winget (in seconds)
|
# Configuration - Timeout for winget (in seconds)
|
||||||
|
|
@ -32,7 +32,7 @@ if (-not (Test-Path $LogDirectory)) {
|
||||||
# Initialize structured data object
|
# Initialize structured data object
|
||||||
$ScriptResult = [ordered]@{
|
$ScriptResult = [ordered]@{
|
||||||
"script_name" = "System Cleanup Script"
|
"script_name" = "System Cleanup Script"
|
||||||
"version" = "1.1"
|
"version" = "1.2"
|
||||||
"execution_info" = @{
|
"execution_info" = @{
|
||||||
"started_at" = $ScriptStartTime.ToString("yyyy-MM-dd HH:mm:ss")
|
"started_at" = $ScriptStartTime.ToString("yyyy-MM-dd HH:mm:ss")
|
||||||
"computer_name" = $env:COMPUTERNAME
|
"computer_name" = $env:COMPUTERNAME
|
||||||
|
|
@ -338,7 +338,6 @@ if ($ScriptResult.app_updates.winget_available) {
|
||||||
|
|
||||||
# Create temporary files for output
|
# Create temporary files for output
|
||||||
$WingetOutputFile = Join-Path $LogDirectory "winget_output.txt"
|
$WingetOutputFile = Join-Path $LogDirectory "winget_output.txt"
|
||||||
$WingetErrorFile = Join-Path $LogDirectory "winget_error.txt"
|
|
||||||
|
|
||||||
# Start winget process with timeout
|
# Start winget process with timeout
|
||||||
$wingetProcess = Start-Process -FilePath "winget" -ArgumentList "upgrade --all --silent --accept-package-agreements --accept-source-agreements" -NoNewWindow -Wait -PassThru -ErrorAction Stop
|
$wingetProcess = Start-Process -FilePath "winget" -ArgumentList "upgrade --all --silent --accept-package-agreements --accept-source-agreements" -NoNewWindow -Wait -PassThru -ErrorAction Stop
|
||||||
|
|
@ -349,9 +348,13 @@ if ($ScriptResult.app_updates.winget_available) {
|
||||||
Write-Log "Winget exit code: $WingetExitCode" -Level "INFO"
|
Write-Log "Winget exit code: $WingetExitCode" -Level "INFO"
|
||||||
Write-Log "Winget duration: $($WingetDuration.ToString('F2')) seconds" -Level "INFO"
|
Write-Log "Winget duration: $($WingetDuration.ToString('F2')) seconds" -Level "INFO"
|
||||||
|
|
||||||
# Read output if available
|
# Parse winget output from log file if available
|
||||||
if (Test-Path $WingetOutputFile) {
|
$wingetOutput = Get-Content $LogFile | Select-String -Pattern "winget|Winget|Upgrading|Upgraded" -Context 2 | Out-String
|
||||||
$wingetOutput = Get-Content $WingetOutputFile -Raw
|
$wingetOutput | Out-File -FilePath $LogFile -Append -Encoding UTF8
|
||||||
|
|
||||||
|
# Alternative: Try to capture output directly
|
||||||
|
try {
|
||||||
|
$wingetOutput = winget upgrade --all --silent 2>&1 | Out-String
|
||||||
$wingetOutput | Out-File -FilePath $LogFile -Append -Encoding UTF8
|
$wingetOutput | Out-File -FilePath $LogFile -Append -Encoding UTF8
|
||||||
|
|
||||||
# Parse winget output to extract updated apps
|
# Parse winget output to extract updated apps
|
||||||
|
|
@ -374,16 +377,14 @@ if ($ScriptResult.app_updates.winget_available) {
|
||||||
|
|
||||||
$ScriptResult.app_updates.apps_updated = $AppsUpdated
|
$ScriptResult.app_updates.apps_updated = $AppsUpdated
|
||||||
$ScriptResult.app_updates.apps_checked = $AppsUpdated.Count
|
$ScriptResult.app_updates.apps_checked = $AppsUpdated.Count
|
||||||
|
} catch {
|
||||||
# Clean up temporary files
|
Write-Log "Could not capture winget output: $($_.Exception.Message)" -Level "WARNING"
|
||||||
Remove-Item $WingetOutputFile -ErrorAction SilentlyContinue
|
|
||||||
Remove-Item $WingetErrorFile -ErrorAction SilentlyContinue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($AppsUpdated.Count -gt 0) {
|
if ($AppsUpdated.Count -gt 0) {
|
||||||
Write-Log "Application updates completed. Updated $($AppsUpdated.Count) application(s): $($AppsUpdated -join ', ')" -Level "INFO"
|
Write-Log "Application updates completed. Updated $($AppsUpdated.Count) application(s): $($AppsUpdated -join ', ')" -Level "INFO"
|
||||||
} else {
|
} else {
|
||||||
Write-Log "Application updates completed. All applications are up to date." -Level "INFO"
|
Write-Log "Application updates completed. All applications are up to date or winget output could not be parsed." -Level "INFO"
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
# Check if it's a timeout
|
# Check if it's a timeout
|
||||||
|
|
@ -405,112 +406,133 @@ Write-Log "Application updates section completed." -Level "INFO"
|
||||||
"" | Out-File -FilePath $LogFile -Append -Encoding UTF8
|
"" | Out-File -FilePath $LogFile -Append -Encoding UTF8
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------
|
||||||
# Updating Windows
|
# Updating Windows (using Windows Update API directly)
|
||||||
# --------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------
|
||||||
Write-Log "================================================================================" -Level "INFO"
|
Write-Log "================================================================================" -Level "INFO"
|
||||||
Write-Log "SECTION: Windows Updates" -Level "INFO"
|
Write-Log "SECTION: Windows Updates" -Level "INFO"
|
||||||
Write-Log "================================================================================" -Level "INFO"
|
Write-Log "================================================================================" -Level "INFO"
|
||||||
|
|
||||||
# Install NuGet provider
|
# Load Windows Update COM object
|
||||||
Write-Log "Installing NuGet package provider..." -Level "INFO"
|
Write-Log "Initializing Windows Update service..." -Level "INFO"
|
||||||
try {
|
try {
|
||||||
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -ErrorAction Stop | Out-Null
|
$UpdateSession = New-Object -ComObject "Microsoft.Update.Session"
|
||||||
$ScriptResult.windows_updates.nuget_installed = $true
|
$UpdateSearcher = $UpdateSession.CreateUpdateSearcher()
|
||||||
Write-Log "NuGet package provider installed successfully." -Level "INFO"
|
$UpdateDownloader = $UpdateSession.CreateUpdateDownloader()
|
||||||
} catch {
|
$UpdateInstaller = $UpdateSession.CreateUpdateInstaller()
|
||||||
Write-Log "Failed to install NuGet: $($_.Exception.Message)" -Level "ERROR"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Install PSWindowsUpdate module
|
Write-Log "Searching for available Windows updates..." -Level "INFO"
|
||||||
Write-Log "Installing PSWindowsUpdate module..." -Level "INFO"
|
|
||||||
try {
|
|
||||||
Install-Module PSWindowsUpdate -Force -AllowClobber -ErrorAction Stop | Out-Null
|
|
||||||
$ScriptResult.windows_updates.pswindowsupdate_installed = $true
|
|
||||||
Write-Log "PSWindowsUpdate module installed successfully." -Level "INFO"
|
|
||||||
} catch {
|
|
||||||
Write-Log "Failed to install PSWindowsUpdate: $($_.Exception.Message)" -Level "ERROR"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Import PSWindowsUpdate module
|
# Search for updates
|
||||||
if ($ScriptResult.windows_updates.pswindowsupdate_installed) {
|
$SearchResult = $UpdateSearcher.Search("IsInstalled=0 and Type='Software'")
|
||||||
try {
|
$AvailableUpdates = $SearchResult.Updates
|
||||||
Write-Log "Importing PSWindowsUpdate module..." -Level "INFO"
|
|
||||||
Import-Module PSWindowsUpdate -ErrorAction Stop
|
|
||||||
Write-Log "PSWindowsUpdate module imported successfully." -Level "INFO"
|
|
||||||
} catch {
|
|
||||||
Write-Log "Failed to import PSWindowsUpdate: $($_.Exception.Message)" -Level "ERROR"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check for and install Windows updates
|
$ScriptResult.windows_updates.updates_available = $AvailableUpdates.Count
|
||||||
if ($ScriptResult.windows_updates.pswindowsupdate_installed) {
|
Write-Log "Found $($AvailableUpdates.Count) Windows update(s)." -Level "INFO"
|
||||||
try {
|
|
||||||
Write-Log "Checking for and installing Windows updates..." -Level "INFO"
|
|
||||||
|
|
||||||
# Run Windows update check and install in one command
|
if ($AvailableUpdates.Count -gt 0) {
|
||||||
$UpdateOutput = Get-WindowsUpdate -AcceptAll -Install -IgnoreUser -IgnoreReboot -ErrorAction Stop 2>&1 | Out-String
|
# Prepare download collection
|
||||||
$UpdateOutput | Out-File -FilePath $LogFile -Append -Encoding UTF8
|
$UpdatesToDownload = New-Object -ComObject "Microsoft.Update.UpdateColl"
|
||||||
|
|
||||||
# Parse the output to extract KB numbers and titles
|
foreach ($Update in $AvailableUpdates) {
|
||||||
$UpdateLines = $UpdateOutput -split "`n"
|
$UpdateInfo = @{
|
||||||
$UpdatesFound = $false
|
"kb" = if ($Update.KBArticleIDs.Count -gt 0) { "KB$($Update.KBArticleIDs[0])" } else { "Unknown" }
|
||||||
$UpdatesInstalled = @()
|
"title" = $Update.Title
|
||||||
|
"description" = $Update.Description
|
||||||
foreach ($line in $UpdateLines) {
|
"size_mb" = [math]::Round($Update.MaxDownloadSize / 1MB, 2)
|
||||||
# Look for KB pattern in the output
|
"is_downloaded" = $false
|
||||||
if ($line -match "KB\d+" -or $line -match "Update for|Security Update|Cumulative Update") {
|
"reboot_required" = ($Update.InstallationBehavior.RebootBehavior -ne "NeverRequiresReboot")
|
||||||
$UpdatesFound = $true
|
|
||||||
|
|
||||||
# Extract KB number
|
|
||||||
$kbMatch = [regex]::Match($line, 'KB\d+')
|
|
||||||
$kb = if ($kbMatch.Success) { $kbMatch.Value } else { "Unknown" }
|
|
||||||
|
|
||||||
# Extract title (remove KB number and extra spaces)
|
|
||||||
$title = $line -replace 'KB\d+\s*' -replace '\s+' -replace '^\s*|\s*$' -trim
|
|
||||||
|
|
||||||
if ($title -and $title.Length -gt 3) {
|
|
||||||
$UpdateInfo = @{
|
|
||||||
"kb" = $kb
|
|
||||||
"title" = $title
|
|
||||||
"description" = ""
|
|
||||||
"size_mb" = 0
|
|
||||||
"is_downloaded" = $true
|
|
||||||
"reboot_required" = $false
|
|
||||||
}
|
|
||||||
$UpdatesInstalled += $UpdateInfo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
$ScriptResult.windows_updates.updates_installed += $UpdateInfo
|
||||||
|
|
||||||
|
# Add to download collection
|
||||||
|
$UpdatesToDownload.Add($Update) | Out-Null
|
||||||
}
|
}
|
||||||
|
|
||||||
$ScriptResult.windows_updates.updates_installed = $UpdatesInstalled
|
# Download updates
|
||||||
$ScriptResult.windows_updates.updates_available = $UpdatesInstalled.Count
|
Write-Log "Downloading $($AvailableUpdates.Count) update(s)..." -Level "INFO"
|
||||||
|
$UpdateDownloader.Updates = $UpdatesToDownload
|
||||||
|
$DownloadResult = $UpdateDownloader.Download()
|
||||||
|
|
||||||
# Check if reboot is required from output
|
# Check download result
|
||||||
if ($UpdateOutput -match "reboot|Reboot|restart|restart your computer") {
|
$DownloadResultCode = switch ($DownloadResult.ResultCode) {
|
||||||
$ScriptResult.windows_updates.reboot_required = $true
|
0 { "NotStarted" }
|
||||||
|
1 { "InProgress" }
|
||||||
|
2 { "Succeeded" }
|
||||||
|
3 { "SucceededWithErrors" }
|
||||||
|
4 { "Failed" }
|
||||||
|
5 { "Aborted" }
|
||||||
|
default { "Unknown" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Log "Download result: $DownloadResultCode" -Level "INFO"
|
||||||
|
|
||||||
|
if ($DownloadResult.ResultCode -in @(2, 3)) {
|
||||||
|
# Prepare installation collection
|
||||||
|
$UpdatesToInstall = New-Object -ComObject "Microsoft.Update.UpdateColl"
|
||||||
|
|
||||||
|
foreach ($Update in $AvailableUpdates) {
|
||||||
|
if ($Update.IsDownloaded) {
|
||||||
|
$UpdatesToInstall.Add($Update) | Out-Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install updates
|
||||||
|
Write-Log "Installing $($UpdatesToInstall.Count) update(s)..." -Level "INFO"
|
||||||
|
$UpdateInstaller.Updates = $UpdatesToInstall
|
||||||
|
$InstallResult = $UpdateInstaller.Install()
|
||||||
|
|
||||||
|
# Check installation result
|
||||||
|
$InstallResultCode = switch ($InstallResult.ResultCode) {
|
||||||
|
0 { "NotStarted" }
|
||||||
|
1 { "InProgress" }
|
||||||
|
2 { "Succeeded" }
|
||||||
|
3 { "SucceededWithErrors" }
|
||||||
|
4 { "Failed" }
|
||||||
|
5 { "Aborted" }
|
||||||
|
default { "Unknown" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Log "Installation result: $InstallResultCode" -Level "INFO"
|
||||||
|
|
||||||
|
# Check if reboot is required
|
||||||
|
if ($InstallResult.RebootRequired) {
|
||||||
|
$ScriptResult.windows_updates.reboot_required = $true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update status for downloaded updates
|
||||||
|
for ($i = 0; $i -lt $ScriptResult.windows_updates.updates_installed.Count; $i++) {
|
||||||
|
$ScriptResult.windows_updates.updates_installed[$i].is_downloaded = $true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Log "Windows updates installation completed." -Level "INFO"
|
Write-Log "Windows updates installation completed." -Level "INFO"
|
||||||
|
|
||||||
if ($UpdatesInstalled.Count -gt 0) {
|
if ($ScriptResult.windows_updates.updates_installed.Count -gt 0) {
|
||||||
Write-Log "Installed $($UpdatesInstalled.Count) update(s):" -Level "INFO"
|
Write-Log "Installed $($ScriptResult.windows_updates.updates_installed.Count) update(s):" -Level "INFO"
|
||||||
foreach ($update in $UpdatesInstalled) {
|
foreach ($update in $ScriptResult.windows_updates.updates_installed) {
|
||||||
Write-Log " - $($update.kb): $($update.title)" -Level "INFO"
|
Write-Log " - $($update.kb): $($update.title)" -Level "INFO"
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Write-Log "No Windows updates were needed or found." -Level "INFO"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ScriptResult.windows_updates.reboot_required) {
|
if ($ScriptResult.windows_updates.reboot_required) {
|
||||||
Write-Log "A system reboot is required to complete the updates." -Level "WARNING"
|
Write-Log "A system reboot is required to complete the updates." -Level "WARNING"
|
||||||
}
|
}
|
||||||
} catch {
|
} else {
|
||||||
$ErrorMsg = "Failed to install Windows updates: $($_.Exception.Message)"
|
Write-Log "No Windows updates were needed." -Level "INFO"
|
||||||
$ScriptResult.windows_updates.errors += $ErrorMsg
|
|
||||||
Write-Log $ErrorMsg -Level "ERROR"
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Write-Log "PSWindowsUpdate not installed. Skipping Windows updates." -Level "INFO"
|
# Clean up COM objects
|
||||||
|
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($UpdateInstaller) | Out-Null
|
||||||
|
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($UpdateDownloader) | Out-Null
|
||||||
|
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($UpdateSearcher) | Out-Null
|
||||||
|
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($UpdateSession) | Out-Null
|
||||||
|
[System.GC]::Collect()
|
||||||
|
[System.GC]::WaitForPendingFinalizers()
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
$ErrorMsg = "Failed to install Windows updates: $($_.Exception.Message)"
|
||||||
|
$ScriptResult.windows_updates.errors += $ErrorMsg
|
||||||
|
Write-Log $ErrorMsg -Level "ERROR"
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Log "Windows updates section completed." -Level "INFO"
|
Write-Log "Windows updates section completed." -Level "INFO"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue