DROP AUTO STATS RECURRING

USER GUIDE

INSTALL VIDEO

POWER SHELL SCRIPT


# DropAutoStats_SSPI.ps1
# Production script using System.Data.SqlClient with SSPI, archiving, logging, event logs, STRING_AGG fix, and explicit USE POS

$BaseDir = "C:\POS_Logs\DropAutoStats"
$LogFile = "$BaseDir\DropAutoStats.log"
$ErrorLog = "$BaseDir\DropAutoStats_Error.log"
$ArchiveDir = "$BaseDir\Archive"
$EventSource = "DropAutoStatsScript"
$EventLog = "Application"
$Server = "."
$Database = "POS"

if (-not (Test-Path $BaseDir)) { New-Item -ItemType Directory -Path $BaseDir | Out-Null }
if (-not (Test-Path $ArchiveDir)) { New-Item -ItemType Directory -Path $ArchiveDir | Out-Null }
if (-not [System.Diagnostics.EventLog]::SourceExists($EventSource)) {
    New-EventLog -LogName $EventLog -Source $EventSource
}

$Timestamp = Get-Date -Format "yyyy-MM-dd_HHmm"
$ArchiveBase = "$ArchiveDir\DropAutoStats_$Timestamp"
$ArchiveFile = "$ArchiveBase.log"
$Counter = 1
while (Test-Path $ArchiveFile) {
    $ArchiveFile = "$ArchiveBase" + "_$Counter.log"
    $Counter++
}
try {
    if (Test-Path $LogFile) {
        Move-Item $LogFile $ArchiveFile -ErrorAction Stop
        Compress-Archive -Path $ArchiveFile -DestinationPath "$ArchiveFile.zip" -ErrorAction Stop
        Remove-Item $ArchiveFile -ErrorAction Stop
    }
} catch {
    Write-EventLog -LogName $EventLog -Source $EventSource -EntryType Error -EventId 1004 -Message "Failed to archive log file: $_"
}
"==================================================" | Out-File -FilePath $LogFile -Append
"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] Running DropAutoStats script" | Out-File -FilePath $LogFile -Append
Write-EventLog -LogName $EventLog -Source $EventSource -EntryType Information -EventId 1000 -Message "DropAutoStats script started."
$sqlCommand = @"
USE POS;
DECLARE @sql NVARCHAR(MAX) = '';
SELECT @sql = STRING_AGG(CONVERT(NVARCHAR(MAX), 'DROP STATISTICS '
    + QUOTENAME(SCHEMA_NAME(ob.schema_id)) + '.'
    + QUOTENAME(OBJECT_NAME(s.object_id)) + '.'
    + QUOTENAME(s.name)), '; ')
FROM sys.stats s
INNER JOIN sys.objects ob ON ob.object_id = s.object_id
WHERE SCHEMA_NAME(ob.schema_id) <> 'sys'
AND auto_created = 1;
IF @sql IS NOT NULL AND LEN(@sql) > 0
    EXEC sp_executesql @sql;
"@
$connectionString = "Server=$Server;Database=$Database;Integrated Security=SSPI;"
try {
    $conn = New-Object System.Data.SqlClient.SqlConnection $connectionString
    $cmd = $conn.CreateCommand()
    $cmd.CommandText = $sqlCommand
    $cmd.CommandTimeout = 60
    $conn.Open()
    $cmd.ExecuteNonQuery()
    $conn.Close()
    "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] SQL command executed successfully." | Out-File -FilePath $LogFile -Append
}
catch {
    $errorMsg = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] ERROR: $($_.Exception.Message)"
    $errorMsg | Out-File -FilePath $LogFile -Append
}
$hasError = Select-String -Path $LogFile -Pattern "\berror\b|\bfail\b" -Quiet
$hasWarning = Select-String -Path $LogFile -Pattern "\bwarning\b" -Quiet
if ($hasError) {
    $errorMsg = "DropAutoStats script detected critical errors. See $ErrorLog for details."
    "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] ERROR detected! See error log." | Out-File -FilePath $LogFile -Append
    Copy-Item $LogFile $ErrorLog -Force
    Write-EventLog -LogName $EventLog -Source $EventSource -EntryType Error -EventId 1001 -Message $errorMsg
} elseif ($hasWarning) {
    $warnMsg = "DropAutoStats script completed with warnings. Check $LogFile for details."
    Write-EventLog -LogName $EventLog -Source $EventSource -EntryType Warning -EventId 1002 -Message $warnMsg
} else {
    $infoMsg = "DropAutoStats script completed successfully with no errors."
    Write-EventLog -LogName $EventLog -Source $EventSource -EntryType Information -EventId 1003 -Message $infoMsg
}
"[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] Done dropping auto-created statistics." | Out-File -FilePath $LogFile -Append
"==================================================" | Out-File -FilePath $LogFile -Append
$exitCode = $LASTEXITCODE
Write-EventLog -LogName $EventLog -Source $EventSource -EntryType Information -EventId 1006 -Message "Script completed with exit code $exitCode."
try {
    $archives = Get-ChildItem -Path $ArchiveDir -Filter *.zip | Sort-Object LastWriteTime -Descending
    $archivesToDelete = $archives | Select-Object -Skip 30
    foreach ($file in $archivesToDelete) {
        Remove-Item $file.FullName -ErrorAction Stop
    }
} catch {
    Write-EventLog -LogName $EventLog -Source $EventSource -EntryType Error -EventId 1007 -Message "Failed to clean up old archives: $_"
}

TASK SCHEDULER XML

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Description>Runs the DropAutoStats PowerShell script weekly on Sundays at midnight using SqlClient and SSPI, with robust STRING_AGG fix and explicit USE POS database context.</Description>
    <Author>Admin</Author>
  </RegistrationInfo>
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>2025-05-04T00:00:00</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByWeek>
        <DaysOfWeek>
          <Sunday />
        </DaysOfWeek>
        <WeeksInterval>1</WeeksInterval>
      </ScheduleByWeek>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <UserId>SYSTEM</UserId>
      <LogonType>Password</LogonType>
      <RunLevel>HighestAvailable</RunLevel>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>true</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <StopOnIdleEnd>false</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>PT1H</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <Exec>
      <Command>powershell.exe</Command>
      <Arguments>-ExecutionPolicy Bypass -File C:\POS_Logs\DropAutoStats\DropAutoStats_SSPI.ps1</Arguments>
    </Exec>
  </Actions>
</Task>

CREDITS

Last updated