Antivirus management is a critical aspect of IT administration, particularly for managed service providers (MSPs) and IT professionals tasked with overseeing large fleets of devices. Efficiently configuring or overriding antivirus settings across multiple endpoints can save time, ensure compliance, and maintain security posture. The provided PowerShell script offers a robust solution for setting antivirus overrides or removing existing ones in a structured and automated way.
Background
In IT environments, administrators often encounter scenarios where they need to standardize antivirus configurations across endpoints. This can include specifying antivirus versions, statuses, and states to reflect the actual security state of devices or to override reported information for compliance reasons. The script serves as a tool to either add or update antivirus details or remove overrides altogether. It is particularly useful for MSPs managing diverse client environments through tools like NinjaOne.
By leveraging PowerShell, this script streamlines operations, eliminates manual errors, and ensures consistency in antivirus management. Its ability to handle overrides programmatically makes it an asset for IT professionals who manage numerous devices or those seeking to enforce organization-wide security standards.
The Script:
#Requires -Version 5.1 <# .SYNOPSIS Add an antivirus to the device details or override the existing antivirus information. .DESCRIPTION Add an antivirus to the device details or override the existing antivirus information. By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use. Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA). .EXAMPLE -AntivirusName "My AV" -AntivirusVersion "1.0.1" -AntivirusStatus "Out-of-Date" -AntivirusState "ON" Creating customization folder. Directory: C:\ProgramData\NinjaRMMAgent Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 6/19/2024 4:09 PM Customization Successfully created customization folder. Applying override. Successfully applied override. PARAMETER: -AntivirusName "ReplaceMeWithNameOfAnAntivirus" Name of the antivirus you would like to appear in the device details. PARAMETER: -AntivirusVersion "1.0.2" Specify the version number of the antivirus. PARAMETER: -AntivirusStatus "Up-to-Date" Specify whether the antivirus definitions are up-to-date, out-of-date, or unknown. PARAMETER: -AntivirusState "ON" Specify the current status of the antivirus. PARAMETER: -Append Append or update an existing override. PARAMETER: -RemoveOverride Remove all existing overrides. .NOTES Minimum OS Architecture Supported: Windows 10, Windows Server 2016 Release Notes: Initial Release #> [CmdletBinding()] param ( [Parameter()] [String]$AntivirusName, [Parameter()] [String]$AntivirusVersion, [Parameter()] [String]$AntivirusStatus, [Parameter()] [String]$AntivirusState, [Parameter()] [Switch]$Append = [System.Convert]::ToBoolean($env:append), [Parameter()] [Switch]$RemoveOverride = [System.Convert]::ToBoolean($env:removeOverride) ) begin { # Replace command line paramets with the form variables if used. if ($env:avName -and $env:avName -notlike "null") { $AntivirusName = $env:avName } if ($env:avVersion -and $env:avVersion -notlike "null") { $AntivirusVersion = $env:avVersion } if ($env:avStatus -and $env:avStatus -notlike "null") { $AntivirusStatus = $env:avStatus } if ($env:avState -and $env:avState -notlike "null") { $AntivirusState = $env:avState } # Check if RemoveOverride is set and any of the other parameters are also set if ($RemoveOverride -and ($AntivirusState -or $AntivirusStatus -or $AntivirusVersion -or $AntivirusName -or $Append)) { Write-Host -Object "[Error] Cannot remove an override and add an override at the same time." exit 1 } # Check if AntivirusName is not provided and RemoveOverride is not set if (!$AntivirusName -and !$RemoveOverride) { Write-Host $RemoveOverride if ($Append) { Write-Host -Object "[Error] Antivirus name was not given. The antivirus name is required when updating or adding a new override!" } else { Write-Host -Object "[Error] Antivirus name was not given. Antivirus name, state, and status are required when adding a new override!" } exit 1 } # Validate AntivirusVersion for invalid characters if ($AntivirusVersion -and $AntivirusVersion -match '[^0-9\.]') { Write-Host -Object "[Error] The antivirus version given contains an invalid character. Only the following characters are allowed: '0-9' and '.'" exit 1 } # Check if AntivirusStatus is not provided and neither RemoveOverride nor Append is set if (!$AntivirusStatus -and !$RemoveOverride -and !$Append) { Write-Host -Object "[Error] Antivirus status was not given. Antivirus name, state, and status are required!" exit 1 } # Define valid antivirus statuses $ValidStatus = "Up-to-Date", "Out-of-Date", "Unknown" # Check if the provided AntivirusStatus is valid if ($AntivirusStatus -and $ValidStatus -notcontains $AntivirusStatus) { Write-Host -Object "[Error] An invalid antivirus status was given. Only the following statuses are valid: 'Up-to-Date', 'Out-of-Date', and 'Unknown'." exit 1 } # Check if AntivirusState is not provided and neither RemoveOverride nor Append is set if (!$AntivirusState -and !$RemoveOverride -and !$Append) { Write-Host -Object "[Error] Antivirus state was not given. Antivirus name, state, and status are required!" exit 1 } # Define valid antivirus states $ValidState = "ON", "OFF", "EXPIRED", "SNOOZED", "UNKNOWN" # Check if the provided AntivirusState is valid if ($AntivirusState -and $ValidState -notcontains $AntivirusState) { Write-Host -Object "[Error] An invalid antivirus state was given. Only the following states are valid: 'ON', 'OFF', 'EXPIRED', 'SNOOZED', and 'UNKNOWN'." exit 1 } # Check if the NinjaRMMAgent directory exists if (!(Test-Path -Path "$env:ProgramData\NinjaRMMAgent")) { Write-Host -Object "[Error] Ninja Agent is not present at '$env:ProgramData\NinjaRMMAgent'." exit 1 } # Function to check if the script is running with elevated privileges function Test-IsElevated { $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object System.Security.Principal.WindowsPrincipal($id) $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) } # Set ExitCode to 0 if it is not already set if (!$ExitCode) { $ExitCode = 0 } } process { # Check if the script is running with elevated privileges if (!(Test-IsElevated)) { Write-Host -Object "[Error] Access denied. Please run with administrator privileges." exit 1 } # Check if RemoveOverride is set if ($RemoveOverride) { # Check if the antivirus override file exists if (Test-Path -Path "$env:ProgramData\NinjaRMMAgent\Customization\av_override.json" -ErrorAction SilentlyContinue) { Write-Host -Object "Removing $env:ProgramData\NinjaRMMAgent\Customization\av_override.json file." # Attempt to remove the antivirus override file try { Remove-Item -Path "$env:ProgramData\NinjaRMMAgent\Customization\av_override.json" -ErrorAction Stop } catch { Write-Host -Object "[Error] Failed to remove antivirus override." Write-Host -Object "[Error] $($_.Exception.Message)" exit 1 } } else { Write-Host -Object "Antivirus override is not currently set." } exit $ExitCode } # Check if the Customization directory exists, if not, create it if (!(Test-Path -Path "$env:ProgramData\NinjaRMMAgent\Customization" -ErrorAction SilentlyContinue)) { try { Write-Host -Object "Creating customization folder." New-Item -Path "$env:ProgramData\NinjaRMMAgent\Customization" -ItemType Directory -Force -ErrorAction Stop Write-Host -Object "Successfully created customization folder.`n" } catch { Write-Host -Object "[Error] Unable to create customization folder." Write-Host -Object "[Error] $($_.Exception.Message)" exit 1 } } # Initialize a list to hold antivirus overrides $AntivirusOverrides = New-Object System.Collections.Generic.List[Object] # If Append is set and the antivirus override file exists, retrieve current overrides if ($Append -and (Test-Path -Path "$env:ProgramData\NinjaRMMAgent\Customization\av_override.json" -ErrorAction SilentlyContinue)) { try { $CurrentOverrides = Get-Content -Path "$env:ProgramData\NinjaRMMAgent\Customization\av_override.json" -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop | Select-Object -ExpandProperty "av_override" -ErrorAction Stop } catch { Write-Host -Object "[Error] Failed to retrieve current overrides." Write-Host -Object "[Error] $($_.Exception.Message)" exit 1 } # Iterate over current overrides to update or add new overrides $CurrentOverrides | ForEach-Object { if ($AntivirusName -notmatch [Regex]::Escape($_.av_name)) { $AntivirusOverrides.Add($_) return } Write-Host -Object "An existing antivirus with the same name was detected. Updating the existing entry.`n" $AntivirusOverrides.Add( [PSCustomObject]@{ av_name = $AntivirusName av_version = if ($AntivirusVersion) { $AntivirusVersion }else { $_.av_version } av_status = if ($AntivirusStatus) { $AntivirusStatus }else { $_.av_status } av_state = if ($AntivirusState) { $AntivirusState }else { $_.av_state } } ) $UpdatedOverride = $True } } # If Append is set but no override was updated, check for required parameters if ($Append -and !$UpdatedOverride -and (!$AntivirusStatus -or !$AntivirusState)) { Write-Host -Object "[Error] Antivirus name, state, and status are required when adding a new override!" exit 1 } elseif ($Append) { Write-Host -Object "Adding override to the existing list of overrides.`n" } # If no override was updated, add a new override if (!$UpdatedOverride) { $AntivirusOverrides.Add( [PSCustomObject]@{ av_name = $AntivirusName av_version = $AntivirusVersion av_status = $AntivirusStatus av_state = $AntivirusState } ) } # Attempt to apply the override by writing to the override file try { Write-Host -Object "Applying override." $AntivirusOverrideJSON = [PSCustomObject]@{ av_override = $AntivirusOverrides } | ConvertTo-Json -ErrorAction Stop $AntivirusOverrideJSON | Out-File -FilePath "$env:ProgramData\NinjaRMMAgent\Customization\av_override.json" -Encoding "utf8" -Force -ErrorAction Stop Write-Host -Object "Successfully applied override." } catch { Write-Host -Object "[Error] Unable to create override." Write-Host -Object "[Error] $($_.Exception.Message)" exit 1 } exit $ExitCode } end { }
Save time with over 300+ scripts from the NinjaOne Dojo.
Detailed Breakdown of the Script
Initial Validation and Parameters
The script begins by accepting several parameters:
- AntivirusName: Name of the antivirus to appear in the device details.
- AntivirusVersion: Version number of the antivirus.
- AntivirusStatus: Status of the antivirus, such as “Up-to-Date” or “Out-of-Date”.
- AntivirusState: Operational state of the antivirus, such as “ON” or “OFF”.
- Append: A switch to add or update an existing override.
- RemoveOverride: A switch to remove all overrides.
The script validates these inputs, ensuring the antivirus version contains only numeric characters and dots and that the status and state fall within predefined valid values.
Privilege Checks
To prevent unauthorized changes, the script ensures it is running with administrator privileges. If not, it terminates with an error message.
Override Management
- Remove Overrides: If RemoveOverride is specified, the script deletes any existing override file (av_override.json) in the NinjaRMMAgent directory.
- Add or Update Overrides: For other operations, the script:
- Checks for the existence of the customization folder and creates it if necessary.
- Reads existing overrides if Append is specified, updating them if the antivirus name matches or adding a new entry if it does not.
- Saves the new or updated override information in JSON format.
Error Handling and Logging
The script incorporates robust error handling, logging any issues encountered during file or directory operations and providing clear error messages to guide users.
Potential Use Cases
Hypothetical Scenario
An MSP managing a fleet of 500 devices notices that some endpoints report outdated antivirus definitions incorrectly due to compatibility issues. Using this script, the MSP can:
- Override the reported status to “Up-to-Date” for affected devices.
- Ensure compliance reports accurately reflect the organization’s security posture.
- Automate the process by integrating the script into their device management workflows.
This approach saves hours of manual updates while maintaining a standardized security configuration.
Comparisons to Other Methods
The script’s approach provides several advantages over manual or GUI-based configurations:
- Efficiency: Changes can be applied to multiple devices in seconds.
- Repeatability: The script can be reused with different parameters for various scenarios.
- Automation-Friendly: It can be integrated into broader IT management workflows, unlike manual methods.
Compared to advanced remote monitoring and management (RMM) tools, the script offers a lightweight alternative that doesn’t require specialized software for basic antivirus override tasks.
FAQs
- What happens if I don’t specify an antivirus name?
The script will terminate with an error, as the antivirus name is required unless removing overrides. - Can this script be used on older Windows versions?
No, the script is designed for Windows 10 and Windows Server 2016 or newer. - What should I do if I encounter a file permission error?
Ensure the script is executed with administrator privileges. - Is the override permanent?
The override persists until it is removed using the RemoveOverride parameter or manually deleted.
Implications of the Script’s Results
By accurately managing antivirus details, this script ensures that device security states are consistently reported. It mitigates the risk of compliance failures due to incorrect status reporting and helps organizations maintain a strong security posture. However, misusing overrides could result in devices being reported as secure when they are not, highlighting the need for careful and informed usage.
Recommendations for Best Practices
- Always verify the antivirus information before applying overrides.
- Use Append cautiously to avoid overwriting important details inadvertently.
- Run the script in a controlled environment or test its impact on a single device before deploying it across the fleet.
- Regularly review and update overrides to reflect the current state of devices accurately.
Final Thoughts
This PowerShell script provides IT professionals with a practical tool for managing antivirus configurations across endpoints. It is particularly valuable for environments managed via NinjaOne, where consistency and efficiency are paramount. By integrating this script into their workflows, MSPs and IT admins can streamline operations, ensure compliance, and maintain accurate security reporting.