Cómo automatizar Microsoft Safety Scanner mediante un script PowerShell

En el actual panorama informático, tan preocupado por la seguridad, garantizar que los sistemas permanezcan libres de malware y otras amenazas es una prioridad absoluta para los profesionales de TI y los proveedores de servicios gestionados (MSP). Aunque existen varias herramientas para lograrlo, la automatización de la detección y respuesta a las amenazas puede reducir significativamente el tiempo y el esfuerzo necesarios para mantener un entorno seguro.

Una de estas herramientas, que puede integrarse en un flujo de trabajo automatizado, es el Microsoft Safety Scanner (MSERT). En este post, exploraremos un script PowerShell que automatiza la descarga, ejecución y generación de informes de Microsoft Safety Scanner, facilitando a los profesionales de TI el mantenimiento de la seguridad de sus sistemas.

Contexto

Microsoft Safety Scanner es una herramienta gratuita de análisis on-demand diseñada para detectar y eliminar malware de sistemas Windows. Se actualiza con frecuencia y está pensada para entornos en los que se requieren las últimas definiciones de seguridad, pero en los que una solución siempre activa puede no ser factible.

El script del que hablaremos en este post agiliza el proceso de uso de MSERT automatizando su descarga, ejecución y gestión de resultados. Esto resulta especialmente útil en entornos en los que es necesario realizar exploraciones periódicas pero la intervención manual resulta poco práctica.

Para los profesionales de TI y los MSP, la posibilidad de automatizar este proceso reduce el riesgo de error humano, garantiza la coherencia en la ejecución de las exploraciones y deja un tiempo valioso para otras tareas. Este script es una poderosa herramienta para mantener un entorno de TI seguro con el mínimo esfuerzo.

El script para automatizar 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://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 {
    
    
     
}

 

Análisis detallado

El script PowerShell proporcionado está diseñado para automatizar varias tareas clave relacionadas con la ejecución de Microsoft Safety Scanner:

  1. Gestión de parámetros: el script comienza definiendo parámetros para el tipo de escaneo (Rápido o Completo), un período de tiempo de espera y un campo personalizado opcional donde se pueden guardar los resultados. Estos parámetros se establecen por defecto, pero también pueden ser anulados por variables de entorno, lo que permite un uso flexible en diferentes escenarios.
  2. Configuración del entorno: antes de continuar, el script comprueba si el usuario tiene los privilegios administrativos necesarios. Sin ellos, el script terminará, asegurando que sólo el personal autorizado pueda ejecutar escaneos potencialmente perjudiciales.
  3. Descarga de archivos: una de las principales funciones del script es descargar la última versión de MSERT de los servidores de Microsoft. De ello se encarga la función Invoke-Download, que admite TLS 1.2 y 1.3 para conexiones seguras. La función intenta descargar el archivo varias veces para tener en cuenta cualquier problema de red o limitación de velocidad por parte del servidor.
  4. Ejecución de la exploración: una vez descargado, el script inicia el escaneo utilizando los parámetros especificados. Puede realizar un escaneo rápido de las ubicaciones más comunes de los exploits o un escaneo completo de todo el disco, dependiendo de la elección del usuario. La exploración se realiza en modo silencioso para minimizar las interrupciones.
  5. Resultados de la gestión: una vez finalizado el análisis, el script procesa el archivo de registro generado por MSERT. Comprueba si se ha detectado alguna amenaza e imprime los resultados en la consola. Si se especifica, también guarda los resultados en un campo personalizado dentro de NinjaOne, que puede ser utilizado para su posterior análisis o presentación de informes.
  6. Limpieza: por último, el script elimina el ejecutable MSERT descargado y el archivo de registro para limpiar el sistema, asegurándose de que no quedan archivos innecesarios.

Posibles casos de uso

Imagínate una situación en la que un MSP es responsable de la seguridad de cientos de endpoints de varios clientes. Ejecutar manualmente análisis de malware en cada máquina llevaría mucho tiempo y sería ineficaz.

Al desplegar este script en todos los endpoints, el MSP puede garantizar que cada sistema se analice periódicamente en busca de amenazas y que los resultados se comuniquen automáticamente a su consola de gestión. Si se detecta una amenaza, el MSP puede responder rápidamente, minimizando el daño potencial y manteniendo un entorno seguro para sus clientes.

Comparaciones

El enfoque utilizado en este script para automatizar Microsoft Safety Scanner contrasta con los métodos manuales tradicionales de ejecución de MSERT. Normalmente, un profesional de TI tendría que descargar MSERT, ejecutarlo manualmente y luego revisar los resultados, pasos propensos a descuidos e incoherencias.

Al automatizar el proceso con PowerShell, el script garantiza que las exploraciones se realicen de manera uniforme y regular, reduciendo la posibilidad de errores humanos y asegurando que los protocolos de seguridad se sigan de manera coherente.

En comparación con otras soluciones automatizadas, como el software antivirus completo con protección en tiempo real, este script para automatizar Microsoft Safety Scanner ofrece una alternativa ligera y on-demand que puede integrarse en prácticas de seguridad más amplias. Resulta especialmente útil en entornos en los que no es posible o necesario ejecutar un software antivirus completo en todos los equipos.

FAQ

¿Qué ocurre si se agota el tiempo de espera del script durante una exploración?
Si el análisis supera el tiempo de espera especificado, el script finaliza el proceso y emite una alerta. Esto evita que la exploración se ejecute indefinidamente y afecte potencialmente al rendimiento del sistema.

2.  ¿Se puede utilizar el script en versiones anteriores de Windows?
El script requiere al menos Windows 10 o Server 2016. Es posible que las versiones antiguas de Windows no admitan algunas de las funciones utilizadas en el script, como TLS 1.2/1.3 o determinados cmdlets de PowerShell.

3. ¿Cómo gestiona el script los problemas de red durante la descarga?
La función Invoke-Download incluye múltiples intentos de descarga del ejecutable MSERT. Si la descarga falla tras varios intentos, el script mostrará un error y finalizará.

4.  ¿Es seguro ejecutar este script en un entorno de producción?
Sí, el script se ha diseñado pensando en la seguridad, incluyendo comprobaciones de privilegios administrativos y un tratamiento cuidadoso de los posibles errores. Sin embargo, siempre es recomendable probar los scripts en un entorno controlado antes de desplegarlos ampliamente.

Implicaciones

Los resultados de este script para automatizar Microsoft Safety Scanner pueden tener importantes implicaciones para la seguridad informática. Mediante la automatización de los análisis de malware, los equipos informáticos pueden garantizar que los sistemas se comprueban periódicamente en busca de amenazas, reduciendo el riesgo de infecciones no detectadas. Este enfoque proactivo de la seguridad puede ayudar a prevenir las violaciones de datos y otros incidentes de seguridad, que pueden tener graves consecuencias para las empresas, como pérdidas financieras y daños a la reputación.

Recomendaciones

Cuando utilices este script para automatizar Microsoft Safety Scanner, ten en cuenta las siguientes prácticas recomendadas:

  • Prueba el script en un entorno de laboratorio antes de desplegarlo en todos los endpoints para asegurarte de que funciona como se espera.
  • Programa escaneos regulares utilizando el Programador de Tareas de Windows u otra herramienta de automatización para asegurarte de que los sistemas están continuamente monitorizados.
  • Supervisa de cerca los resultados y establece alertas para cuando se detecten amenazas, de modo que puedas responder rápidamente.

Reflexiones finales

Este script PowerShell ofrece una potente forma de automatizar el uso de Microsoft Safety Scanner, proporcionando a los profesionales de TI y MSP una herramienta fiable para mantener la seguridad del sistema. Al integrarlo en prácticas de seguridad más amplias, los usuarios pueden garantizar que sus entornos permanezcan protegidos contra las amenazas de malware con una intervención manual mínima.

Categorías:

Quizá también te interese…

×

¡Vean a NinjaOne en acción!

Al enviar este formulario, acepto la política de privacidad de NinjaOne.

Términos y condiciones de NinjaOne

Al hacer clic en el botón “Acepto” que aparece a continuación, estás aceptando los siguientes términos legales, así como nuestras Condiciones de uso:

  • Derechos de propiedad: NinjaOne posee y seguirá poseyendo todos los derechos, títulos e intereses sobre el script (incluidos los derechos de autor). NinjaOne concede al usuario una licencia limitada para utilizar el script de acuerdo con estos términos legales.
  • Limitación de uso: solo podrás utilizar el script para tus legítimos fines personales o comerciales internos, y no podrás compartirlo con terceros.
  • Prohibición de republicación: bajo ninguna circunstancia está permitido volver a publicar el script en ninguna biblioteca de scripts que pertenezca o esté bajo el control de cualquier otro proveedor de software.
  • Exclusión de garantía: el script se proporciona “tal cual” y “según disponibilidad”, sin garantía de ningún tipo. NinjaOne no promete ni garantiza que el script esté libre de defectos o que satisfaga las necesidades o expectativas específicas del usuario.
  • Asunción de riesgos: el uso que el usuario haga del script corre por su cuenta y riesgo. El usuario reconoce que existen ciertos riesgos inherentes al uso del script, y entiende y asume cada uno de esos riesgos.
  • Renuncia y exención: el usuario no hará responsable a NinjaOne de cualquier consecuencia adversa o no deseada que resulte del uso del script y renuncia a cualquier derecho o recurso legal o equitativo que pueda tener contra NinjaOne en relación con su uso del script.
  • CLUF: si el usuario es cliente de NinjaOne, su uso del script está sujeto al Contrato de Licencia para el Usuario Final (CLUF).