Audit Symantec Endpoint Protection Clients

If you’ve ever administered clients running Symantec Endpoint Protection 11 (SEP), you know how woefully inadequate the SEP management interface is for determining the health of your clients.  If a computer get’s a corrupt policy, chances are the Symantec Management Client (SMC) service will stop and refuse to restart.  When this happens, the component of SEP responsible for updating definitions and reporting out of date definitions stops working.  The real-time scanning component – the Symantec Endpoint Protection service – will continue to run, but it will never update.  Since the service that tells the SEP Manager that a client is out of date doesn’t work, chances are you will never know about it unless one (or more) of your end users happens to report it.

So, in order to find the broken SEP clients in my company – about 14,000 computers in various locations around the country – I turned to Powershell and the .NET Framework to do the heavy lifting.  The results were both very surprising and disconcerting.  Hundreds of our computers were out of date and not reporting this to the SEP Manager.  This information allowed us to update our computers using a combination of some automation and the good ol’ fashioned Sneaker Net.

This script assumes a few things:

  1. You must have admin privileges on the computers you are auditing.
  2. File and Print Sharing is enabled on the computers.
  3. You have a pretty solid list of computer names to run the Powershell script against (I used an SCCM list of all discovered Active Directory computer objects).
#################################################################
#
#
#	- Antivirus Health Check Script
#	- Audit computer objects from a text file specified at
#		runtime.  Checks for AV version, stopped/running
#		services, and definition dates.
#
#	- Written by Jim Melton
#        ** Feel free to use and modify this script as needed.
#            Just please give credit if you do.
#
#################################################################
 
## Setup command line parameter to allow user to specify content
## file at runtime.  Parameter is -FileName
param ([string]$FileName = $(throw "Text Input is Required"))
Write-Host $FileName
 
## Load assembly used to interrogate services on the remote machine.
[System.Reflection.Assembly]::LoadWithPartialName('system.serviceprocess')
$erroractionpreference = "Continue"
 
## Set variables
$SMCsvc = "Symantec Management Client"
$SMCstatus = ""
$SEPsvc = "Symantec Endpoint Protection"
$SAVsvc = "Symantec Antivirus"
$SAV8svc = "Symantec Antivirus Client"
$Path = "c$\Program Files\Common Files\Symantec Shared\VirusDefs"
$SavePath = "\\SERVER\SHARE\"
 
## Instantiate Excel ComObject and write headings on spreadsheet.
$excel = New-Object -comobject Excel.Application
$excel.visible = $true
 
$workbook = $excel.Workbooks.Add()
$worksheet = $workbook.Worksheets.Item(1)
 
$worksheet.Cells.Item(1,1) = "Machine Name"
$worksheet.Cells.Item(1,2) = "IP Address"
$worksheet.Cells.Item(1,3) = "AV Version"
$worksheet.Cells.Item(1,4) = "Virus Definition"
$worksheet.Cells.Item(1,5) = "Status"
 
$range = $worksheet.UsedRange
$range.Interior.ColorIndex = 19
$range.Font.ColorIndex = 11
$range.Font.Bold = $True
 
$intRow = 2
 
## Create Ping object
$ping = New-Object System.Net.NetworkInformation.Ping
 
## Get data from user specified file
$colComputers = get-content $FileName 
 
foreach ($computer in $colComputers){
 
	## Zero variables at the top of the loop and ping the next machin
	## in the list.
	$IPaddress = ""
	$AVservice = ""
	[string]$service = ""
	$VirDate = ""
	$reply = $ping.send($computer)
	$IPaddress = [string]$reply.Address
 
	## Check ping reply.  If it's a success, test the Symantec Shared files path to see if
	## it exists.  If the path is valid, get the content of definfo.dat and parse the
	## definition date and rev.
	If ($reply.status -eq 'Success'){
		$ValidPath = Test-Path "\\$computer\$path"
		If ($ValidPath -eq "True"){
		     $DefInfo = Get-Content "\\$computer\$Path\definfo.dat"
		     $DefLine = $DefInfo[1]
		     $DefYear = $DefLine.substring(8,4)
		     $DefMonth = $DefLine.substring(12,2)
		     $DefDay = $DefLine.substring(14,2)
		     $Revision = $DefLine.substring(17,3)
		     [int]$DefDate = $DefLine.Substring(8,8)
		     [string]$DefDate = "$DefMonth" + "-" + "$DefDay" + "-" + "$DefYear"
		     $VirDate = [datetime]$DefDate
		}
 
		## If the path or definfo.dat doesn't exist, bail out of the if statement.
		Else{
		     $VirDate = $null
		     Continue
		}
	## Query the remote machine for the SEP, SAV, or SAV 8x RTVScan services.  Also,
	## query the SMC service for SEP.  These are separate in order to make sure
	## that both the SEP and SMC services are running on a machine.
	$services = [System.ServiceProcess.ServiceController]::GetServices($computer) | `
			where { (($_.displayname -eq $SEPsvc) -or ($_.displayname -eq $SAVsvc) `
			                                      -or ($_.displayname -eq $SAV8svc))}
	$SMCservice = [System.ServiceProcess.ServiceController]::GetServices($computer) | `
			where { ($_.displayname -eq $SMCsvc)}
 
	## Check to see what services are present.  If there are no services on the machine, write that
	## into the spreadsheet and continue on to the next computer.
	foreach ($service in $services){
		If ($service.displayname -eq $null){
			$worksheet.Cells.Item($intRow,1) = $computer
			$worksheet.Cells.Item($intRow,2) = $IPaddress
			$worksheet.Cells.Item($intRow,5) = "Services are not present on $computer."
			$intRow = $intRow + 1
		}
 
		## Otherwise, if it's SAV or SAV 8, insert SAV into $AVService.
		Else{
			If (($service.DisplayName -eq $SAVsvc) -or ($service.DisplayName -eq $SAV8svc)){
				$AVservice = "Symantec Antivirus"
			}
 
			## If not Null or SAV, then it must be SEP.  Insert SEP into $AVService.  Also check to see if
			## the SMC service is stopped.  If so, set $SMCstatus to Stopped.
			Else {
				If ($service.DisplayName -eq $SEPsvc){
				     $AVservice = "Symantec Endpoint Protection"
				     If ($SMCservice.DisplayName -eq $SMCsvc){
		        	          If ([string]$SMCservice.status -eq 'Stopped'){
			        		$SMCstatus = "Stopped"
					  }
				     }
				}
			}
 
		## If computer is online and has AV installed, insert its information into the spreadsheet.
		## If the SMC service is stopped, append that info to the Status block showing the SEP
		## RTVScan status.  Otherwise,just insert the status of RTVScan.
		$worksheet.Cells.Item($intRow,1) = $computer
		$worksheet.Cells.Item($intRow,2) = $IPaddress
		$worksheet.Cells.Item($intRow,3) = $AVservice
		$worksheet.Cells.Item($intRow,4) = "$DefDate" + " rev " + "$Revision"
		If ($SMCstatus -eq "Stopped"){
			$worksheet.Cells.Item($intRow,5) = [string]$service.Status + ", `
				however, the SMC Service is stopped."
		}
		Else{
			$worksheet.Cells.Item($intRow,5) = [string]$service.Status
		}
	}
 
	## Increment the spreadsheet row and reset $SMCstatus to blank.
	$intRow = $intRow + 1
	$SMCstatus = ""
		}
	}
 
	## If the machine doesn't respond to a ping, insert that in the spreadsheet.
	Else{
		If ($reply.status -eq "TimedOut"){
			$worksheet.Cells.Item($intRow,1) = $computer
			$worksheet.Cells.Item($intRow,3) = $IPaddress
			$worksheet.Cells.Item($intRow,5) = "Did not respond to a ping."
			$intRow = $intRow + 1
		}
		## If the machine doesn't respond to a ping and the IP is not valid, the computer name
		## must not bevalid any longer.
		Else{
			$IPaddress = "Computer name is not valid."
			$worksheet.Cells.Item($intRow,1) = $computer
			$worksheet.Cells.Item($intRow,3) = $IPaddress
			$worksheet.Cells.Item($intRow,5) = "Did not respond to a ping."
			$intRow = $intRow + 1
		}
	}
 
## Once the data is completely written to the spreadsheet, auto-fit all columns to the data width.
$range.EntireColumn.AutoFit() | Out-Null
}
 
## Switch statement using a regular expression switch to determine location being audited based on the
## input file filename.  If you need an Adhoc report, use computers.txt as the input file.
Switch -regex ($FileName){
 
	"loc01comps.txt" {$Location = "Location1"}
	"loc02comps.txt" {$Location = "Location2"}
	"loc03comps.txt" {$Location = "Location3"}
	"loc04comps.txt" {$Location = "Location4"}
	"loc05comps.txt" {$Location = "Location5"}
	"loc06comps.txt" {$Location = "Location6"}
	"loc07comps.txt" {$Location = "Location7"}
	"loc08comps.txt" {$Location = "Location8"}
	"loc09comps.txt" {$Location = "Location9"}
	"loc10comps.txt" {$Location = "Location10"}
	"loc11comps.txt" {$Location = "Location11"}
	"computers.txt"    {$Location = "Adhoc Report"}
	default {$Location = "Other"}
}
 
## Save the spreadsheet to the path in the variable using the name determined from the above Switch.
$SpreadSheetName = $SavePath+$Location+".xls"
$workbook.Worksheets.item(1).Name = $Location
 
## Check to see if the spreadsheet exists.  If it does, delete it and recreate it, and save it.
## Attempt to close Excel and end the ComObject.  This doesn't seem to work well with Excel 2K7,
## so we are killing processes called Excel.  This will close all Excel processes.
If(Test-Path $SpreadSheetName){
	Remove-Item $SpreadSheetName
	Write-host $SpreadSheetName
	$excel.ActiveWorkbook.SaveAs($SpreadSheetName)
	$excel.Quit()
	[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
	Remove-Variable excel
	Get-Process -Name Excel | Kill
}
Else{
	$excel.ActiveWorkbook.SaveAs($SpreadSheetName)
	$excel.Quit()
	[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
	Remove-Variable excel
	Get-Process -Name Excel | Kill
}

6 thoughts on “Audit Symantec Endpoint Protection Clients

  1. Pingback: Repair a Broken Symantec Management Client Service

  2. Mike

    Thank you for taking the time to post this fantastic script! It’s going into my toolkit for future use.

    Kind Regards,

    Mike

  3. Gudge

    This is a great script!

    Would it be possible to output the installed location on each computer?

  4. Jim Post author

    It’s absolutely possible. I actually grab the installation path from the registry in . I’ll get that code together and try to get back to you today.

  5. Jim Post author

    Here is the code you will have to add to that script specifically, but this could easily be adapted for about any application you need the path for. A quick disclosure on this…I haven’t tested this to verify how well it works. If you run into problems, let me know and I’ll try to figure out what’s wrong.

    ## This is to initialize the usual registry path for SEP, the SEP install variable,
    ## and the SEP "Home Directory" key. Depending on whether SEP was installed freshly 
    ## or if this was an upgrade, the SEP registry path may be slightly different. It
    ## would be a good idea to check a couple of computers first. This also goes at the 
    ## top of the script. This goes at the top of the script.
    $SEPreg       = "SOFTWARE\Symantec\Symantec Endpoint Protection\AV"
    $SEPinstall   = ""
    $SEPhome      = "Home Directory"
     
    ## This line adds a column in Excel that we will write our installation path to.
    ## Add it just below $worksheet.Cells.Item(1,5) = "Status"
    $worksheet.Cells.Item(1,5) = "Status"
     
    ## Open a remote registry connection with .NET.  LocalMachine in this call
    ## refers to the HKEY Local Machine Hive. If you needed this for another
    ## hive, you could change it to whatever is necessary. A quick Google/Bing
    ## search should give you what you need. The $computer variable should be
    ## obvious. This needs to go just below if($reply.status -eq 'Success')
    $OpenRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey
                      ([Microsoft.Win32.RegistryHive]::LocalMachine,$computer)
     
     
    ## Again, using the Audit script, you need to add this immediately below
    ## the $OpenRegistry variable entry. This opens the registry
    ## location we specified above and gets the value of the $SEPHome key.
    $SEPpath      = $OpenRegistry.OpenSubKey($SEPreg,$true)
    $SEPinstall   = $SEPpath.GetValue("$SEPhome")
     
    ## Write the install path to the newly created column. This goes
    ## below Else{
    ##		$worksheet.Cells.Item($intRow,5) = [string]$service.Status
    ##	     }
    $worksheet.Cells.Item($intRow,3) = $SEPinstall
  6. Gudge

    Jim sorry for the long delay in replying back to you, i will try with those update suggestions and let you know – Many thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *