Avec le contexte actuel de la sécurité informatique, les professionnels de l’informatique et les fournisseurs de services gérés (MSP) ont pour priorité de s’assurer que les systèmes sont exempts de logiciels malveillants et d’autres menaces. Bien qu’il existe plusieurs outils pour y parvenir, l’automatisation de la détection et de la réponse aux menaces peut réduire de manière significative le temps et les efforts nécessaires au maintien d’un environnement sécurisé.
Le scanner de sécurité Microsoft ou Microsoft Safety Scanner (MSERT) est un outil de ce type qui peut être intégré dans un flux de travail automatisé. Dans cet article, nous allons explorer un script PowerShell qui automatise le téléchargement, l’exécution et la création de rapports MSERT, ce qui permet aux professionnels de l’informatique de garder leurs systèmes en sécurité plus facilement.
Contexte
Microsoft Safety Scanner est un outil d’analyse gratuit et à la demande conçu pour détecter et supprimer les logiciels malveillants (malware) des systèmes Windows. Il est fréquemment mis à jour et est destiné à être utilisé dans des environnements où les définitions de sécurité les plus récentes sont nécessaires, mais où une solution permanente n’est pas envisageable.
Le script dont nous allons parler dans ce billet rationalise le processus d’utilisation de MSERT en automatisant son téléchargement, son exécution et le traitement des résultats. Cette fonction est particulièrement utile dans les environnements où des analyses régulières sont nécessaires, mais où l’intervention manuelle n’est pas pratique.
Pour les professionnels de l’informatique et les MSP, la possibilité d’automatiser ce processus réduit le risque d’erreur humaine, garantit la cohérence des analyses et libère un temps précieux pour d’autres tâches. Ce script est un outil puissant pour maintenir un environnement informatique sécurisé avec un minimum d’efforts.
Le script :
#Requires -Version 5.1 <# .SYNOPSIS Run the Microsoft Safety Scanner, collect the results, and optionally save the results to a multiline custom field. .DESCRIPTION Run the Microsoft Safety Scanner, collect the results, and optionally save the results to a multiline custom field. .EXAMPLE (No Parameters) Downloading MSERT from https://go.microsoft.com/fwlink/?LinkId=212732 Waiting for 3 seconds. Download Attempt 1 Download Successful! Initiating Scan Exit Code: 7 [Critical] Infections found! --------------------------------------------------------------------------------------- Microsoft Safety Scanner v1.405, (build 1.405.445.0) Started On Thu Feb 22 13:33:34 2024 Engine: 1.1.24010.10 Signatures: 1.405.445.0 MpGear: 1.1.16330.1 Run Mode: Scan Run in Quiet Mode Quick Scan Results: ------------------- Threat Detected: Virus:DOS/EICAR_Test_File, not removed. Action: NoAction, Result: 0x00000000 file://C:\Windows\system32\eicarcom2.zip->eicar_com.zip->eicar.com SigSeq: 0x00000555DC2DDDB0 file://C:\Windows\system32\eicar.com SigSeq: 0x00000555DC2DDDB0 file://C:\Windows\eicar.com SigSeq: 0x00000555DC2DDDB0 containerfile://C:\Windows\system32\eicarcom2.zip Results Summary: ---------------- Found Virus:DOS/EICAR_Test_File, not removed. Successfully Submitted MAPS Report Successfully Submitted Heartbeat Report Microsoft Safety Scanner Finished On Thu Feb 22 13:35:58 2024 Return code: 7 (0x7) PARAMETER: -ScanType "Full" Specifies the type of scan to perform. "Full" for a complete disk scan, or "Quick" for a scan of common exploit locations. PARAMETER: -Timeout "ReplaceMeWithANumber" Sets a time limit for the scan in minutes. If the scan exceeds this duration, it is canceled, and an error is output. Replace "ReplaceMeWithANumber" with the desired time limit in minutes. PARAMETER: -CustomField "ReplaceWithNameOfCustomField" Specifies the name of the multiline custom field where scan results are optionally saved. Enter the field name to enable this feature. .OUTPUTS None .NOTES Minimum OS Architecture Supported: Windows 10, Server 2016 Release Notes: Initial Release By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://ninjastage2.wpengine.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). #> [CmdletBinding()] param ( [Parameter()] [String]$ScanType = "Quick", [Parameter()] [Int]$Timeout = 30, [Parameter()] [String]$CustomField, [Parameter()] [String]$DownloadURL = "https://go.microsoft.com/fwlink/?LinkId=212732" ) begin { # Set parameters using dynamic script variables. if($env:scanType -and $env:scanType -notlike "null"){ $ScanType = $env:scanType } if($env:scanTimeoutInMinutes -and $env:scanTimeoutInMinutes -notlike "null"){ $Timeout = $env:scanTimeoutInMinutes } if($env:customFieldName -and $env:customFieldName -notlike "null"){ $CustomField = $env:customFieldName } # If a timeout is specified, check that it's in the valid range. if($Timeout -lt 1 -or $Timeout -ge 120){ Write-Host "[Error] Timeout must be greater than or equal to 1 minute and less than 120 minutes." exit 1 } # If we're not given a scan type, error out. if(-not $ScanType){ Write-Host "[Error] Please select a scan type (Quick or Full)." exit 1 } # Check that the scan type is valid. switch($ScanType){ "Quick" { Write-Verbose "Quick Scan Selected!"} "Full" { Write-Verbose "Full Scan Selected!" } default { Write-Host "[Error] Invalid scan type selected!" exit 1 } } # Checks for local administrator rights. function Test-IsElevated { $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object System.Security.Principal.WindowsPrincipal($id) $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) } # Utility function for downloading files. function Invoke-Download { param( [Parameter()] [String]$URL, [Parameter()] [String]$Path, [Parameter()] [int]$Attempts = 3, [Parameter()] [Switch]$SkipSleep ) $SupportedTLSversions = [enum]::GetValues('Net.SecurityProtocolType') if ( ($SupportedTLSversions -contains 'Tls13') -and ($SupportedTLSversions -contains 'Tls12') ) { [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol::Tls13 -bor [System.Net.SecurityProtocolType]::Tls12 } elseif ( $SupportedTLSversions -contains 'Tls12' ) { [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 } else { # Not everything requires TLS 1.2, but we'll try anyway. Write-Warning "TLS 1.2 and or TLS 1.3 are not supported on this system. This download may fail!" if ($PSVersionTable.PSVersion.Major -lt 3) { Write-Warning "PowerShell 2 / .NET 2.0 doesn't support TLS 1.2." } } $i = 1 While ($i -le $Attempts) { # Some cloud services have rate-limiting if (-not ($SkipSleep)) { $SleepTime = Get-Random -Minimum 3 -Maximum 15 Write-Host "Waiting for $SleepTime seconds." Start-Sleep -Seconds $SleepTime } if ($i -ne 1) { Write-Host "" } Write-Host "Download Attempt $i" $PreviousProgressPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' try { # Invoke-WebRequest is preferred because it supports links that redirect, e.g., https://t.ly if ($PSVersionTable.PSVersion.Major -lt 4) { # Downloads the file $WebClient = New-Object System.Net.WebClient $WebClient.DownloadFile($URL, $Path) } else { # Standard options $WebRequestArgs = @{ Uri = $URL OutFile = $Path MaximumRedirection = 10 UseBasicParsing = $true } # Downloads the file Invoke-WebRequest @WebRequestArgs } $ProgressPreference = $PreviousProgressPreference $File = Test-Path -Path $Path -ErrorAction SilentlyContinue } catch { Write-Warning "An error has occurred while downloading!" Write-Warning $_.Exception.Message if (Test-Path -Path $Path -ErrorAction SilentlyContinue) { Remove-Item $Path -Force -Confirm:$false -ErrorAction SilentlyContinue } $File = $False } if ($File) { $i = $Attempts } else { Write-Warning "File failed to download." Write-Host "" } $i++ } if (-not (Test-Path -Path $Path)) { [PSCustomObject]@{ ExitCode = 1 } } else { [PSCustomObject]@{ ExitCode = 0 } } } # Utility function to help set custom fields function Set-NinjaProperty { [CmdletBinding()] Param( [Parameter(Mandatory = $True)] [String]$Name, [Parameter()] [String]$Type, [Parameter(Mandatory = $True, ValueFromPipeline = $True)] $Value, [Parameter()] [String]$DocumentName ) $Characters = $Value | Measure-Object -Character | Select-Object -ExpandProperty Characters if($Characters -ge 10000){ throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded, value is greater than 10,000 characters.") } # If we're requested to set the field value for a Ninja document we'll specify it here. $DocumentationParams = @{} if ($DocumentName) { $DocumentationParams["DocumentName"] = $DocumentName } # This is a list of valid fields that can be set. If no type is given, it will be assumed that the input doesn't need to be changed. $ValidFields = "Attachment", "Checkbox", "Date", "Date or Date Time", "Decimal", "Dropdown", "Email", "Integer", "IP Address", "MultiLine", "MultiSelect", "Phone", "Secure", "Text", "Time", "URL", "WYSIWYG" if ($Type -and $ValidFields -notcontains $Type) { Write-Warning "$Type is an invalid type! Please check here for valid types. https://ninjarmm.zendesk.com/hc/en-us/articles/16973443979789-Command-Line-Interface-CLI-Supported-Fields-and-Functionality" } # The field below requires additional information to be set $NeedsOptions = "Dropdown" if ($DocumentName) { if ($NeedsOptions -contains $Type) { # We'll redirect the error output to the success stream to make it easier to error out if nothing was found or something else went wrong. $NinjaPropertyOptions = Ninja-Property-Docs-Options -AttributeName $Name @DocumentationParams 2>&1 } } else { if ($NeedsOptions -contains $Type) { $NinjaPropertyOptions = Ninja-Property-Options -Name $Name 2>&1 } } # If an error is received it will have an exception property, the function will exit with that error information. if ($NinjaPropertyOptions.Exception) { throw $NinjaPropertyOptions } # The below type's require values not typically given in order to be set. The below code will convert whatever we're given into a format ninjarmm-cli supports. switch ($Type) { "Checkbox" { # While it's highly likely we were given a value like "True" or a boolean datatype it's better to be safe than sorry. $NinjaValue = [System.Convert]::ToBoolean($Value) } "Date or Date Time" { # Ninjarmm-cli expects the Date-Time to be in Unix Epoch time so we'll convert it here. $Date = (Get-Date $Value).ToUniversalTime() $TimeSpan = New-TimeSpan (Get-Date "1970-01-01 00:00:00") $Date $NinjaValue = $TimeSpan.TotalSeconds } "Dropdown" { # Ninjarmm-cli is expecting the guid of the option we're trying to select. So we'll match up the value we were given with a guid. $Options = $NinjaPropertyOptions -replace '=', ',' | ConvertFrom-Csv -Header "GUID", "Name" $Selection = $Options | Where-Object { $_.Name -eq $Value } | Select-Object -ExpandProperty GUID if (-not $Selection) { throw [System.ArgumentOutOfRangeException]::New("Value is not present in dropdown") } $NinjaValue = $Selection } default { # All the other types shouldn't require additional work on the input. $NinjaValue = $Value } } # We'll need to set the field differently depending on if its a field in a Ninja Document or not. if ($DocumentName) { $CustomField = Ninja-Property-Docs-Set -AttributeName $Name -AttributeValue $NinjaValue @DocumentationParams 2>&1 } else { $CustomField = Ninja-Property-Set -Name $Name -Value $NinjaValue 2>&1 } if ($CustomField.Exception) { throw $CustomField } } $ExitCode = 0 # If the log file already exists remove it. if(Test-Path -Path "$env:SYSTEMROOT\debug\msert.log"){ Remove-Item -Path "$env:SYSTEMROOT\debug\msert.log" -Force -ErrorAction SilentlyContinue } } process { # Error out if we don't have local admin permissions. if (-not (Test-IsElevated)) { Write-Host "[Error] Access Denied. Please run with Administrator privileges." exit 1 } # Download MSERT. Write-Host "Downloading MSERT from $DownloadURL" $MSERTPath = "$env:TEMP\MSERT.exe" $Download = Invoke-Download -Path $MSERTPath -URL $DownloadURL if($Download.ExitCode -ne 0){ Write-Host "[Error] Failed to download MSERT please check that $DownloadURL is reachable!" exit 1 } Write-Host "Download Successful!" # Start the MSERT Scan with the parameters given. Write-Host "Initiating Scan" $Arguments = New-Object System.Collections.Generic.List[string] if($ScanType -eq "Full"){ $Arguments.Add("/F") } $Arguments.Add("/Q") $Arguments.Add("/N") try{ # Run it with our specified timeout. $TimeoutInSeconds = $Timeout * 60 $MSERTProcess = Start-Process -FilePath $MSERTPath -ArgumentList $Arguments -NoNewWindow -PassThru $MSERTProcess | Wait-Process -Timeout $TimeoutInSeconds -ErrorAction Stop }catch{ Write-Host "[Alert] The Microsoft Safety Scanner exceeded the specified timeout of $Timeout minutes, and the script is now terminating." $MSERTProcess | Stop-Process -Force $TimedOut = $True $ExitCode = 1 } Write-Host "Exit Code: $($MSERTProcess.ExitCode)" # If the report is missing, something has clearly gone wrong. if(-not (Test-Path -Path $env:SYSTEMROOT\debug\msert.log)){ Write-Host "[Error] The report from MSERT.exe is missing?" exit 1 } # Get the contents of the MSERT log and error out if it's blank. $Report = Get-Content -Path "$env:SYSTEMROOT\debug\msert.log" if(-not $Report){ Write-Host "[Error] The report from MSERT.exe is empty?" exit 1 } # If threats are detected, send out the alert. $Report | ForEach-Object { if($_ -match "No infection found"){ $NoInfectionFoundTextPresent = $True } if($_ -match "Threat Detected" ){ $ThreatDetectedTextPresent = $True } } if(($ThreatDetectedTextPresent -or -not $NoInfectionFoundTextPresent) -and -not $TimedOut){ Write-Host "[Critical] Infections found!" }elseif($ExitCode -ne 1 -and -not $TimedOut){ Write-Host "[Success] Scan has completed no infections detected." } # Save to a custom field upon request. if($CustomField){ try { Write-Host "Attempting to set Custom Field '$CustomField'." Set-NinjaProperty -Name $CustomField -Value ($Report | Out-String) Write-Host "Successfully set Custom Field '$CustomField'!" } catch { if($_.Exception.Message){ Write-Host "[Error] $($_.Exception.Message)" } if($_.Message){ Write-Host "[Error] $($_.Message)" } $ExitCode = 1 } } # Send out the report to the activity log. $Report | Write-Host # Remove the old log file. if(Test-Path -Path "$env:SYSTEMROOT\debug\msert.log"){ Remove-Item -Path "$env:SYSTEMROOT\debug\msert.log" -Force -ErrorAction SilentlyContinue } # Exit. exit $ExitCode } end { }
Description détaillée
Le script PowerShell fourni est conçu pour automatiser plusieurs tâches clés liées à l’exécution de Microsoft Safety Scanner :
- Traitement des paramètres : Le script commence par définir des paramètres pour le type d’analyse (rapide ou complète), un délai d’attente et un champ personnalisé facultatif dans lequel les résultats peuvent être enregistrés. Ces paramètres sont définis par défaut, mais peuvent également être remplacés par des variables d’environnement, ce qui permet une utilisation flexible dans différents scénarios.
- Configuration de l’environnement: Avant de poursuivre, le script vérifie si l’utilisateur dispose des privilèges administratifs nécessaires. Sans cela, le script s’arrêtera, ce qui garantit que seul le personnel autorisé peut exécuter des analyses potentiellement perturbatrices.
- Téléchargement de fichiers: L’une des principales fonctions du script consiste à télécharger la dernière version de MSERT à partir des serveurs de Microsoft. Cette opération est gérée par la fonction Invoke-Download, qui prend en charge les protocoles TLS 1.2 et 1.3 pour les connexions sécurisées. La fonction tente de télécharger le fichier plusieurs fois pour tenir compte d’éventuels problèmes de réseau ou de limitation du débit par le serveur.
- Exécution de l’analyse: Une fois téléchargé, le script lance l’analyse à l’aide des paramètres spécifiés. Il peut effectuer une analyse rapide des emplacements d’exploitation courants ou une analyse complète du disque entier, selon le choix de l’utilisateur. L’analyse est effectuée en mode silencieux afin de minimiser les interruptions.
- Résultats: Une fois l’analyse terminée, le script traite le fichier journal généré par MSERT. Il vérifie si des menaces ont été détectées et affiche les résultats sur la console. Si cela est spécifié, il enregistre également les résultats dans un champ personnalisé de NinjaOne, qui peut être utilisé pour des analyses ou des rapports supplémentaires.
- Nettoyage: Enfin, le script supprime l’exécutable MSERT téléchargé et le fichier journal pour nettoyer le système, en veillant à ne pas laisser de fichiers inutiles.
Cas d’utilisation potentiels
Imaginez un scénario dans lequel une entreprise MSP est responsable de la sécurité de centaines de terminaux chez plusieurs clients. Lancer manuellement des analyses de logiciels malveillants sur chaque machine prendrait beaucoup de temps et serait inefficace.
En déployant ce script sur tous les terminaux, l’entreprise MSP peut s’assurer que chaque système est régulièrement analysé à la recherche de menaces, les résultats étant automatiquement transmis à sa console de gestion. Si une menace est détectée, l’entreprise MSP peut réagir rapidement, en minimisant les dommages potentiels et en maintenant un environnement sécurisé pour ses clients.
Comparaisons
L’approche utilisée dans ce script contraste avec les méthodes traditionnelles et manuelles d’exécution de Microsoft Safety Scanner. Normalement, un professionnel de l’informatique devrait télécharger MSERT, l’exécuter manuellement, puis examiner les résultats – des étapes qui sont sujettes à des oublis et à des incohérences.
En automatisant le processus à l’aide de PowerShell, le script garantit que les analyses sont effectuées de manière uniforme et régulière, ce qui réduit le risque d’erreur humaine et garantit que les protocoles de sécurité sont toujours respectés.
Par rapport à d’autres solutions automatisées, telles qu’un logiciel antivirus complet avec protection en temps réel, ce script offre une alternative légère, à la demande, qui peut être intégrée dans des pratiques de sécurité plus grandes. Il est particulièrement utile dans les environnements où il n’est pas possible ou nécessaire d’installer un logiciel antivirus complet sur chaque machine.
FAQ
1. Que se passe-t-il si le script s’interrompt au cours d’une analyse ?
Si l’analyse dépasse le délai spécifié, le script met fin au processus et émet une alerte. Cela permet d’éviter que l’analyse ne s’exécute indéfiniment et n’affecte les performances du système.
2. Le script peut-il être utilisé sur d’anciennes versions de Windows ?
Le script nécessite au moins Windows 10 ou Server 2016. Les anciennes versions de Windows peuvent ne pas prendre en charge certaines des fonctionnalités utilisées dans le script, telles que TLS 1.2/1.3 ou certaines cmdlets PowerShell.
3. Comment le script gère-t-il les problèmes de réseau pendant le téléchargement ?
La fonction Invoke-Download comprend plusieurs tentatives de téléchargement de l’exécutable MSERT. Si le téléchargement échoue après plusieurs tentatives, le script affiche une erreur et se termine.
4. Est-il possible d’exécuter ce script en toute sécurité dans un environnement de production ?
Oui, le script est conçu dans un souci de sécurité, notamment en vérifiant les privilèges d’administration et en traitant avec soin les erreurs potentielles. Toutefois, il est toujours recommandé de tester les scripts dans un environnement contrôlé avant de les déployer à grande échelle.
Implications
Les résultats de ce script peuvent avoir des conséquences importantes pour la sécurité informatique. En automatisant la recherche de logiciels malveillants, les équipes informatiques peuvent s’assurer que les systèmes sont régulièrement contrôlés pour détecter les menaces, réduisant ainsi le risque d’infections non détectées. Cette approche proactive de la sécurité peut contribuer à prévenir les violations de données et autres incidents de sécurité, qui peuvent avoir de graves conséquences pour les entreprises, notamment des pertes financières et une atteinte à leur réputation.
Recommandations
Lors de l’utilisation de ce script, il est important de suivre les bonnes pratiques suivantes :
- Testez le script dans un environnement de test avant de le déployer sur tous les terminaux pour vous assurer qu’il fonctionne comme prévu.
- Planifiez des analyses régulières à l’aide du planificateur de tâches de Windows ou d’un autre outil d’automatisation afin de garantir une surveillance continue des systèmes.
- Surveillez de près les résultats obtenus et implémentez des alertes en cas de détection de menaces afin de pouvoir réagir rapidement.
Conclusion
Ce script PowerShell offre un moyen puissant d’automatiser l’utilisation du scanner de sécurité Microsoft (Microsoft Safety Scanner), fournissant aux professionnels de l’informatique et aux MSP un outil fiable pour maintenir la sécurité du système. En l’intégrant à des pratiques de sécurité plus grandes, les utilisateurs peuvent s’assurer que leurs environnements restent protégés contre les menaces de logiciels malveillants avec une intervention manuelle minimale