Nell’odierno panorama IT attento alla sicurezza, garantire che i sistemi rimangano liberi da malware e altre minacce è una priorità assoluta per i professionisti IT e i Managed Service Provider (MSP). Sebbene siano disponibili diversi strumenti per raggiungere questo obiettivo, l’automazione del rilevamento e della risposta alle minacce può ridurre in modo significativo il tempo e l’impegno necessari per mantenere un ambiente sicuro.
Uno di questi strumenti che può essere integrato in un flusso di lavoro automatizzato è Microsoft Safety Scanner (MSERT). In questo post analizzeremo uno script PowerShell che automatizza il download, l’esecuzione e la creazione di report di MSERT, rendendo più semplice per i professionisti IT mantenere i propri sistemi sicuri.
Background
Microsoft Safety Scanner è uno strumento gratuito di scansione on-demand progettato per rilevare e rimuovere i malware dai sistemi Windows. Viene aggiornato frequentemente ed è progettato per essere utilizzato in ambienti in cui sono necessarie le definizioni di sicurezza più recenti, ma in cui una soluzione always-on potrebbe non essere possibile da implementare.
Lo script per automatizzare Microsoft Safety Scanner di cui parleremo in questo post semplifica il processo di utilizzo di MSERT automatizzandone il download, l’esecuzione e la gestione dei risultati. È particolarmente utile negli ambienti in cui è necessario effettuare scansioni regolari, ma dove non risulta pratico intervenire manualmente.
Per i professionisti IT e gli MSP, la possibilità di automatizzare Microsoft Safety Scanner riduce il rischio di errori umani, garantisce la coerenza delle modalità di esecuzione delle scansioni e libera tempo prezioso per altre attività. Questo script è uno strumento potente per mantenere un ambiente IT sicuro con il minimo sforzo.
Lo script per automatizzare Microsoft Safety Scanner:
#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://www.ninjaone.com/it/condizioni-utilizzo 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 { }
Accedi a oltre 700 script nel Dojo NinjaOne
Analisi dettagliata
Lo script PowerShell fornito è progettato per automatizzare diverse attività chiave relative all’esecuzione di Microsoft Safety Scanner:
- Gestione dei parametri: Lo script per automatizzare Microsoft Safety Scanner inizia definendo i parametri per il tipo di scansione (rapida o completa), un periodo di timeout e un campo personalizzato opzionale in cui salvare i risultati. Questi parametri sono impostati con valori predefiniti, ma possono anche essere sovrascritti da variabili d’ambiente, consentendo un uso flessibile in diversi scenari.
- Impostazione dell’ambiente: Prima di procedere, lo script per automatizzare Microsoft Safety Scanner controlla che l’utente abbia i privilegi amministrativi necessari. In mancanza di questi, lo script si interrompe, garantendo che solo il personale autorizzato possa eseguire scansioni che potrebbero potenzialmente interrompere i flussi di lavoro.
- Download del file: Una delle funzioni principali dello script per automatizzare Microsoft Safety Scanner è scaricare l’ultima versione di MSERT dai server di Microsoft. Questa azione viene gestita dalla funzione Invoke-Download, che supporta TLS 1.2 e 1.3 per le connessioni sicure. La funzione tenta di scaricare il file più volte per tenere conto di eventuali problemi di rete o di limitazione della velocità da parte del server.
- Esecuzione della scansione: Una volta scaricato, lo script per automatizzare Microsoft Safety Scanner avvia la scansione utilizzando i parametri specificati. Può eseguire una scansione rapida delle posizioni più comuni degli exploit o una scansione completa dell’intero disco, a seconda della scelta dell’utente. La scansione viene eseguita in modalità silenziosa per ridurre al minimo le interruzioni.
- Gestione dei risultati: Al termine della scansione, lo script elabora il file di log generato da MSERT. Verifica la presenza di eventuali minacce rilevate e stampa i risultati nella console. Se specificato, salva anche i risultati in un campo personalizzato all’interno di NinjaOne, che può essere utilizzato per ulteriori analisi o report.
- Pulizia: Infine, lo script rimuove l’eseguibile MSERT scaricato e il file di log per ripulire il sistema, assicurandosi che non vengano lasciati file inutili.
Casi d’uso potenziali
Immagina uno scenario in cui un MSP è responsabile della sicurezza di centinaia di endpoint di più clienti. Eseguire manualmente le scansioni del malware su ogni computer sarebbe dispendioso in termini di tempo e inefficiente.
Distribuendo su tutti gli endpoint questo script per automatizzare Microsoft Safety Scanner, l’MSP può garantire che ogni sistema venga regolarmente sottoposto a scansione alla ricerca di minacce, con i risultati riportati automaticamente nella console di gestione. Se viene rilevata una minaccia, l’MSP può rispondere rapidamente, riducendo al minimo il danno potenziale e mantenendo un ambiente sicuro per i propri clienti.
Confronti
L’approccio utilizzato in questo script per automatizzare Microsoft Safety Scanner è diverso rispetto ai metodi tradizionali e manuali di esecuzione dello strumento Microsoft. Tradizionalmente, un professionista dell’IT dovrebbe scaricare MSERT, eseguirlo manualmente e poi esaminare i risultati, operazioni che sono soggette a sviste e incoerenze.
Automatizzando il processo con PowerShell, lo script assicura che le scansioni vengano eseguite in modo uniforme e regolare, riducendo la possibilità di errore umano e garantendo che i protocolli di sicurezza vengano seguiti in modo coerente.
Rispetto ad altre soluzioni automatizzate, come un software antivirus completo con protezione in tempo reale, questo script per automatizzare Microsoft Safety Scanner offre un’alternativa leggera e on-demand che può essere integrata in pratiche di sicurezza più ampie. È particolarmente utile negli ambienti in cui l’esecuzione di un software antivirus completo su ogni computer potrebbe non essere attuabile o necessaria.
Domande frequenti
1. Cosa succede se lo script per automatizzare Microsoft Safety Scanner si interrompe durante una scansione?
Se la scansione supera il periodo di timeout specificato, lo script termina il processo ed emette un avviso. In questo modo si evita che la scansione venga eseguita all’infinito, con un potenziale impatto sulle prestazioni del sistema.
2. Lo script può essere utilizzato su versioni precedenti di Windows?
Lo script per automatizzare Microsoft Safety Scanner richiede almeno Windows 10 o Server 2016. Le versioni più vecchie di Windows potrebbero non supportare alcune delle funzioni utilizzate nello script, come TLS 1.2/1.3 o alcuni cmdlet PowerShell.
3. Come gestisce lo script i problemi di rete durante il download?
La funzione Invoke-Download prevede più tentativi di scaricare l’eseguibile MSERT. Se il download non riesce dopo diversi tentativi, lo script genera un errore e termina.
4. È sicuro eseguire questo script in un ambiente di produzione?
Sì, lo script per automatizzare Microsoft Safety Scanner è stato progettato tenendo conto della sicurezza, con controlli dei privilegi amministrativi e un’attenta gestione dei potenziali errori. Tuttavia, è sempre consigliabile testare gli script in un ambiente controllato prima di distribuirli su larga scala.
Implicazioni
I risultati di questo script per automatizzare Microsoft Safety Scanner possono avere implicazioni significative per la sicurezza informatica. Automatizzando le scansioni di malware, i team IT possono garantire che i sistemi vengano controllati regolarmente per individuare le minacce, riducendo il rischio di infezioni non rilevate. Questo approccio proattivo alla sicurezza può aiutare a prevenire le violazioni dei dati e altri incidenti di sicurezza, che potrebbero avere gravi conseguenze per le aziende, tra cui perdite finanziarie e danni alla reputazione.
Raccomandazioni
Quando utilizzi questo script per automatizzare Microsoft Safety Scanner, tieni a mente le seguenti best practice:
- Testa lo script in un ambiente controllato prima di distribuirlo su tutti gli endpoint, per assicurarti che funzioni come previsto.
- Pianifica scansioni regolari utilizzando Windows Task Scheduler o un altro strumento di automazione, per garantire un monitoraggio continuo dei sistemi.
- Monitora i risultati attentamente e imposta degli avvisi quando vengono rilevate delle minacce, in modo da poter rispondere rapidamente.
Considerazioni finali
Questo script PowerShell offre un modo efficace per automatizzare Microsoft Safety Scanner, fornendo ai professionisti IT e agli MSP uno strumento affidabile per mantenere la sicurezza del sistema. Integrandolo in pratiche di sicurezza più ampie, gli utenti possono garantire che i loro ambienti rimangano protetti dalle minacce malware con un intervento manuale minimo.