import depuis ancien GitHub
This commit is contained in:
396
maintenance-ivanti/ExploitBox.ps1
Normal file
396
maintenance-ivanti/ExploitBox.ps1
Normal file
@@ -0,0 +1,396 @@
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
[System.Windows.Forms.Application]::EnableVisualStyles()
|
||||
|
||||
|
||||
# ==== Config SQL IVANTI ====
|
||||
$script:IvantiSqlInstance = "serveurIVANTI.domain.lan"
|
||||
$script:IvantiSqlDatabase = "LDMS123"
|
||||
|
||||
# -----------------------------
|
||||
# Form setup (compact & pro)
|
||||
# -----------------------------
|
||||
$form = New-Object System.Windows.Forms.Form
|
||||
$form.Text = 'Ops Maintenance Console'
|
||||
$form.Size = New-Object System.Drawing.Size(465,580)
|
||||
$form.StartPosition= 'CenterScreen'
|
||||
$form.FormBorderStyle = 'FixedDialog'
|
||||
$form.MaximizeBox = $false
|
||||
$form.MinimizeBox = $false
|
||||
$form.Font = New-Object System.Drawing.Font('Segoe UI', 9)
|
||||
|
||||
# Status strip (status text + progress)
|
||||
$statusStrip = New-Object System.Windows.Forms.StatusStrip
|
||||
$statusLabel = New-Object System.Windows.Forms.ToolStripStatusLabel
|
||||
$prog = New-Object System.Windows.Forms.ToolStripProgressBar
|
||||
$statusLabel.Spring = $true
|
||||
$prog.Minimum = 0; $prog.Maximum = 1; $prog.Step = 1; $prog.Value = 0
|
||||
[void]$statusStrip.Items.Add($statusLabel)
|
||||
[void]$statusStrip.Items.Add($prog)
|
||||
$form.Controls.Add($statusStrip)
|
||||
|
||||
function Set-Status([string]$text){ $statusLabel.Text = $text }
|
||||
|
||||
# -----------------------------
|
||||
# GroupBox: Task
|
||||
# -----------------------------
|
||||
$gbTask = New-Object System.Windows.Forms.GroupBox
|
||||
$gbTask.Text = 'Task'
|
||||
$gbTask.Location = New-Object System.Drawing.Point(10,8)
|
||||
$gbTask.Size = New-Object System.Drawing.Size(445,80)
|
||||
$form.Controls.Add($gbTask)
|
||||
|
||||
$lblSelect = New-Object System.Windows.Forms.Label
|
||||
$lblSelect.Text = 'Select:'
|
||||
$lblSelect.Location = New-Object System.Drawing.Point(12,30)
|
||||
$lblSelect.AutoSize = $true
|
||||
$gbTask.Controls.Add($lblSelect)
|
||||
|
||||
$comboBox = New-Object System.Windows.Forms.ComboBox
|
||||
$comboBox.Location = New-Object System.Drawing.Point(65,27)
|
||||
$comboBox.Size = New-Object System.Drawing.Size(230,24)
|
||||
$comboBox.DropDownStyle = 'DropDownList'
|
||||
$comboBox.Items.Add('IVANTI Core') | Out-Null
|
||||
$comboBox.Items.Add('IVANTI Console') | Out-Null
|
||||
$comboBox.Items.Add('WSUS') | Out-Null
|
||||
$gbTask.Controls.Add($comboBox)
|
||||
|
||||
$btnRun = New-Object System.Windows.Forms.Button
|
||||
$btnRun.Text = 'Run'
|
||||
$btnRun.Location = New-Object System.Drawing.Point(310,26)
|
||||
$btnRun.Size = New-Object System.Drawing.Size(110,26)
|
||||
$gbTask.Controls.Add($btnRun)
|
||||
$form.AcceptButton = $btnRun
|
||||
|
||||
# -----------------------------
|
||||
# GroupBox: Credentials
|
||||
# -----------------------------
|
||||
$gbCreds = New-Object System.Windows.Forms.GroupBox
|
||||
$gbCreds.Text = 'Credentials (IVANTI Core)'
|
||||
$gbCreds.Location = New-Object System.Drawing.Point(10,95)
|
||||
$gbCreds.Size = New-Object System.Drawing.Size(445,90)
|
||||
$form.Controls.Add($gbCreds)
|
||||
|
||||
$labelUser = New-Object System.Windows.Forms.Label
|
||||
$labelUser.Text = 'Username:'
|
||||
$labelUser.Location = New-Object System.Drawing.Point(12,27)
|
||||
$labelUser.AutoSize = $true
|
||||
$gbCreds.Controls.Add($labelUser)
|
||||
|
||||
$textBoxNom = New-Object System.Windows.Forms.TextBox
|
||||
$textBoxNom.Location = New-Object System.Drawing.Point(90,24)
|
||||
$textBoxNom.Size = New-Object System.Drawing.Size(150,24)
|
||||
$textBoxNom.Enabled = $false
|
||||
$gbCreds.Controls.Add($textBoxNom)
|
||||
|
||||
$labelPwd = New-Object System.Windows.Forms.Label
|
||||
$labelPwd.Text = 'Password:'
|
||||
$labelPwd.Location = New-Object System.Drawing.Point(12,57)
|
||||
$labelPwd.AutoSize = $true
|
||||
$gbCreds.Controls.Add($labelPwd)
|
||||
|
||||
$textBoxPassword = New-Object System.Windows.Forms.TextBox
|
||||
$textBoxPassword.Location = New-Object System.Drawing.Point(90,54)
|
||||
$textBoxPassword.Size = New-Object System.Drawing.Size(150,24)
|
||||
$textBoxPassword.UseSystemPasswordChar = $true
|
||||
$textBoxPassword.Enabled = $false
|
||||
$gbCreds.Controls.Add($textBoxPassword)
|
||||
|
||||
# -----------------------------
|
||||
# GroupBox: Output
|
||||
# -----------------------------
|
||||
$gbOut = New-Object System.Windows.Forms.GroupBox
|
||||
$gbOut.Text = 'Output'
|
||||
$gbOut.Location = New-Object System.Drawing.Point(10,190)
|
||||
$gbOut.Size = New-Object System.Drawing.Size(445,330)
|
||||
$form.Controls.Add($gbOut)
|
||||
|
||||
$outputBox = New-Object System.Windows.Forms.RichTextBox
|
||||
$outputBox.Location = New-Object System.Drawing.Point(12,22)
|
||||
$outputBox.Size = New-Object System.Drawing.Size(420,270)
|
||||
$outputBox.Font = New-Object System.Drawing.Font('Consolas', 9)
|
||||
$outputBox.ReadOnly = $true
|
||||
$outputBox.WordWrap = $false
|
||||
$gbOut.Controls.Add($outputBox)
|
||||
|
||||
$btnClear = New-Object System.Windows.Forms.Button
|
||||
$btnClear.Text= 'Clear'
|
||||
$btnClear.Location = New-Object System.Drawing.Point(322,295)
|
||||
$btnClear.Size = New-Object System.Drawing.Size(110,26)
|
||||
$gbOut.Controls.Add($btnClear)
|
||||
|
||||
# Helper: unified output
|
||||
function Append-Output([string]$text){
|
||||
foreach($line in ($text -split "(`r`n|`n|`r)")){
|
||||
if ([string]::IsNullOrWhiteSpace($line)) { continue }
|
||||
|
||||
$color = [System.Drawing.Color]::Black
|
||||
if ($line -match '\bOK\b') { $color = [System.Drawing.Color]::ForestGreen }
|
||||
elseif ($line -match '\bKO\b') { $color = [System.Drawing.Color]::Crimson }
|
||||
|
||||
$outputBox.SelectionStart = $outputBox.TextLength
|
||||
$outputBox.SelectionLength = 0
|
||||
$outputBox.SelectionColor = $color
|
||||
$outputBox.AppendText($line + [Environment]::NewLine)
|
||||
$outputBox.SelectionColor = $outputBox.ForeColor
|
||||
}
|
||||
$outputBox.ScrollToCaret()
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Logging helper
|
||||
# -----------------------------
|
||||
function Write-Log {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory=$True)][string]$Message,
|
||||
[Parameter(Mandatory=$False)]
|
||||
[string]$Path = $(if ($MyInvocation.MyCommand.Path) {
|
||||
$MyInvocation.MyCommand.Path -replace '\.ps1$', '.log'
|
||||
} else { "C:\Windows\Temp\exploitbox.log" })
|
||||
)
|
||||
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
||||
"$timestamp : $script:SelectedOption : $Message" | Out-File -FilePath $Path -Append
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Functions (business)
|
||||
# -----------------------------
|
||||
function Start-WSUS-Maintenance {
|
||||
Write-Host "[STEP] Start-WSUS-Maintenance"
|
||||
Set-Status "WSUS maintenance..."
|
||||
$Aff = ""
|
||||
$FileSQL = Join-Path $PSScriptRoot "WSUSMaintenance.sql"
|
||||
Write-Log -Message "----- Start-WSUS-Maintenance"
|
||||
$Instance = "\\.\pipe\MICROSOFT##WID\tsql\query"
|
||||
$Bdd = "SUSDB"
|
||||
try {
|
||||
Import-Module SqlServer -ErrorAction Stop
|
||||
Invoke-Sqlcmd -ServerInstance $Instance -Database $Bdd -InputFile $FileSQL -ErrorAction Stop -Verbose
|
||||
$Aff = "Maintenance OK"
|
||||
Write-Log -Message "WSUS maintenance OK"
|
||||
Write-Host "[DONE] WSUS maintenance OK"
|
||||
} catch {
|
||||
$Aff = "KO : $($_.Exception.Message)"
|
||||
Write-Log -Message "WSUS maintenance KO ($($_.Exception.Message))"
|
||||
Write-Host "[FAIL] WSUS maintenance KO $($_.Exception.Message)"
|
||||
}
|
||||
return ($Aff + "`r`n")
|
||||
}
|
||||
|
||||
function Start-IVANTI-Maintenance {
|
||||
Write-Host "[STEP] Start-IVANTI-Maintenance"
|
||||
Set-Status "IVANTI SQL maintenance..."
|
||||
$Aff = ""
|
||||
$FileSQL = Join-Path $PSScriptRoot "SQLMaintenance2022.sql"
|
||||
Write-Log -Message "----- Start-IVANTI-Maintenance"
|
||||
|
||||
$username = $textBoxNom.Text
|
||||
$password = $textBoxPassword.Text
|
||||
|
||||
try {
|
||||
Import-Module SqlServer -ErrorAction Stop
|
||||
Invoke-Sqlcmd -ServerInstance $script:IvantiSqlInstance `
|
||||
-Database $script:IvantiSqlDatabase `
|
||||
-Username $username `
|
||||
-Password $password `
|
||||
-InputFile $FileSQL `
|
||||
-ErrorAction Stop -Verbose
|
||||
$Aff = "Maintenance OK"
|
||||
Write-Log -Message "IVANTI SQL maintenance OK"
|
||||
Write-Host "[DONE] IVANTI SQL maintenance OK"
|
||||
} catch {
|
||||
$Aff = "KO : $($_.Exception.Message)"
|
||||
Write-Log -Message "IVANTI SQL maintenance KO ($($_.Exception.Message))"
|
||||
Write-Host "[FAIL] IVANTI SQL maintenance KO $($_.Exception.Message)"
|
||||
}
|
||||
return ($Aff + "`r`n")
|
||||
}
|
||||
|
||||
function Get-RebootStatus {
|
||||
Write-Host "[STEP] Get-RebootStatus"
|
||||
Set-Status "Checking reboot status..."
|
||||
$Aff = ""
|
||||
Write-Log -Message "----- Get-RebootStatus"
|
||||
$rebootRequired = $false
|
||||
$rebootPaths = @(
|
||||
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending',
|
||||
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired'
|
||||
)
|
||||
foreach ($p in $rebootPaths) { if (Test-Path $p) { $rebootRequired = $true; break } }
|
||||
if ($rebootRequired) {
|
||||
$Aff = "Reboot Needed (KO)"; Write-Log -Message $Aff; Write-Host "[INFO] Reboot Needed"
|
||||
} else {
|
||||
$Aff = "No Reboot Needed (OK)"; Write-Log -Message $Aff; Write-Host "[INFO] No Reboot Needed"
|
||||
}
|
||||
return ($Aff + "`r`n")
|
||||
}
|
||||
|
||||
function Cleanup-IIS {
|
||||
Write-Host "[STEP] Cleanup-IIS"
|
||||
Set-Status "Cleaning IIS logs..."
|
||||
$Aff = ""; Write-Log -Message "----- Cleanup-IIS"
|
||||
$LogPath = "C:\inetpub\logs\LogFiles\W3SVC1"
|
||||
if (-not (Test-Path $LogPath)) {
|
||||
$Aff = "PurgeIIS : OK (no log folder)`r`n"
|
||||
Write-Log -Message "PurgeIIS : OK (no log folder)"
|
||||
Write-Host "[DONE] Cleanup-IIS OK (no folder)"
|
||||
return $Aff
|
||||
}
|
||||
$maxDaystoKeep = -30
|
||||
$old = Get-ChildItem -Path $LogPath -File -Filter *.log | Where-Object LastWriteTime -lt ((Get-Date).AddDays($maxDaystoKeep))
|
||||
if ($old.Count -gt 0){ foreach ($i in $old){ Remove-Item $i.FullName -Force -Verbose } }
|
||||
$old = Get-ChildItem -Path $LogPath -File -Filter *.log | Where-Object LastWriteTime -lt ((Get-Date).AddDays($maxDaystoKeep))
|
||||
if ($old.Count -gt 0){ $Aff = "PurgeIIS : KO"; Write-Log -Message $Aff; Write-Host "[FAIL] Cleanup-IIS KO" }
|
||||
else { $Aff = "PurgeIIS : OK"; Write-Log -Message $Aff; Write-Host "[DONE] Cleanup-IIS OK" }
|
||||
return ($Aff + "`r`n")
|
||||
}
|
||||
|
||||
function Check-ldscan {
|
||||
Write-Host "[STEP] Check-ldscan"
|
||||
Set-Status "Checking ldscan folder..."
|
||||
$Aff = ""; Write-Log -Message "----- Check-ldscan"
|
||||
$path = "C:\Program Files\LANDesk\ManagementSuite\ldscan"
|
||||
$count = Get-ChildItem $path -File | Measure-Object | ForEach-Object { $_.Count }
|
||||
if ($count -gt 200) {
|
||||
$Aff = "Countldscan : KO"; Write-Log -Message $Aff; Write-Host "[FAIL] ldscan KO ($count files)"
|
||||
} else {
|
||||
$count = Get-ChildItem $path -Recurse -File | Measure-Object | ForEach-Object { $_.Count }
|
||||
if ($count -gt 200) { $Aff = "Countldscan : WARNING"; Write-Log -Message $Aff; Write-Host "[WARN] ldscan WARNING ($count files)" }
|
||||
else { $Aff = "Countldscan : OK"; Write-Log -Message $Aff; Write-Host "[DONE] ldscan OK ($count files)" }
|
||||
}
|
||||
return ($Aff + "`r`n")
|
||||
}
|
||||
|
||||
|
||||
# PSWindowsUpdate
|
||||
function Install-WindowsUpdate {
|
||||
Write-Host "[STEP] Install-WindowsUpdate (PSWindowsUpdate)"
|
||||
Set-Status "Installing Windows Updates..."
|
||||
$Aff = ""; Write-Log -Message "----- Install-WindowsUpdate (PSWindowsUpdate)"
|
||||
try {
|
||||
if (-not (Get-Module -ListAvailable -Name PSWindowsUpdate)) { throw "Module PSWindowsUpdate not found on this system." }
|
||||
Import-Module PSWindowsUpdate -ErrorAction Stop
|
||||
# Remove -WindowsUpdate to honor WSUS policy
|
||||
$updates = PSWindowsUpdate\Install-WindowsUpdate -WindowsUpdate -AcceptAll -IgnoreReboot -ErrorAction Stop
|
||||
if ($updates) {
|
||||
$Aff += ($updates | Select-Object KB, Title, Result | Format-Table -AutoSize | Out-String)
|
||||
$updates | ForEach-Object { Write-Log -Message ("{0} {1} -> {2}" -f $_.KB, $_.Title, $_.Result) } | Out-Null
|
||||
Write-Host "[DONE] Windows Update processed (OK)"
|
||||
} else {
|
||||
$Aff += "No applicable updates (OK).`r`n"; Write-Log -Message "No applicable updates."; Write-Host "[INFO] No applicable updates"
|
||||
}
|
||||
} catch {
|
||||
$Aff += "PSWindowsUpdate failed (KO): $($_.Exception.Message)`r`n"
|
||||
Write-Log -Message "PSWindowsUpdate failed (KO): $($_.Exception.Message)"
|
||||
Write-Host "[FAIL] Windows Update failed (KO): $($_.Exception.Message)"
|
||||
}
|
||||
return $Aff
|
||||
}
|
||||
|
||||
function Get-WSUS-PatchInGroups {
|
||||
Write-Host "[STEP] Get-WSUS-PatchInGroups"
|
||||
Set-Status "Building WSUS report..."
|
||||
$Aff = ""; Write-Log -Message "----- Get-WSUS-PatchInGroups"
|
||||
$MaxDaysReport = 35; $ListeKB=@()
|
||||
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | Out-Null
|
||||
$wsusServer = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer()
|
||||
$updates = $wsusServer.GetUpdates()
|
||||
$targetGroups = $wsusServer.GetComputerTargetGroups()
|
||||
foreach ($u in $updates){
|
||||
$approvals = $u.GetUpdateApprovals()
|
||||
foreach ($ap in $approvals){
|
||||
foreach ($tg in $targetGroups){
|
||||
if ($tg.Id -eq $ap.ComputerTargetGroupId) {
|
||||
$days = (New-TimeSpan -Start $ap.goLiveTime -End (Get-Date)).Days
|
||||
$title = $u.Title; $group = $tg.Name
|
||||
if ($days -lt $MaxDaysReport) {
|
||||
$match = 0
|
||||
if (($title -match "Windows 10") -and ($title -match "1809") -and ($title -match " x64")) { $match = 1 }
|
||||
if ($match -eq 1) {
|
||||
$ListeKB += [PSCustomObject]@{ KBTitre=$title; KBGroup=$group; KBChang=$days }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$ListeKB = $ListeKB | Sort-Object KBTitre, KBChang
|
||||
$maxTitle=120; $maxGroup=25; $maxDays=5; $prev="####"
|
||||
foreach ($KB in $ListeKB) {
|
||||
if ($KB.KBTitre -ne $prev) { $Aff += "`r`n"; $prev = $KB.KBTitre }
|
||||
$line = "{0,-$maxTitle} | {1,-$maxGroup} | {2,-$maxDays}" -f $KB.KBTitre, $KB.KBGroup, $KB.KBChang
|
||||
$Aff += "`r`n$line"; Write-Log -Message $line
|
||||
}
|
||||
Write-Host "[DONE] WSUS patch listing generated"
|
||||
return ($Aff + "`r`n")
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# Admin check
|
||||
# -----------------------------
|
||||
if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
|
||||
Start-Process PowerShell -ArgumentList "-File `"$($MyInvocation.MyCommand.Path)`"" -Verb RunAs
|
||||
exit
|
||||
}
|
||||
|
||||
# -----------------------------
|
||||
# UI events
|
||||
# -----------------------------
|
||||
$comboBox.Add_SelectedIndexChanged({
|
||||
$script:SelectedOption = $comboBox.SelectedItem
|
||||
if ($comboBox.SelectedItem -eq 'IVANTI Core') {
|
||||
$textBoxNom.Enabled = $true; $textBoxPassword.Enabled = $true; $textBoxNom.Text = "admindb"
|
||||
$gbCreds.Enabled = $true
|
||||
} else {
|
||||
$textBoxNom.Enabled = $false; $textBoxPassword.Enabled = $false; $gbCreds.Enabled = $false
|
||||
}
|
||||
})
|
||||
|
||||
$btnClear.Add_Click({ $outputBox.Clear(); Set-Status "Output cleared." })
|
||||
|
||||
$btnRun.Add_Click({
|
||||
$selectedOption = $comboBox.SelectedItem
|
||||
$script:SelectedOption = $selectedOption
|
||||
if (-not $selectedOption) { [System.Windows.Forms.MessageBox]::Show("Please select a task.", "Info", 'OK', 'Information') | Out-Null; return }
|
||||
|
||||
# progress config
|
||||
switch ($selectedOption) {
|
||||
'IVANTI Core' { $prog.Maximum = 6 }
|
||||
'IVANTI Console' { $prog.Maximum = 2 }
|
||||
'WSUS' { $prog.Maximum = 4 }
|
||||
}
|
||||
$prog.Value = 0
|
||||
|
||||
if ($selectedOption -eq "IVANTI Core") {
|
||||
Set-Status "IVANTI Core running..."
|
||||
Append-Output "----- Check ldscan"; Append-Output (Check-ldscan); $prog.PerformStep()
|
||||
Append-Output "----- Clean IIS Log"; Append-Output (Cleanup-IIS); $prog.PerformStep()
|
||||
Append-Output "----- Windows Update"; Append-Output (Install-WindowsUpdate); $prog.PerformStep()
|
||||
Append-Output "----- SQL maintenance"; Append-Output (Start-IVANTI-Maintenance);$prog.PerformStep()
|
||||
Append-Output "----- Get Reboot"; Append-Output (Get-RebootStatus); $prog.PerformStep()
|
||||
Set-Status "IVANTI Core: done."
|
||||
}
|
||||
|
||||
if ($selectedOption -eq "IVANTI Console") {
|
||||
Set-Status "IVANTI Console running..."
|
||||
Append-Output "----- Windows Update"; Append-Output (Install-WindowsUpdate); $prog.PerformStep()
|
||||
Append-Output "----- Get Reboot"; Append-Output (Get-RebootStatus); $prog.PerformStep()
|
||||
Set-Status "IVANTI Console: done."
|
||||
}
|
||||
|
||||
if ($selectedOption -eq "WSUS") {
|
||||
Set-Status "WSUS tasks running..."
|
||||
Append-Output "----- Windows Update"; Append-Output (Install-WindowsUpdate); $prog.PerformStep()
|
||||
Append-Output "----- Get Reboot"; Append-Output (Get-RebootStatus); $prog.PerformStep()
|
||||
Append-Output "----- SQL Maintenance"; Append-Output (Start-WSUS-Maintenance); $prog.PerformStep()
|
||||
Append-Output "----- Deploy"; Append-Output (Get-WSUS-PatchInGroups); $prog.PerformStep()
|
||||
Set-Status "WSUS: done."
|
||||
}
|
||||
})
|
||||
|
||||
# -----------------------------
|
||||
# Run UI
|
||||
# -----------------------------
|
||||
$form.ShowDialog() | Out-Null
|
||||
202
maintenance-ivanti/SQLMaintenance2022.sql
Normal file
202
maintenance-ivanti/SQLMaintenance2022.sql
Normal file
@@ -0,0 +1,202 @@
|
||||
-- Delete from patch history only needs to be run once if the proper thresholds have been set up in the product (Security Activity Tool - Gear icon)
|
||||
|
||||
DECLARE @DaysToKeepPatchHistory INTEGER;
|
||||
DECLARE @DaysToKeepAuditing INTEGER;
|
||||
DECLARE @DaysToKeepSecurityAction INTEGER;
|
||||
DECLARE @BatchSize INTEGER;
|
||||
DECLARE @Producthistory INTEGER;
|
||||
DECLARE @ChangedateHistory INTEGER;
|
||||
DECLARE @Loopsize INTEGER;
|
||||
DECLARE @RowThreshold INTEGER;
|
||||
|
||||
SET @DaysToKeepPatchHistory = 90; --Change 90 to how many days of patching history you want
|
||||
SET @DaysToKeepAuditing = 90; --Change 90 to how many days of auditing history you want
|
||||
SET @DaysToKeepSecurityAction = 90; --Change 90 to how many days of security actions from EPS you want
|
||||
SET @BatchSize = 100000; -- Change to number of records per delete you can make this larger or smaller depending on how much room you have for the transaction logs.
|
||||
SET @Producthistory = 180; -- This will clear out older entries from the ProductComputer table which houses MSI entries.
|
||||
SET @ChangedateHistory = 90; -- Clears out DBO.history these are the history values for an machine. On older databases the number of entries can cause the clean up statement to lock up.
|
||||
SET @RowThreshold = 500 --- This value handles the threshold for the delete statement, At 500 it will run the loop until the table has less than 500 records.
|
||||
WHILE EXISTS
|
||||
(
|
||||
SELECT *
|
||||
FROM [dbo].[PatchHistory]
|
||||
WHERE [ActionDate] < (GETDATE() - @DaysToKeepPatchHistory) HAVING count(*) > @RowThreshold
|
||||
)
|
||||
BEGIN
|
||||
DELETE TOP (@BatchSize)
|
||||
FROM [dbo].[PatchHistory]
|
||||
WHERE [ActionDate] < (GETDATE() - @DaysToKeepPatchHistory)
|
||||
END;
|
||||
|
||||
WHILE EXISTS
|
||||
(
|
||||
SELECT *
|
||||
FROM [dbo].[AuditInstance]
|
||||
WHERE [ModifiedDate] < (GETDATE() - @DaysToKeepAuditing) HAVING count(*) > @RowThreshold
|
||||
)
|
||||
BEGIN
|
||||
DELETE TOP (@BatchSize)
|
||||
FROM [dbo].[AuditInstance]
|
||||
WHERE [ModifiedDate] < (GETDATE() - @DaysToKeepAuditing)
|
||||
END;
|
||||
|
||||
WHILE EXISTS
|
||||
(
|
||||
SELECT *
|
||||
FROM [dbo].[History]
|
||||
WHERE [ChangeDate] < (GETDATE() - @ChangedateHistory) HAVING count(*) > @RowThreshold
|
||||
)
|
||||
BEGIN
|
||||
DELETE TOP (@BatchSize)
|
||||
FROM [dbo].[history]
|
||||
WHERE [ChangeDate] < (GETDATE() - @ChangedateHistory)
|
||||
END;
|
||||
|
||||
WHILE EXISTS
|
||||
(
|
||||
SELECT *
|
||||
FROM [dbo].[SecurityAction]
|
||||
WHERE [ActionDate] < (GETDATE() - @DaysToKeepSecurityAction) HAVING count(*) > @RowThreshold
|
||||
)
|
||||
BEGIN
|
||||
DELETE TOP (@BatchSize)
|
||||
FROM [dbo].[SecurityAction]
|
||||
WHERE [ActionDate] < (GETDATE() - @DaysToKeepSecurityAction)
|
||||
END;
|
||||
|
||||
WHILE EXISTS
|
||||
(
|
||||
SELECT *
|
||||
FROM [dbo].[ProductComputer]
|
||||
WHERE [Entrydate] < (GETDATE() - @Producthistory) HAVING count(*) > @RowThreshold
|
||||
)
|
||||
BEGIN
|
||||
DELETE TOP (@BatchSize)
|
||||
FROM [dbo].[ProductComputer]
|
||||
WHERE [Entrydate] < (GETDATE() - @Producthistory);
|
||||
END;
|
||||
--Removes FileInfoInstance Entries greater than 180 days. ONLY USE IN EMERGENCY SITUATIONS. Contact Ivanti support before utilizing this line.
|
||||
-- WHILE EXISTS
|
||||
-- (
|
||||
--SELECT *
|
||||
--FROM [dbo].[FileInfoInstance]
|
||||
-- WHERE [FileDate] < (GETDATE() - 180) HAVING count(*) > @RowThreshold
|
||||
--)
|
||||
--BEGIN
|
||||
--DELETE TOP (@BatchSize)
|
||||
--FROM [dbo].[FileInfoInstance]
|
||||
--WHERE [FileDate] < (GETDATE() - 180); --Removes FileInfoInstance Entries greater than 180 days. ONLY USE IN EMERGENCY SITUATIONS. Contact Ivanti support before utilizing this line.
|
||||
--END;
|
||||
|
||||
|
||||
-- Drop Temporary Tables Created by DA during Vendor Imports
|
||||
|
||||
DECLARE @cmd VARCHAR(4000);
|
||||
DECLARE [cmds] CURSOR FOR
|
||||
SELECT 'drop table [' + [TABLE_NAME] + ']'
|
||||
FROM [INFORMATION_SCHEMA].[TABLES]
|
||||
WHERE [TABLE_NAME] LIKE 'tmp_%';
|
||||
|
||||
OPEN [cmds];
|
||||
WHILE 1 = 1
|
||||
BEGIN
|
||||
FETCH [cmds]
|
||||
INTO @cmd;
|
||||
IF @@fetch_status != 0
|
||||
BREAK;
|
||||
EXEC (@cmd);
|
||||
END;
|
||||
CLOSE [cmds];
|
||||
DEALLOCATE [cmds];
|
||||
|
||||
-- Remove orphaned entries from FileInfo
|
||||
WHILE EXISTS
|
||||
(
|
||||
SELECT *
|
||||
FROM [FileInfo]
|
||||
WHERE [FileSize] <> 1
|
||||
AND [Version] <> 'X'
|
||||
AND [Discovered] = 1
|
||||
AND [FileInfo_Idn] IN
|
||||
(
|
||||
SELECT [a].[FileInfo_Idn]
|
||||
FROM [FileInfo] [a]
|
||||
LEFT OUTER JOIN [FileInfoInstance] [b] ON [a].[FileInfo_Idn] = [b].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [ProductFile] [c] ON [a].[FileInfo_Idn] = [c].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [FileConnections] [d] ON [a].[FileInfo_Idn] = [d].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [TrustedFileInfo] [e] ON [a].[FileInfo_Idn] = [e].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [SLM_ProductUsageFile] [f] ON [a].[FileInfo_Idn] = [f].[FileInfo_Idn]
|
||||
WHERE [b].[FileInfo_Idn] IS NULL
|
||||
AND [c].[FileInfo_Idn] IS NULL
|
||||
AND [d].[FileInfo_Idn] IS NULL
|
||||
AND [e].[FileInfo_Idn] IS NULL
|
||||
AND [f].[FileInfo_Idn] IS NULL
|
||||
) HAVING count(*) > @RowThreshold
|
||||
)
|
||||
BEGIN
|
||||
DELETE TOP (@BatchSize)
|
||||
FROM [FileInfo]
|
||||
WHERE [FileSize] <> 1
|
||||
AND [Version] <> 'X'
|
||||
AND [Discovered] = 1
|
||||
AND [FileInfo_Idn] IN
|
||||
(
|
||||
SELECT [a].[FileInfo_Idn]
|
||||
FROM [FileInfo] [a]
|
||||
LEFT OUTER JOIN [FileInfoInstance] [b] ON [a].[FileInfo_Idn] = [b].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [ProductFile] [c] ON [a].[FileInfo_Idn] = [c].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [FileConnections] [d] ON [a].[FileInfo_Idn] = [d].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [TrustedFileInfo] [e] ON [a].[FileInfo_Idn] = [e].[FileInfo_Idn]
|
||||
LEFT OUTER JOIN [SLM_ProductUsageFile] [f] ON [a].[FileInfo_Idn] = [f].[FileInfo_Idn]
|
||||
WHERE [b].[FileInfo_Idn] IS NULL
|
||||
AND [c].[FileInfo_Idn] IS NULL
|
||||
AND [d].[FileInfo_Idn] IS NULL
|
||||
AND [e].[FileInfo_Idn] IS NULL
|
||||
AND [f].[FileInfo_Idn] IS NULL
|
||||
);
|
||||
END;
|
||||
|
||||
--- Clears Unkown items list
|
||||
|
||||
TRUNCATE TABLE [METABLOCKED];
|
||||
|
||||
--- Changes null device id's to unassigned
|
||||
|
||||
|
||||
UPDATE [Computer]
|
||||
SET [DeviceId] = 'Unassigned'
|
||||
WHERE [DeviceId] IS NULL;
|
||||
|
||||
|
||||
-- Rebuild fragmented indexes
|
||||
|
||||
DECLARE @TableName VARCHAR(255);
|
||||
DECLARE @sql NVARCHAR(500);
|
||||
DECLARE @fillfactor INT;
|
||||
SET @fillfactor = 80;
|
||||
DECLARE [TableCursor] CURSOR FOR
|
||||
SELECT OBJECT_SCHEMA_NAME([object_id]) + '.' + [name] AS [TableName]
|
||||
FROM [sys].[tables];
|
||||
OPEN [TableCursor];
|
||||
FETCH NEXT FROM [TableCursor]
|
||||
INTO @TableName;
|
||||
WHILE @@FETCH_STATUS = 0
|
||||
BEGIN
|
||||
SET @sql
|
||||
= N'ALTER INDEX ALL ON ' + @TableName + N' REBUILD WITH (FILLFACTOR = ' + CONVERT(VARCHAR(3), @fillfactor)
|
||||
+ N')';
|
||||
EXEC (@sql);
|
||||
FETCH NEXT FROM [TableCursor]
|
||||
INTO @TableName;
|
||||
END;
|
||||
CLOSE [TableCursor];
|
||||
DEALLOCATE [TableCursor];
|
||||
GO
|
||||
|
||||
--Check for consistency errors
|
||||
|
||||
DBCC CHECKDB;
|
||||
|
||||
--Run checkpoint to allow logs to be freed
|
||||
|
||||
CHECKPOINT;
|
||||
118
maintenance-ivanti/WSUSMaintenance.sql
Normal file
118
maintenance-ivanti/WSUSMaintenance.sql
Normal file
@@ -0,0 +1,118 @@
|
||||
USE SUSDB;
|
||||
GO
|
||||
SET NOCOUNT ON;
|
||||
|
||||
-- Rebuild or reorganize indexes based on their fragmentation levels
|
||||
DECLARE @work_to_do TABLE (
|
||||
objectid int
|
||||
, indexid int
|
||||
, pagedensity float
|
||||
, fragmentation float
|
||||
, numrows int
|
||||
)
|
||||
|
||||
DECLARE @objectid int;
|
||||
DECLARE @indexid int;
|
||||
DECLARE @schemaname nvarchar(130);
|
||||
DECLARE @objectname nvarchar(130);
|
||||
DECLARE @indexname nvarchar(130);
|
||||
DECLARE @numrows int
|
||||
DECLARE @density float;
|
||||
DECLARE @fragmentation float;
|
||||
DECLARE @command nvarchar(4000);
|
||||
DECLARE @fillfactorset bit
|
||||
DECLARE @numpages int
|
||||
|
||||
-- Select indexes that need to be defragmented based on the following
|
||||
-- * Page density is low
|
||||
-- * External fragmentation is high in relation to index size
|
||||
PRINT 'Estimating fragmentation: Begin. ' + convert(nvarchar, getdate(), 121)
|
||||
INSERT @work_to_do
|
||||
SELECT
|
||||
f.object_id
|
||||
, index_id
|
||||
, avg_page_space_used_in_percent
|
||||
, avg_fragmentation_in_percent
|
||||
, record_count
|
||||
FROM
|
||||
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'SAMPLED') AS f
|
||||
WHERE
|
||||
(f.avg_page_space_used_in_percent < 85.0 and f.avg_page_space_used_in_percent/100.0 * page_count < page_count - 1)
|
||||
or (f.page_count > 50 and f.avg_fragmentation_in_percent > 15.0)
|
||||
or (f.page_count > 10 and f.avg_fragmentation_in_percent > 80.0)
|
||||
|
||||
PRINT 'Number of indexes to rebuild: ' + cast(@@ROWCOUNT as nvarchar(20))
|
||||
|
||||
PRINT 'Estimating fragmentation: End. ' + convert(nvarchar, getdate(), 121)
|
||||
|
||||
SELECT @numpages = sum(ps.used_page_count)
|
||||
FROM
|
||||
@work_to_do AS fi
|
||||
INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id
|
||||
INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id
|
||||
|
||||
-- Declare the cursor for the list of indexes to be processed.
|
||||
DECLARE curIndexes CURSOR FOR SELECT * FROM @work_to_do
|
||||
|
||||
-- Open the cursor.
|
||||
OPEN curIndexes
|
||||
|
||||
-- Loop through the indexes
|
||||
WHILE (1=1)
|
||||
BEGIN
|
||||
FETCH NEXT FROM curIndexes
|
||||
INTO @objectid, @indexid, @density, @fragmentation, @numrows;
|
||||
IF @@FETCH_STATUS < 0 BREAK;
|
||||
|
||||
SELECT
|
||||
@objectname = QUOTENAME(o.name)
|
||||
, @schemaname = QUOTENAME(s.name)
|
||||
FROM
|
||||
sys.objects AS o
|
||||
INNER JOIN sys.schemas as s ON s.schema_id = o.schema_id
|
||||
WHERE
|
||||
o.object_id = @objectid;
|
||||
|
||||
SELECT
|
||||
@indexname = QUOTENAME(name)
|
||||
, @fillfactorset = CASE fill_factor WHEN 0 THEN 0 ELSE 1 END
|
||||
FROM
|
||||
sys.indexes
|
||||
WHERE
|
||||
object_id = @objectid AND index_id = @indexid;
|
||||
|
||||
IF ((@density BETWEEN 75.0 AND 85.0) AND @fillfactorset = 1) OR (@fragmentation < 30.0)
|
||||
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
|
||||
ELSE IF @numrows >= 5000 AND @fillfactorset = 0
|
||||
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD WITH (FILLFACTOR = 90)';
|
||||
ELSE
|
||||
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
|
||||
PRINT convert(nvarchar, getdate(), 121) + N' Executing: ' + @command;
|
||||
EXEC (@command);
|
||||
PRINT convert(nvarchar, getdate(), 121) + N' Done.';
|
||||
END
|
||||
|
||||
-- Close and deallocate the cursor.
|
||||
CLOSE curIndexes;
|
||||
DEALLOCATE curIndexes;
|
||||
|
||||
|
||||
IF EXISTS (SELECT * FROM @work_to_do)
|
||||
BEGIN
|
||||
PRINT 'Estimated number of pages in fragmented indexes: ' + cast(@numpages as nvarchar(20))
|
||||
SELECT @numpages = @numpages - sum(ps.used_page_count)
|
||||
FROM
|
||||
@work_to_do AS fi
|
||||
INNER JOIN sys.indexes AS i ON fi.objectid = i.object_id and fi.indexid = i.index_id
|
||||
INNER JOIN sys.dm_db_partition_stats AS ps on i.object_id = ps.object_id and i.index_id = ps.index_id
|
||||
|
||||
PRINT 'Estimated number of pages freed: ' + cast(@numpages as nvarchar(20))
|
||||
END
|
||||
GO
|
||||
|
||||
|
||||
--Update all statistics
|
||||
PRINT 'Updating all statistics.' + convert(nvarchar, getdate(), 121)
|
||||
EXEC sp_updatestats
|
||||
PRINT 'Done updating statistics.' + convert(nvarchar, getdate(), 121)
|
||||
GO
|
||||
1
maintenance-ivanti/main.cmd
Normal file
1
maintenance-ivanti/main.cmd
Normal file
@@ -0,0 +1 @@
|
||||
powershell -file "C:\Scripts\Exploitation\ExploitBox.ps1"
|
||||
57
maintenance-ivanti/readme.md
Normal file
57
maintenance-ivanti/readme.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# ExploitBox
|
||||
|
||||
## PowerShell GUI for Maintenance Tasks (Ivanti / WSUS)
|
||||
|
||||
This project provides a PowerShell-based GUI tool to assist with routine maintenance operations, specifically targeting Ivanti and WSUS environments.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
Edit the following variables at the top of the `ExploitBox.ps1` script:
|
||||
|
||||
```powershell
|
||||
# ==== Global Config ====
|
||||
$script:IvantiSqlInstance = "serveurIVANTI.domain.lan"
|
||||
$script:IvantiSqlDatabase = "LDMS123"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Installation
|
||||
|
||||
Before running the script, install the required PowerShell modules:
|
||||
|
||||
```powershell
|
||||
Install-Module SqlServer -Scope CurrentUser -Force
|
||||
Install-Module PSWindowsUpdate -Scope CurrentUser -Force -AllowClobber
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ▶️ Execution
|
||||
|
||||
Unblock the script and execute it using PowerShell:
|
||||
|
||||
```powershell
|
||||
Unblock-File .\ExploitBox.ps1
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\ExploitBox.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Features
|
||||
|
||||
- GUI interface for easier operations
|
||||
- Connects to Ivanti SQL database
|
||||
- Uses `PSWindowsUpdate` for patch management
|
||||
- Modular and easily configurable
|
||||
|
||||
---
|
||||
|
||||
## 📸 Screenshots
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
BIN
maintenance-ivanti/readme.png
Normal file
BIN
maintenance-ivanti/readme.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Reference in New Issue
Block a user