Guide d’utilisation de PowerShell pour créer des rapports sur les extensions de fichiers pour la gestion informatique

Dans le monde numérique actuel, la gestion des fichiers est cruciale pour les professionnels de l’informatique et les fournisseurs de services gérés (MSP). La possibilité de générer des rapports complets basés sur les extensions de fichiers dans des répertoires spécifiques permet d’améliorer les opérations, de renforcer la sécurité et d’aider à maintenir l’hygiène du système. Cet article présente un script PowerShell conçu pour automatiser cette tâche, afin que les professionnels de l’informatique puissent localiser et documenter les fichiers par extension dans différents répertoires en toute simplicité.

Contexte 

Les scripts PowerShell sont des outils inestimables pour les administrateurs informatiques, car ils fournissent l’automatisation nécessaire pour traiter des tâches complexes avec précision et facilité. Ce script particulier se concentre sur la génération de rapports détaillés sur les extensions de fichiers dans les répertoires et leurs sous-répertoires spécifiés par l’utilisateur. Grâce à ce script, les professionnels de l’informatique peuvent rapidement identifier des types de fichiers particuliers, ce qui facilite les tâches telles que les audits de logiciels, les contrôles de conformité et les évaluations de sécurité.

Le script

#Requires -Version 5.1

<#
.SYNOPSIS
    Creates a report based on the files found in the directory or subdirectory you specified with your desired extension.
.DESCRIPTION
    Creates a report based on the files found in the directory or subdirectory you specified with your desired extension.
.EXAMPLE
    -Extensions ".exe" -SearchPaths "C:\Users\tuser\Downloads"
    
    Searching C:\Users\tuser\Downloads for files with extension '.exe'...
    No files found with extension .exe!


PARAMETER: -Extensions "exe, .ico"
    A comma-separated list of extensions to search for. You can use the * character as a wildcard.

PARAMETER: -SearchPaths "C:\Replace\Me\With\Valid\Path"
    Enter the starting directories for the search, separated by commas. This will include all subdirectories as well.

PARAMETER: -MultiLineField "ReplaceMeWithNameOfMultilineCustomField"
    Optional multiline field to record search results. Leave blank if unused.

PARAMETER: -WysiwygField "ReplaceMeWithNameOfWYSIWYGCustomField"
    Optional WYSIWYG field to record search results. Leave blank if unused.

PARAMETER: -ScanSystemDrive
    This will set the system drive (usually drive C:\) as the starting point for the search.

PARAMETER: -ScanAllDrives
    This will set all drives (including flash drives) as the starting point for the search.
.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows 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/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]$Extensions,
    [Parameter()]
    [String]$SearchPaths,
    [Parameter()]
    [String]$MultiLineField,
    [Parameter()]
    [String]$WysiwygField,
    [Parameter()]
    [Switch]$ScanSystemDrive = [System.Convert]::ToBoolean($env:scanSystemDrive),
    [Parameter()]
    [Switch]$ScanAllDrives = [System.Convert]::ToBoolean($env:scanAllDrives)
)
begin {
    # Set parameters using dynamic script variables.
    if ($env:fileExtension -and $env:fileExtension -notlike "null") { $Extensions = $env:fileExtension }
    if ($env:searchPath -and $env:searchPath -notlike "null") { $SearchPaths = $env:searchPath }
    if ($env:multilineCustomField -and $env:multilineCustomField -notlike "null") { $MultiLineField = $env:multilineCustomField }
    if ($env:wysiwygCustomField -and $env:wysiwygCustomField -notlike "null") { $WysiwygField = $env:wysiwygCustomField }

    # Check if no extensions were specified and exit with an error if true.
    if (-not $Extensions) {
        Write-Host -Object "[Error] Missing extension to search for!"
        exit 1
    }

    # Verify that WysiwygField and MultiLineField are not the same, exiting with an error if they are.
    if ($WysiwygField -and $MultiLineField -and ($WysiwygField -eq $MultiLineField)) {
        Write-Host -Object "[Error] Wysiwyg Field and Multiline Field are the same! Custom fields cannot be the same type."
        Write-Host -Object "https://ninjarmm.zendesk.com/hc/en-us/articles/18601842971789-Custom-Fields-by-Type-and-Functionality"
        exit 1
    }

    # Initialize a list to store the extensions to search for.
    $ExtensionsToSearch = New-Object System.Collections.Generic.List[string]
    # Split the extensions if they are comma-separated and trim whitespace.
    if ($Extensions -match ",") {
        $Extensions -split "," | ForEach-Object { $ExtensionsToSearch.Add($_.Trim()) }
    }
    else {
        $ExtensionsToSearch.Add($Extensions.Trim())
    }
    
    # Initialize a list to keep track of extensions that need to be replaced (adding a leading dot if missing).
    $ExtensionsToReplace = New-Object System.Collections.Generic.List[object]
    $ExtensionsToSearch | ForEach-Object {
        if ($_ -notmatch "^\.") {
            $NewExtension = ".$_"

            $ExtensionsToReplace.Add(
                [PSCustomObject]@{
                    Index        = $ExtensionsToSearch.IndexOf("$_")
                    NewExtension = $NewExtension
                }
            )
                
            Write-Warning "Missing . for extension. Changing extension search to '$NewExtension'."
        }
    }

    # Apply the replacements for extensions that were missing a leading dot.
    $ExtensionsToReplace | ForEach-Object {
        $ExtensionsToSearch[$_.index] = $_.NewExtension 
    }

    # Check if no search locations were specified and exit with an error if true.
    if (!$SearchPaths -and !$ScanSystemDrive -and !$ScanAllDrives) {
        Write-Host -Object "[Error] Missing somewhere to search!"
        exit 1
    }

    # If scanning all drives, ignore specific paths and the system drive flag.
    if ($ScanAllDrives) {
        $ScanSystemDrive = $false
        $SearchPaths = $Null
    }

    # Initialize a list for paths to search.
    $PathsToSearch = New-Object System.Collections.Generic.List[string]
    # Split the search paths if they are comma-separated and trim whitespace.
    if ($SearchPaths -match ",") {
        $SearchPaths -split "," | ForEach-Object { $PathsToSearch.Add($_.Trim()) }
    }
    elseif ($SearchPaths) {
        $PathsToSearch.Add($SearchPaths)
    }

    # Add the system drive to the search paths if specified.
    if ($ScanSystemDrive) {
        if ($env:SystemDrive -notmatch '^[A-Z]:\\$' -and $env:SystemDrive -match '^[A-Z]:$') {
            $PathsToSearch.Add("$env:SystemDrive\")
        }
        else {
            $PathsToSearch.Add($env:SystemDrive)
        }
    }

    # Add all filesystem drives to the search paths if scanning all drives.
    if ($ScanAllDrives) {
        Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Free -and $_.Used } | ForEach-Object {
            if ($_.Root -notmatch '^[A-Z]:\\$' -and $_.Root -match '^[A-Z]:$') {
                $PathsToSearch.Add("$($_.Root)\")
            }
            else {
                $PathsToSearch.Add($_.Root)
            }
        }
    }

    # Initialize a list for paths that need to be corrected (adding a trailing backslash if missing).
    $ReplacementPaths = New-Object System.Collections.Generic.List[Object]

    # Check each path and add a backslash if it's missing.
    $PathsToSearch | ForEach-Object {
        if ($_ -notmatch '^[A-Z]:\\$' -and $_ -match '^[A-Z]:$') {
            $NewPath = "$_\"
            $ReplacementPaths.Add(
                [PSCustomObject]@{
                    Index   = $PathsToSearch.IndexOf("$_")
                    NewPath = $NewPath
                }
            )
                
            Write-Warning "Backslash missing from the search path. Changing it to $NewPath."
        }
    }

    # Apply the path corrections.
    $ReplacementPaths | ForEach-Object {
        $PathsToSearch[$_.index] = $_.NewPath 
    }

    # Function to test if the script is running with elevated permissions.
    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }

    # Handy function to set a custom field.
    function Set-NinjaProperty {
        [CmdletBinding()]
        Param(
            [Parameter(Mandatory = $True)]
            [String]$Name,
            [Parameter()]
            [String]$Type,
            [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
            $Value,
            [Parameter()]
            [String]$DocumentName
        )

        $Characters = $Value | Out-String | Measure-Object -Character | Select-Object -ExpandProperty Characters
        if ($Characters -ge 200000) {
            throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded, value is greater than or equal to 200,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 GUID of the option to be selected. Therefore, the given value will be matched with a GUID.
                $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 = $NinjaValue | Ninja-Property-Set-Piped -Name $Name 2>&1
        }
    
        if ($CustomField.Exception) {
            throw $CustomField
        }
    }

    $ExitCode = 0
}
process {
    # Check if the script is running with Administrator privileges. Exit with an error message if not.
    if (!(Test-IsElevated)) {
        Write-Host -Object "[Error] Access Denied. Please run with Administrator privileges."
        exit 1
    }

    # Remove illegal extensions
    $ExtensionsToRemove = New-Object System.Collections.Generic.List[String]
    $invalidExtensions = '[<>:"/\\|\x00-\x1F]|\.$'
    $ExtensionsToSearch | ForEach-Object {
        if($_ -match $invalidExtensions){
            Write-Host -Object "[Error] Extension $_ contains one of the following invalid characters or ends in a period. '\:<>`"/|'"
            $ExtensionsToRemove.Add($_)
            $ExitCode = 1
        }
    }

    # Actual removal
    $ExtensionsToRemove | ForEach-Object {
        $ExtensionsToSearch.Remove($_) | Out-Null
    }

    # Exit the script if there are no valid extensions left to search.
    if ($ExtensionsToSearch.Count -eq 0) {
        Write-Host "[Error] No valid extensions to search!"
        exit 1
    }

    # Initialize lists to store information about paths and errors.
    $CustomFieldErrorInfo = New-Object System.Collections.Generic.List[string]

    # These characters are not valid for a search path.
    $invalidSearchPathCharacters = '[<>"/|?\x00-\x1F]'

    # Initialize a generic list to store paths that don't exist and should be removed from the search.
    $PathsToRemove = New-Object System.Collections.Generic.List[String]
    # Check each path in the search list to ensure it exists. Collect paths that don't exist for removal.
    $PathsToSearch | ForEach-Object {
        if($_ -match $invalidSearchPathCharacters){
            Write-Host -Object "[Error] Path $_ contains one of the following invalid characters. '<>`"/|'"
            $PathsToRemove.Add($_)
            $ExitCode = 1
            return
        }

        if (!(Test-Path $_)) {
            Write-Host -Object "[Error] $_ does not exist!"
            $PathsToRemove.Add($_)
            $ExitCode = 1
        }
    }

    # Remove non-existing paths from the search list.
    $PathsToRemove | ForEach-Object {
        $PathsToSearch.Remove($_) | Out-Null
    }

    # Exit the script if there are no valid paths left to search.
    if ($PathsToSearch.Count -eq 0) {
        Write-Host "[Error] No valid paths to search!"
        exit 1
    }

    # Initialize a list to keep track of the search jobs created.
    $SearchJobs = New-Object System.Collections.Generic.List[object]

    # Create and start a PowerShell job for each path and extension combination.
    foreach ($Path in $PathsToSearch) {
        foreach ($Extension in $ExtensionsToSearch) {
            Write-Host "Searching '$Path' for files with extension '$Extension'..."
            $SearchJobs.Add(
                (
                    Start-Job -ScriptBlock {
                        param($Path, $Extension)

                        # Defines a function to convert file sizes to a human-readable format.
                        function Get-FriendlySize {
                            param($Bytes)
                            # Converts Bytes to the highest matching unit
                            $Sizes = 'Bytes,KB,MB,GB,TB,PB,EB,ZB' -split ','
                            for ($i = 0; ($Bytes -ge 1kb) -and ($i -lt $Sizes.Count); $i++) { $Bytes /= 1kb }
                            $N = 2
                            if ($i -eq 0) { $N = 0 }
                            if ($Bytes) { "$([System.Math]::Round($Bytes,$N)) $($Sizes[$i])" }else { "0 B" }
                        }

                        # Search for files matching the extension and output their details in CSV format.
                        Get-ChildItem -Path $Path -Filter "*$Extension" -Recurse -File -Force | Select-Object Name, FullName, CreationTime, LastWriteTime, Length, @{Name = "Size"; Expression = { Get-FriendlySize $_.Length } } | ConvertTo-Csv
                    } -ArgumentList $Path, $Extension
                )
            )
        }
    }

    # Wait for all search jobs to complete or timeout after 9000 seconds (2.5 hours).
    $SearchJobs | Wait-Job -Timeout 9000 | Out-Null

    # Check for incomplete jobs due to timeout and log an error.
    $IncompleteJobs = $SearchJobs | Get-Job | Where-Object { $_.State -eq "Running" }
    if ($IncompleteJobs) {
        Write-Host "[Error] The timeout period of 2.5 hours has been reached, but not all files or directories have been searched!"
        $CustomFieldErrorInfo.Add("[Error] The timeout period of 2.5 hours has been reached, but not all files or directories have been searched!")
        $ExitCode = 1
    }

    # Collect and process the output from each search job.
    $MatchingItems = $SearchJobs | ForEach-Object {
        $_ | Get-Job | Receive-Job -ErrorAction SilentlyContinue -ErrorVariable JobErrors | ConvertFrom-Csv
    }

    # Clear out duplicate entries
    if ($MatchingItems) {
        $MatchingItems = $MatchingItems | Sort-Object FullName -Unique
    }

    # Check for jobs that failed to complete successfully and log errors.
    $FailedJobs = $SearchJobs | Get-Job | Where-Object { $_.State -ne "Completed" }
    if ($JobErrors -or $FailedJobs) {
        $CustomFieldErrorInfo.Add("[Error] Failed to search certain directories due to an error.")

        if ($JobErrors) {
            $JobErrors | ForEach-Object { 
                $CustomFieldErrorInfo.Add("[Error] $($_.Exception.Message)")
            }
        }
        $ExitCode = 1
    }

    # Process and attempt to set custom field values based on search results and errors, with specific handling for multiline fields.
    # Truncate data if it exceeds character limits for the fields.
    if ($MultiLineField -and $MatchingItems) {
        try {
            Write-Host "Attempting to set Custom Field '$MultiLineField'."

            # Prepare the custom field output.
            $CustomFieldValue = New-Object System.Collections.Generic.List[string]

            # We don't want to edit the matching items array if we have to truncate later so we'll create a duplicate here.
            $CustomFieldList = $MatchingItems | Select-Object -Property Name, FullName, CreationTime, LastWriteTime, Size

            # Format the matching items into a nice list with the relevant properties.
            $CustomFieldValue.Add(($CustomFieldList | Format-List -Property Name, FullName, CreationTime, LastWriteTime, Size | Out-String))
            
            # If any errors were encountered in the search add them to the bottom of the custom field output.
            $CustomFieldErrorInfo | ForEach-Object {
                $CustomFieldValue.Add($_)
            }
            
            # Check that the output complies with the hard character limits.
            $Characters = $CustomFieldValue | Out-String | Measure-Object -Character | Select-Object -ExpandProperty Characters
            if ($Characters -ge 9500) {
                Write-Warning "10,000 Character Limit has been reached! Trimming output until the character limit is satisified..."
                
                # If it doesn't comply with the limits we'll need to recreate it with some adjustments.
                $i = 0
                do {
                    # Recreate the custom field output starting with a warning that we truncated the output.
                    $CustomFieldValue = New-Object System.Collections.Generic.List[string]
                    $CustomFieldValue.Add("This info has been truncated to accommodate the 10,000 character limit.")
                    
                    # The custom field information is sorted in alphabetical order. We'll flip the array upside down to sort it in reverse alphabetical.
                    [array]::Reverse($CustomFieldList)

                    # Remove the next item which in this case will be the smallest item.
                    $CustomFieldList[$i] = $null
                    $i++

                    # We'll flip the array back to right side up.
                    [array]::Reverse($CustomFieldList)

                    # Add it back to the output.
                    $CustomFieldValue.Add(($CustomFieldList | Format-List -Property Name, FullName, CreationTime, LastWriteTime, Size | Out-String))
                    # Finish with adding any errors we encountered during the search.
                    $CustomFieldErrorInfo | ForEach-Object {
                        $CustomFieldValue.Add($_)
                    }

                    # Check that we now comply with the character limit. If not restart the do loop.
                    $Characters = $CustomFieldValue | Out-String | Measure-Object -Character | Select-Object -ExpandProperty Characters
                }while ($Characters -ge 9500)
            }

            # Set the custom field.
            Set-NinjaProperty -Name $MultiLineField -Value $CustomFieldValue
            Write-Host "Successfully set Custom Field '$MultiLineField'!"
        }
        catch {
            Write-Host "[Error] $($_.Exception.Message)"
            $ExitCode = 1
        }
    }

    # Process and attempt to set custom field values based on search results and errors, with specific handling for WYSIWYG fields.
    # Truncate data if it exceeds character limits for the fields.
    if ($WysiwygField -and $MatchingItems) {
        try {
            Write-Host "Attempting to set Custom Field '$WysiwygField'."

            # Prepare the custom field output.
            $CustomFieldValue = New-Object System.Collections.Generic.List[string]

            # Convert the matching items into an html report.
            $htmlTable = $MatchingItems | Select-Object -Property Name, FullName, CreationTime, LastWriteTime, Size | ConvertTo-Html -Fragment
            
            # Add the newly created html into the custom field output.
            $CustomFieldValue.Add($htmlTable)
            # If any errors were encountered in the search add them to the bottom of the custom field output.
            $CustomFieldErrorInfo | ForEach-Object {
                $CustomFieldValue.Add($_)
            }

            # Check that the output complies with the hard character limits.
            $Characters = $CustomFieldValue | Out-String | Measure-Object -Character | Select-Object -ExpandProperty Characters
            if ($Characters -ge 199500) {
                Write-Warning "200,000 Character Limit has been reached! Trimming output until the character limit is satisified..."
                
                # If it doesn't comply with the limits we'll need to recreate it with some adjustments.
                $i = 0
                do {
                    # Recreate the custom field output starting with a warning that we truncated the output.
                    $CustomFieldValue = New-Object System.Collections.Generic.List[string]
                    $CustomFieldValue.Add("<h1>This info has been truncated to accommodate the 200,000 character limit.</h1>")

                    # The custom field information is sorted in alphabetical order. We'll sort it into reverse alphabetical by flipping the array upside down.
                    [array]::Reverse($htmlTable)
                    # If the next entry is a row we'll delete it.
                    if ($htmlTable[$i] -match '<tr><td>') {
                        $htmlTable[$i] = $null
                    }
                    $i++
                    # We'll flip the array back to right side up.
                    [array]::Reverse($htmlTable)

                    # Add it back to the output.
                    $CustomFieldValue.Add($htmlTable)
                    # Finish with adding any errors we encountered during the search.
                    $CustomFieldErrorInfo | ForEach-Object {
                        $CustomFieldValue.Add($_)
                    }
                    # Check that we now comply with the character limit. If not restart the do loop.
                    $Characters = $CustomFieldValue | Out-String | Measure-Object -Character | Select-Object -ExpandProperty Characters
                }while ($Characters -ge 199500)
            }

            # Set the custom field.
            Set-NinjaProperty -Name $WysiwygField -Value $CustomFieldValue
            Write-Host "Successfully set Custom Field '$WysiwygField'!"
        }
        catch {
            Write-Host "[Error] $($_.Exception.Message)"
            $ExitCode = 1
        }
    }

    # Output the results of our search into the activity log.
    if (!$MatchingItems) {
        Write-Host "No files found with extension $Extension!"
    }
    else {
        Write-Host "Files found!"
        $MatchingItems | Format-List -Property Name, FullName, CreationTime, LastWriteTime, Size | Out-String | Write-Host
    }

    # If we encountered any errors during the search we'll output them here.
    if ($JobErrors -or $FailedJobs) {
        Write-Host ""
        Write-Host "[Error] Failed to search certain directories due to an error."

        if ($JobErrors) {
            Write-Host ""

            $JobErrors | ForEach-Object {
                Write-Host "[Error] $($_.Exception.Message)" 
            }
        }
        $ExitCode = 1
    }

    # Remove all jobs to clean up.
    $SearchJobs | Get-Job | Remove-Job -Force

    # Exit the script with the appropriate exit code
    exit $ExitCode
}
end {
    
    
     
}

 

Accédez à plus de 700 scripts dans le Dojo NinjaOne

Obtenir l’accès

Description détaillée

Synopsis du script

Le script est conçu pour rechercher dans les répertoires les fichiers ayant des extensions spécifiques et créer un rapport complet. Il prend en compte divers paramètres, notamment les extensions à rechercher, les répertoires dans lesquels effectuer la recherche et les champs personnalisés facultatifs pour l’enregistrement des résultats.

Paramètres

  1. Extensions: Liste d’extensions de fichiers à rechercher, séparées par des virgules. Les caractères génériques (wildcards) sont pris en charge.
  2. SearchPaths: Répertoires dans lesquels la recherche doit être effectuée, y compris tous les sous-répertoires.
  3. MultiLineField: Champ facultatif permettant d’enregistrer les résultats d’une recherche multiligne.
  4. WysiwygField: Un champ WYSIWYG facultatif pour enregistrer les résultats de la recherche.
  5. ScanSystemDrive: Un commutateur pour définir le lecteur du système comme point de départ.
  6. ScanAllDrives: Un commutateur pour définir tous les lecteurs, y compris les lecteurs flash, comme point de départ.

Exécution du script

  1. Validation des paramètres: Le script commence par valider les paramètres d’entrée. Il s’assure que les extensions et les chemins de recherche sont valides. Il définit également les paramètres de manière dynamique en utilisant les variables d’environnement si elles sont disponibles.
  2. Extension et préparation du chemin: Il normalise les extensions et les chemins de recherche en ajoutant les points et les barres obliques inverses manquants. Les extensions et les chemins non valides sont identifiés et supprimés.
  3. Vérification des privilèges: Le script vérifie s’il s’exécute avec des autorisations élevées, et se termine si ce n’est pas le cas.
  4. Initialisation de la recherche: Il crée une liste de tâches de recherche pour chaque combinaison de chemins et d’extensions. Chaque tâche recherche dans le chemin spécifié les fichiers ayant l’extension donnée.
  5. Collecte et traitement des résultats: Le script recueille les résultats de la recherche, supprime les doublons et les formate pour la sortie. Il gère également les erreurs potentielles et les délais d’attente au cours de la recherche.
  6. Réglage du champ personnalisé: S’ils sont spécifiés, le script tente de définir les résultats dans les champs personnalisés donnés (MultiLineField et WysiwygField), en veillant à ce que les données respectent les limites de caractères.
  7. Sortie et nettoyage: Enfin, le script affiche les résultats de la recherche dans la console et nettoie toutes les tâches avant de se terminer.

Cas d’utilisation potentiels

Scénario hypothétique

Imaginez un professionnel de l’informatique travaillant pour une entreprise de taille moyenne et devant contrôler tous les fichiers exécutables présents sur le réseau. En exécutant ce script avec le paramètre -Extensions « .exe » et en spécifiant les répertoires du réseau, il peut rapidement générer un rapport détaillé de tous les fichiers exécutables, y compris leurs chemins d’accès, leurs heures de création et leurs tailles. Ce rapport peut ensuite être utilisé pour garantir le respect des politiques de l’entreprise et identifier les installations de logiciels non autorisées.

Comparaisons

Comparaison entre les méthodes traditionnelles et le script PowerShell

Traditionnellement, la recherche de fichiers par extension peut impliquer une recherche manuelle dans les répertoires ou l’utilisation d’outils basiques de ligne de commande, ce qui peut prendre beaucoup de temps et être source d’erreurs. Ce script PowerShell automatise le processus, fournit des rapports complets et traite les erreurs en toute simplicité, ce qui le rend bien meilleur que les méthodes manuelles et les scripts plus simples.

FAQ

1) Que se passe-t-il si aucune extension n’est spécifiée ?

Le script se termine par une erreur, indiquant qu’une extension est nécessaire pour la recherche.

2) Puis-je effectuer des recherches dans plusieurs répertoires à la fois ?

Oui, en fournissant une liste de répertoires séparés par des virgules dans le paramètre -SearchPaths, le script recherchera chaque répertoire spécifié et ses sous-répertoires.

3) Que faire si j’ai besoin d’effectuer une recherche sur tous les lecteurs de mon système ?

En utilisant le paramètre -ScanAllDrives, le script inclura tous les lecteurs disponibles dans la recherche, y compris les lecteurs flash.

4) Comment le script gère-t-il de grandes quantités de données ?

Le script comprend des mécanismes permettant de tronquer les résultats s’ils dépassent les limites de caractères pour les champs personnalisés, ce qui permet de s’assurer que les résultats restent utilisables et conformes aux contraintes du système.

Implications

Sécurité et conformité

En utilisant ce script, les professionnels de l’informatique peuvent renforcer la sécurité en identifiant rapidement les fichiers potentiellement dangereux ou non autorisés. Des audits réguliers réalisés à l’aide de ce script peuvent contribuer à maintenir la conformité avec les politiques de l’entreprise et les réglementations.

Recommandations

  • Audits réguliers: Exécutez régulièrement le script pour tenir à jour l’inventaire de certains types de fichiers.
  • Examiner les journaux: Examinez toujours la sortie du script et les journaux pour y déceler d’éventuelles erreurs ou avertissements.
  • Personnaliser les champs: Utilisez les champs personnalisés pour stocker les résultats afin d’améliorer la documentation et le suivi.

Conclusion

Ce script PowerShell est un outil puissant pour les professionnels de l’informatique qui cherchent à automatiser la localisation et le reporting des fichiers en fonction de l’extension. Ses fonctionnalités complètes, combinées à sa facilité d’utilisation, en font un complément informatique essentiel. Pour les entreprises utilisant NinjaOne, ce script s’intègre de manière optimale, améliorant ainsi les capacités de la plateforme en matière de gestion et de sécurité des systèmes.

Pour aller plus loin

Créer une équipe informatique efficace et performante nécessite une solution centralisée qui soit l’outil principal pour fournir vos services. NinjaOne permet aux équipes informatiques de surveiller, gérer, sécuriser et prendre en charge tous les appareils, où qu’ils soient, sans avoir besoin d’une infrastructure complexe sur site.

Pour en savoir plus sur NinjaOne Endpoint Management, participez à une visite guidée ou commencez votre essai gratuit de la plateforme NinjaOne.

Catégories :

Vous pourriez aussi aimer

Voir la démo×
×

Voir NinjaOne en action !

En soumettant ce formulaire, j'accepte la politique de confidentialité de NinjaOne.

Termes et conditions NinjaOne

En cliquant sur le bouton « J’accepte » ci-dessous, vous indiquez que vous acceptez les termes juridiques suivants ainsi que nos conditions d’utilisation:

  • Droits de propriété: NinjaOne possède et continuera de posséder tous les droits, titres et intérêts relatifs au script (y compris les droits d’auteur). NinjaOne vous accorde une licence limitée pour l’utilisation du script conformément à ces conditions légales.
  • Limitation de l’utilisation: Les scripts ne peuvent être utilisés qu’à des fins personnelles ou professionnelles internes légitimes et ne peuvent être partagés avec d’autres entités.
  • Interdiction de publication: Vous n’êtes en aucun cas autorisé à publier le script dans une bibliothèque de scripts appartenant à, ou sous le contrôle d’un autre fournisseur de logiciels.
  • Clause de non-responsabilité: Le texte est fourni « tel quel » et « tel que disponible », sans garantie d’aucune sorte. NinjaOne ne promet ni ne garantit que le script sera exempt de défauts ou qu’il répondra à vos besoins ou attentes particulières.
  • Acceptation des risques: L’utilisation du script est sous votre propre responsabilité. Vous reconnaissez qu’il existe certains risques inhérents à l’utilisation du script, et vous comprenez et assumez chacun de ces risques.
  • Renonciation et exonération de responsabilité: Vous ne tiendrez pas NinjaOne pour responsable des conséquences négatives ou involontaires résultant de votre utilisation du script, et vous renoncez à tout droit ou recours légal ou équitable que vous pourriez avoir contre NinjaOne en rapport avec votre utilisation du script.
  • EULA: Si vous êtes un client de NinjaOne, votre utilisation du script est soumise au contrat de licence d’utilisateur final qui vous est applicable (End User License Agreement (EULA)).