Benachrichtigungen erhalten wenn der Symantec Endpoint Protection Manager (SEPM) keine Virendefinitionen aktualisiert

Seit Jahren benutzen wir die Symantec Endpoint Protection in meiner Firma. Aktuell die Version 14.0.1.
Eigentlich macht das Ding was es soll. Aber… Es gibt einen Fall in dem im Werkzeug Koffer von Symantec kein Tool vorhanden ist das Problem zu lösen.

Was passiert?

Eigentlich möchte man ja von einem Antivirensystem nichts hören und sehen. Es soll funktionieren und das war es.
Ganz besonders in einer Firma in der 5, 10, 20 und mehr Clients vorhanden sind.
Der SEPM (Symantec Endpoint Protection Manager), benachrichtigt much brav wenn auf Stations nach mehreren Tagen noch alte Virendefinition sind, oder auch eine bestimme Anzahl von PCs erreicht wurden, die alte Virendefinitionen haben. Oft sind das bei uns Maschinen, die unterwegs sind, oder lange nicht eingeschaltet wurden.

Aber es gibt einen Fall in dem der SEPM vollkommen versagt: Wenn nämlich der SEPM selber keine neuen Virendefinitionen erhält. Warum auch immer!

Ich hatte in den letzten Jahren mehrfach den Fall, in denen der SEPM keine neuen Virendefinitionen von Symantec geladen hat. Die Gründe waren vielseitig. Mal hatte der SEPM kein Internet aufgrund eines Konfigurationsfehlers, mal startete der SEPM gar nicht nach einem Windows Update.
Aber in den meisten Fällen war der SEPM einfach nicht fähig, die neuen Signaturen zu laden obwohl er anzeigte, dass welche zum Download bereit stehen.

Der letzte Fall ist besonders nervig. Ich habe zwei Support-Cases zu dem Thema schon offen gehabt, aber die redlich bemühten Supporter haben dennoch nichts herausbekommen.
Nach jeweiligem Neustart des Dienstes oder des Servers, lief es fast immer wieder. Also hatte sich scheinbar nur irgendwas intern „verklemmt“!

Dieser Fall ist aber gefährlich. Man bekommt von der ganzen Sache nichts mit, bis eine bestimmte Anzahl von PCs nach ein paar Tagen eben alte Virendefinitionen haben. In der Einstellung bei uns sind das 10% der Maschinen nach 4 Tagen. Man kann das zwar herunter drücken, aber diese Warnungen nerven meistens nur ohne triftigen Grund.
Und man kann in diesem Fall nicht mal testweise einfach den SEPM neu starten.
Eigentlich will ich keine Meldung und das System soll erstmal selbst versuchen erkannte Problem zu lösen.
Vor allem habe ich keine Lust irgendjemanden zu beauftragen, der pro Tag einmal diese blöde Konsole startet und nachschaut was los ist. Über alles andere bekomme ich ja auch Emails.

Ich finde solch eine lange Latenz, in der es nicht bemerkt wird, dass die AV-Signaturen alt sind, einfach gefährlich.
Aber Bordmittel darüber zu warnen gibt es nicht!
Zudem trat dieser Fall ca alle 6-9 Wochen immer einmal wieder auf.
Und das nervt.

Also habe ich mich auf die Suche gemacht und habe für den SQL Server in dem unsere Daten gehalten werden zwei kleine Jobs geschrieben die nachfolgend beschreiben werden.
Diese Jobs laufen nun einige Monate und haben bereits mehrfach erfolgreich dieses Problem „selbsttätig“ behoben…

Job 1: Symantec Virus Signature Check

Dieser Job läuft jede Stunde einmal.
Der Code macht einfach folgendes.

  • Sollte es in den letzten 32 Stunden (siehe Wert für @delta) eine Änderungen in den Signaturen gegeben haben ist alles OK
  • Gab es kein Update der Signaturen dann werden zwei Schritte eingeleitet.
  • Es wird über den internen SQL Mail Dienst eine Warnung versendet an den Admin.
  • Danach wird ein weiterer Job gestartet mit dem Namen Symantec SEPM Restart.

Die 32 Stunden, sind ein Wert der sich aus Erfahrungswerten gebildet hat. In 98% aller Fälle werden Signaturen innerhalb von 24h aktualisiert. Aber es gibt eben ein paar Ausnahmen

Taucht die Email mehr als zweimal auf, muss ich wohl irgendwie aktiv werden und mal manuell kontrollieren.

DECLARE @delta INT
-- number of hours
SET @delta = 32 
DECLARE @d DATETIME 
DECLARE @t VARCHAR(MAX)
IF NOT EXISTS(SELECT * FROM PATTERN WHERE INSERTDATETIME>DATEADD(hh,-@delta,GETDATE()) AND PATTERN_TYPE='VIRUS_DEFS')
BEGIN
      SET @d = (SELECT TOP 1 INSERTDATETIME FROM PATTERN WHERE PATTERN_TYPE='VIRUS_DEFS' ORDER BY INSERTDATETIME DESC)
      SET @t = 'Hallo Admin!

Die letzten Antivirus-Signaturen wurden am ' + CONVERT(VARCHAR, @d, 120)+' aktualisiert!
Es wird versucht den SEPM Dienst neu zu starten!

Liebe Grüße Ihr
SQLServerAgent'
      EXEC msdb.dbo.sp_send_dbmail @profile_name='Administrator',
				   @recipients='administrator@mydomain.de',
				   @subject='Symantec Virus Definitionen sind nicht aktuell',
				   @body=@t
      PRINT 'Virus Signaturen sind veraltet! Letztes Update: ' + CONVERT(VARCHAR, @d, 120)
      EXEC msdb.dbo.sp_start_job @job_name='Symantec Restart'
      PRINT 'Restart SEPM server!!!'
    END
  ELSE
    BEGIN 
      SET @d = (SELECT TOP 1 INSERTDATETIME FROM PATTERN WHERE PATTERN_TYPE='VIRUS_DEFS' ORDER BY INSERTDATETIME DESC)
      PRINT 'Virus Signaturen sind OK! Letztes Update: ' + CONVERT(VARCHAR, @d, 120)
    END

Job 2: Symnatec Restart

Dieser Job wird nur durch den Job 1 gestartet und er ist äußerst trivial.
Führt einfach nur 2 Befehle aus, die den SEPM stoppen und anschließend neu starten.

NET STOP SEMSRV
NET START SEMSRV

PS: Traurig war, dass man durch den Support auch keine Hilfe bekam, nachdem ich solch einen Lösungsansatz vorschlug. Man wollte mir keine Infos über die Strukturen der Tabellen geben. Letzten Endes waren die Suchmaschinen so nett alle nötigen Informationen zu liefern, denn ich war nicht der einzige mit diesem Problem.

Probleme nach Upgrade auf Microsoft SQL Server 2008 R2

Ein Kollege von mir hat ein Upgrade von seinen Microsoft SQL Server 2008 auf einen Microsoft SQL Server 2008 R2 durchgeführt.

Soweit ist alles gut abgelaufen, der SQL Server läuft. Einzig die Reporting Services ließen sich nicht mehr starten. Die Reporting Services liefen allerdings zuvor ohne Probleme.

Eine Reparaturinstallation sowie Entfernen und erneutes Hinzufügen des Dienstes wurden ohne jedweden Erfolg durchgeführt.

Nach dem fehlgeschlagenem Start des Dienst fanden sich nur die drei folgenden Einträge im Event-Log:

Protokollname: Application
Quelle:        SQL Server Reporting Services (MSSQLSERVER)
Datum:         26.05.2011 14:56:09
Ereignis-ID:   0
Aufgabenkategorie:Keine
Ebene:         Fehler
Schlüsselwörter:Klassisch
Benutzer:      Nicht zutreffend
Computer:      xyz
Beschreibung:
Der Dienst kann nicht gestartet werden. System.Exception: Default appdomain failed to initialize.
bei Microsoft.ReportingServices.Library.ServiceAppDomainController.Start()
bei Microsoft.ReportingServices.Library.ReportService.OnStart(String[] args)
bei System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)
Protokollname: Application
Quelle:        Report Server Windows Service (MSSQLSERVER)
Datum:         26.05.2011 14:56:09
Ereignis-ID:   140
Aufgabenkategorie:Starten/Herunterfahren
Ebene:         Fehler
Schlüsselwörter:Klassisch
Benutzer:      Nicht zutreffend
Computer:      xyz
Beschreibung:
Fehler beim Initialisieren der DefaultDomain-Anwendungsdomäne. Fehler: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt..

Protokollname: Application
Quelle:        Report Server Windows Service (MSSQLSERVER)
Datum:         26.05.2011 14:56:09
Ereignis-ID:   113
Aufgabenkategorie:Protokollierung
Ebene:         Fehler
Schlüsselwörter:Klassisch
Benutzer:      Nicht zutreffend
Computer:      xyz
Beschreibung:
Der Berichtsserver kann den Leistungsindikator 'Report Requests' nicht erstellen.

Der letzte Eintrag mit der Meldung „Der Berichtsserver kann den Leistungsindikator ‚Report Requests‘ nicht erstellen.“, in Verbindung mit der Meldung „System.Exception: Default appdomain failed to initialize.“ . Hat mich letzten Endes auf die Spur gebracht.

Die Lösung ist hier zu finden: http://support.microsoft.com/kb/956155/en-us

Offensichtlich wurde bei der Deinstallation des 2008er SQL-Servers mehr entfernt als gut war und der hier vorgeschlagene Weg einer Reparaturinstallation war leider nicht erfolgreich.
Ich habe die 4 Schlüssel die fehlten einfach manuell eingefügt und der Dienst konnte danach sofort wieder gestartet werden.

Tipps & Tricks: Mal ganz schnell das MS-SQL Server 2008 Managment Studio Express nachinstallieren

Bei dem Management Studio für die 2005 EE war noch alles ganz einfach. Man schmeißt einfach den Installer an. Man klickt ein paar mal weiter und das war es auch schon. Nachdem ich VS-2010 installiert hatte wollte ich nun auch das passende Management Studio für die 2008 EE installieren. Also:

  • Download gemacht 
  • Setup gestartet
  • und 😕 was nun?

Das Setup und das was ich hier alles einstellen kann ist alles andere als intuitiv.

Ich mache es kurz. Man kann sich das ganze durch-die-Dialoge-hangeln sparen.
Man startet einfach die Installation mit dem folgenden Befehl von einer Befehlszeile:

SQLManagementStudio_x86_xxx.exe /q /FEATURES= SSMS /ACTION=Install

Statt xxx gebe man bitte einfach in DEU oder ENU an, je nachdem was man für eine Sprache hat.

Gefunden habe ich das hier auf diesem Link, hier finden sich auch weitere Anweisungen wie man sich durch die Dialoge quälen muss:
http://blogs.msdn.com/billramo/archive/2009/02/20/sql-server-2008-management-studio-express-released-to-the-web.aspx

Das Management Studio Express findet sich hier zum Download:
http://www.microsoft.com/downloads/details.aspx?familyid=08E52AC2-1D62-45F6-9A4A-4B76A8564A2B&displaylang=de

Alle SQL Server enumerieren mit den OLE-DB Enumeratoren

Wie bekommt man eigentlich einfach eine Liste aller verfügbaren SQL-Server im Netz?

In der MSDN findet sich schnell ein Artikel How to enumerate available instances of SQL Server by using the SQLDMO components. Allerdings ist dieser Artikel wenig nützlich, denn SQL-DMO findet man nur noch selten auf einem Rechner.

Dabei ist es doch relativ einfach, denn OLE-DB sieht hierfür Enumeratoren vor. Aber auch die sind nicht sonderlich gut dokumentiert. In der SQL-2000 Server Doku findet sich noch ein Eintrag für den SQLOLEDB Enumerator. Für den neuen nativen OLE-DB Clienst für den SQL-Server finde ich nichts mehr dazu.

ATL stellt direkt Klassen zur Verfügung, die die Nutzung von Enumeratoren zu einem Kinderspiel machen.

Anbei ein Codeschnippsel der alle bekannten MS-SQL Server enumeriert. Ich beginne dabei mit dem neuesten Client (2008) und gehe die Schleife weiter bis zum ältesten Server Client (2000).
Wird ein Enumerator gefunden, und dieser lieferte Ergebnisse, dann wird die Schleife abgebrochen. Denn alle Enumeratoren liefern im Allgemeinen das gleiche Ergebnis.

Code:

//////////////////////////////////////////////////////////////////////////
// Main function to enumerate all servers with the appropriate
// known enumerators.

typedef std::set  TSET_CString;

void EnumSQLServer(TSET_CString &setSQLServer)
{
  // We may need the local server name. 
  // We replace the token (local) with the current computer name.
  CString strCompLocal;
  DWORD dwLen = MAX_COMPUTERNAME_LENGTH+1;
  ::GetComputerName(CStrBuf(strCompLocal,dwLen),&dwLen);

  // Loop over all enumerators we know
  static const PCWSTR aEnumerator[] =
  {
    L"SQLNCLI10 Enumerator",    // SQL 2008
    L"SQLNCLI Enumerator",      // SQL 2005
    L"SQLOLEDB Enumerator"      // SQL 2000
  };

  // Try all enumerators
  for (int i=0; i < _countof(aEnumerator); ++i)
  {
    // Check if we have an enumerator
    bool bFoundAny = false;
    HRESULT hr;
    CLSID clsid;
    hr = CLSIDFromProgID(aEnumerator[i],&clsid);
    if (SUCCEEDED(hr))
    {
      // Open enumerator and loop over all entries
      CEnumerator enumrator;
      hr = enumrator.Open(&clsid);
      if (SUCCEEDED(hr))
      {
        while ((hr=enumrator.MoveNext())==S_OK)
        {
          CString strServerName(enumrator.m_szName);

          // Skip empty server names 
          // (older enumerators return sometimes an empty name)
          if (strServerName.IsEmpty())
            continue;

          // Some enumerators return (local) for a local main
          // SQL server instance
          if (strServerName.CompareNoCase(_T("(local)"))==0)
          {
            ATLTRACE(__FUNCTION__ " found local computer\n");
            strServerName = strCompLocal;
          }

          // get uppercase server name
          strServerName.MakeUpper();

          // Insert in list and avoid duplicates with this, if
          // developer decides not to break the loop after the first
          // enumerator.
          if (setSQLServer.insert(strServerName).second)
            ATLTRACE(__FUNCTION__ " found server %s\n",
                  CT2A(strServerName.GetString()));
          bFoundAny = true;
        }
      }

      // After we have found data in one enumerator. There is no need
      // to do this again.
      // But a developer might decide to do this for every enumerator
      if (bFoundAny)
        break;
    }
  }
}

Ein lauffähiges Projekt kann man hier herunterladen: EnumSQLServer.zip.