While helping to manage Microsoft Endpoint, a former colleague suggested that I setup Endpoint to automatically run a full system scan each time an infection is detected. I Googled the blog posting on it and although it is a great post, I figured it could streamlined even more by just using SCCM alone to achieve the same outcome. It is nice when you are out of the office and your backup might not have the time to keep an eye on the antivirus infections. It is also beneficial if you are in an environment where the office is closed overnight and on weekends. If an infection takes place, this can help remediate it without your presence.
This is the third edition. The first edition just initiated a full system scan upon infection. The second edition initiated a full system scan plus would send an email to the designated email address. The third edition now combines the first two and allows for them to be designated using parameters. The code has also been optimized.
I decided to use the SCCM custom application detection to query a system and see if a full system scan has been performed in the event of an infection logged in the event viewer. I first started out by writing a PowerShell script that would perform a WMI query on the SCCM server for the status of the system the application detection was being run on. The problem I ran across was that the application is being run under system credentials, which would require me to pass network credentials within the script. Instead of having to do this, I decided to query the event viewer logs on the local machine to look for the last infection date/time, which is event 1116. I also found that event 1001 and provider name Microsoft Antimalware designate are used when a system scan has been performed. Here are the steps SCCM and PowerShell go through:
psexec.exe \\%computername% -u <domain>\<username> -p <password> -h cmd.exe /c "echo . | powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1"
Do not change %computername%. The only parts of the psexec.exe command line that need to be changed are <domain>, <username>, and <password>.
If you do not want emails sent, then you can use the following command line parameter:
powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -FullScan
or
powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -QuickScan
This is setup in SCCM as a normal application deployment. The only thing that differs from a standard deployment is the application detection method. The ApplicationVirusDetectionMethodEmail.ps1 script is imported in for the detection method. The AntiVirusScanEmail.ps1 file is setup as the installation program. I have mine entered like this:
powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -FullScan
You can see the settings in this video:
If you also want it to email you, then refer to the section above on using psexec.exe and the example to enter in as the installation program.
One more thing is that I have the application hidden from the software center. There really isn't a need for it to be seen by the end-users.
In order for this to work in a timely manor, you will need to change the software deployment frequency under the client settings. I have mine set at every 8 hours, or three times a day.
You can download the application and application detection files from the following links:
This is the third edition. The first edition just initiated a full system scan upon infection. The second edition initiated a full system scan plus would send an email to the designated email address. The third edition now combines the first two and allows for them to be designated using parameters. The code has also been optimized.
I decided to use the SCCM custom application detection to query a system and see if a full system scan has been performed in the event of an infection logged in the event viewer. I first started out by writing a PowerShell script that would perform a WMI query on the SCCM server for the status of the system the application detection was being run on. The problem I ran across was that the application is being run under system credentials, which would require me to pass network credentials within the script. Instead of having to do this, I decided to query the event viewer logs on the local machine to look for the last infection date/time, which is event 1116. I also found that event 1001 and provider name Microsoft Antimalware designate are used when a system scan has been performed. Here are the steps SCCM and PowerShell go through:
- SCCM deploys the package to the system.
- The application detection queries the event viewer logs for the last 1116 ID (infection).
- The application detection queries the event viewer logs for the last 1001 ID and "Microsoft Antimalware" provider name.
- If a system 1001 ID does not exist since the last infection, the custom detection method will exit out as a failure.
- If the custom detection failed, the AntiVirusScanEmail.ps1 file will be executed on the machine.
- An email is sent that tells a scan was performed on %COMPUTERNAME% with the virus details in the body if -Email switch was specified
- Once the scan is complete, an application deployment evaluation cycle is initiated to update the SCCM server with the status of the system.
- The application detection is initiated again to confirm the scan occurred.
psexec.exe \\%computername% -u <domain>\<username> -p <password> -h cmd.exe /c "echo . | powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1"
Do not change %computername%. The only parts of the psexec.exe command line that need to be changed are <domain>, <username>, and <password>.
If you do not want emails sent, then you can use the following command line parameter:
powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -FullScan
or
powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -QuickScan
This is setup in SCCM as a normal application deployment. The only thing that differs from a standard deployment is the application detection method. The ApplicationVirusDetectionMethodEmail.ps1 script is imported in for the detection method. The AntiVirusScanEmail.ps1 file is setup as the installation program. I have mine entered like this:
powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -FullScan
You can see the settings in this video:
If you also want it to email you, then refer to the section above on using psexec.exe and the example to enter in as the installation program.
One more thing is that I have the application hidden from the software center. There really isn't a need for it to be seen by the end-users.
In order for this to work in a timely manor, you will need to change the software deployment frequency under the client settings. I have mine set at every 8 hours, or three times a day.
You can download the application and application detection files from the following links:
ApplicationVirusDetectionMethodEmail.ps1
1: <#
2: .NOTES
3: ===========================================================================
4: Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.127
5: Created on: 8/5/2016 11:11 AM
6: Created by: Mick Pletcher
7: Organization:
8: Filename: ApplicationVirusDetectionMethod.ps1
9: ===========================================================================
10:
11: #>
12:
13:
14: $LastInfection = get-winevent -filterhashtable @{ logname = 'system'; ID = 1116 } -maxevents 1 -ErrorAction SilentlyContinue
15: $LastScan = Get-WinEvent -FilterHashtable @{ logname = 'system'; ProviderName = 'Microsoft Antimalware'; ID = 1001 } -MaxEvents 1
16: If ($LastScan.TimeCreated -lt $LastInfection.TimeCreated) {
17: #No scan since last infection
18: Start-Sleep -Seconds 5
19: exit 0
20: } else {
21: #No infection since last scan
22: Write-Host "No Infection"
23: Start-Sleep -Seconds 5
24: exit 0
25: }
26:
AntiVirusScanEmail.ps1
1: <#
2: .SYNOPSIS
3: EndPoint Virus Scan
4:
5: .DESCRIPTION
6: This script will initiate a full or quick scan, whichever switch is selected at the command line. Once the scan is completed, it will check the event viewer logs for a scan completed entry to verify the scan successfully completed. If the Email switch is designated at the command line, then an email is sent to the specified recipient. It is suggested the $EmailRecipient, $EmailSender, and $SMTPServer be predefined in the parameter field. I have also included a trigger of the application deployment evaluation cycle to expedite the process.
7:
8: .PARAMETER FullScan
9: Initiate a full system scan
10:
11: .PARAMETER QuickScan
12: Initiate a quick scan
13:
14: .PARAMETER Email
15: Select if you want an email report sent to the specified email address
16:
17: .PARAMETER EmailRecipient
18: Receipient's email address
19:
20: .PARAMETER EmailSender
21: Sender's email address
22:
23: .PARAMETER SMTPServer
24: SMTP server address
25:
26: .EXAMPLE
27: Initiate a Quickscan
28: powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -QuickScan
29:
30: Initiate a Fullscan
31: powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -FullScan
32:
33: Initiate a Fullscan and send email report. To, From, and SMTP parameters are pre-defined
34: powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1 -FullScan -Email
35:
36: .NOTES
37: ===========================================================================
38: Created with: SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.127
39: Created on: 8/5/2016 11:11 AM
40: Created by: Mick Pletcher
41: Organization:
42: Filename: AntiVirusScanEmail.ps1
43: ===========================================================================
44: #>
45: param
46: (
47: [switch]
48: $FullScan,
49: [switch]
50: $QuickScan,
51: [switch]
52: $Email,
53: [string]
54: $EmailRecipient = '',
55: [string]
56: $EmailSender = '',
57: [string]
58: $SMTPServer = ''
59: )
60:
61: #Import the Endpoint Provider module
62: Import-Module $env:ProgramFiles"\Microsoft Security Client\MpProvider\MpProvider.psd1"
63: #Get the relative execution path of this script
64: $RelativePath = (split-path $SCRIPT:MyInvocation.MyCommand.Path -parent) + "\"
65: #Find the last infection entry in the event viewer logs
66: $LastInfection = get-winevent -filterhashtable @{ logname = 'system'; ID = 1116 } -maxevents 1 -ErrorAction SilentlyContinue
67: #Full Scan
68: If ($FullScan.IsPresent) {
69: #Initiate a full system scan
70: Start-MProtScan -ScanType "FullScan"
71: #Commented area only there if you want to manually execute this script to watch it execute
72: <# cls
73: Write-Warning "Error: $_"
74: Write-Host $_.Exception.ErrorCode
75: #>
76: #Get the last event viewer log written by Endpoint to check if the full system scan has finished
77: $LastScan = Get-WinEvent -FilterHashtable @{ logname = 'system'; ProviderName = 'Microsoft Antimalware'; ID = 1001 } -MaxEvents 1
78: #
79: If ($LastScan.Message -like '*Microsoft Antimalware scan has finished*') {
80: $EmailBody = "An Endpoint antimalware full system scan has been performed on" + [char]32 + $env:COMPUTERNAME + [char]32 + "due to the virus detection listed below." + [char]13 + [char]13 + $LastInfection.Message
81: } else {
82: $EmailBody = "An Endpoint antimalware full system scan did not complete on" + [char]32 + $env:COMPUTERNAME + [char]32 + "due to the virus detection listed below." + [char]13 + [char]13 + $LastInfection.Message
83: }
84: }
85: #Quick Scan
86: If ($QuickScan.IsPresent) {
87: #Initiate a quick system scan
88: Start-MProtScan -ScanType "QuickScan"
89: #Commented area only there if you want to manually execute this script to watch it execute
90: <# cls
91: Write-Warning "Error: $_"
92: Write-Host $_.Exception.ErrorCode
93: #>
94: #Get the last event viewer log written by Endpoint to check if the quick system scan has finished
95: $LastScan = Get-WinEvent -FilterHashtable @{ logname = 'system'; ProviderName = 'Microsoft Antimalware'; ID = 1001 } -MaxEvents 1
96: #
97: If ($LastScan.Message -like '*Microsoft Antimalware scan has finished*') {
98: $EmailBody = "An Endpoint antimalware quick system scan has been performed on" + [char]32 + $env:COMPUTERNAME + [char]32 + "due to the virus detection listed below." + [char]13 + [char]13 + $LastInfection.Message
99: } else {
100: $EmailBody = "An Endpoint antimalware quick system scan did not complete on" + [char]32 + $env:COMPUTERNAME + [char]32 + "due to the virus detection listed below." + [char]13 + [char]13 + $LastInfection.Message
101: }
102: }
103: #Email Infection Report
104: If ($Email.IsPresent) {
105: $Subject = "Microsoft Endpoint Infection Report"
106: $EmailSubject = "Virus Detection Report for" + [char]32 + $env:COMPUTERNAME
107: Send-MailMessage -To $EmailRecipient -From $EmailSender -Subject $Subject -Body $EmailBody -SmtpServer $SMTPServer
108: }
109: #Initiate Application Deployment Evaluation Cycle
110: $WMIPath = "\\" + $env:COMPUTERNAME + "\root\ccm:SMS_Client"
111: $SMSwmi = [wmiclass]$WMIPath
112: $strAction = "{00000000-0000-0000-0000-000000000121}"
113: [Void]$SMSwmi.TriggerSchedule($strAction)
114:
nice blog
ReplyDeleteHi Mike, Thanks from NJ, USA!
ReplyDeleteMy apology for messing up your name Mick!
DeleteI keep getting the "script is not signed" error although -bypass parameter is specified
DeleteThat sounds like a policy issues on your domain. Have you done a get-executionpolicy?
DeleteHi Mick thanks for your response it was set to RemoteSigned...doh! :)
DeleteSo the command for email report will be
ReplyDeletepsexec.exe \\%computername% -u \ -p -h cmd.exe /c "echo . | powershell.exe -executionpolicy bypass -file AntiVirusScanEmail.ps1" -FullScan -Email
Will have to just change domain\xxx and -p password