IT-Guide zur Verwendung von PowerShell für Dateierweiterungsberichte

In der heutigen digitalen Welt ist die effiziente Verwaltung von Dateien für IT-Experten und Managed Service Provider (MSPs) von entscheidender Bedeutung. Die Möglichkeit, umfassende Berichte basierend auf Dateierweiterungen in angegebenen Verzeichnissen zu erstellen, kann die Arbeitsabläufe optimieren, die Sicherheit verbessern und bei der Aufrechterhaltung der Systemhygiene helfen. In diesem Beitrag wird ein PowerShell-Skript vorgestellt, das die Erstellung von Dateierweiterungsberichten automatisiert und dafür sorgt, dass IT-Experten mühelos Dateien nach Erweiterungen in verschiedenen Verzeichnissen finden und dokumentieren können.

Kontext 

PowerShell-Skripte sind für IT-Administratoren von unschätzbarem Wert, da sie die notwendige Automatisierung bieten, um komplexe Aufgaben mit Präzision und Leichtigkeit zu erledigen. Dieses Skript konzentriert sich auf die Erstellung detaillierter Berichte basierend auf Dateierweiterungen in benutzerdefinierten Verzeichnissen und deren Unterverzeichnissen. Mithilfe dieses Skripts können IT-Experten bestimmte Dateitypen schnell identifizieren und so Aufgaben wie Software-Audits, Compliance-Prüfungen und Sicherheitsbewertungen erleichtern.

Das Skript zur Erstellung von Dateierweiterungsberichten

#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 {
    
    
     
}

 

Greifen Sie auf über 300 Skripte im NinjaOne Dojo zu.

Zugang erhalten

Detailansicht

Skript-Zusammenfassung

Das Skript ist so konzipiert, dass es Verzeichnisse nach Dateien mit bestimmten Erweiterungen durchsucht und einen umfassenden Bericht erstellt. Es akzeptiert verschiedene Parameter, darunter die zu suchenden Erweiterungen, die zu durchsuchenden Verzeichnisse und optionale benutzerdefinierte Felder für die Erfassung der Ergebnisse.

Parameter

  1. Extensions: Eine durch Kommata getrennte Liste von Dateierweiterungen, nach denen gesucht werden soll. Wildcard-Zeichen werden unterstützt.
  2. SearchPaths: Verzeichnisse und deren Unterverzeichnisse, die durchsucht werden sollen.
  3. MultiLineField: Ein optionales Feld zur Erfassung mehrzeiliger Suchergebnisse.
  4. WysiwygField: Ein optionales WYSIWYG-Feld zur Erfassung von Suchergebnissen.
  5. ScanSystemDrive: Ein Schalter, um das Systemlaufwerk als Startpunkt festzulegen.
  6. ScanAllDrives: Ein Schalter, um alle Laufwerke, einschließlich Flash-Laufwerke, als Startpunkt festzulegen.

Skript-Ausführung

  1. Validierung der Parameter: Das Skript beginnt mit der Validierung der Eingabeparameter. Es stellt sicher, dass gültige Erweiterungen und Suchpfade angegeben werden. Es setzt auch dynamisch Parameter unter Verwendung von Umgebungsvariablen, falls vorhanden.
  2. Erweiterung- und Pfadvorbereitung: Es normalisiert Erweiterungen und Suchpfade, indem es fehlende Punkte und umgedrehte Schrägstriche hinzufügt. Ungültige Erweiterungen und Pfade werden erkannt und entfernt.
  3. Prüfung der Berechtigungen: Das Skript prüft, ob es mit erhöhten Rechten ausgeführt wird, und beendet sich andernfalls.
  4. Initialisierung der Suche: Es erstellt eine Liste von Such-Jobs für jede Kombination von Pfaden und Erweiterungen. Jeder Job sucht im angegebenen Pfad nach Dateien mit der gewählten Erweiterung.
  5. Sammlung und Verarbeitung der Ergebnisse: Das Skript sammelt die Suchergebnisse, entfernt Duplikate und formatiert sie für die Ausgabe. Es behandelt auch mögliche Fehler und Zeitüberschreitungen während der Suche.
  6. Einstellung der benutzerdefinierten Felder: Wenn angegeben, versucht das Skript, die Ergebnisse in die angegebenen benutzerdefinierten Felder (‘MultiLineField’ und ‘WysiwygField’) zu setzen, um sicherzustellen, dass die Daten die Zeichengrenzen einhalten.
  7. Ausgabe und Bereinigung: Schließlich gibt das Skript die Suchergebnisse auf die Konsole aus und bereinigt alle Jobs, bevor es beendet wird.

Potenzielle Anwendungsfälle

Hypothetisches Szenario

Stellen Sie sich vor, ein IT-Experte in einem mittelständischen Unternehmen muss alle ausführbaren Dateien im Netzwerk überprüfen. Wenn er dieses Skript mit dem Parameter -Extensions ‘.exe’ ausführt und die Netzwerkverzeichnisse angibt, kann er schnell einen detaillierten Bericht über alle ausführbaren Dateien erstellen, einschließlich ihrer Pfade, Erstellungszeiten und Größen. Dieser Bericht kann dann verwendet werden, um für die Einhaltung der Unternehmensrichtlinien zu sorgen und nicht autorisierte Softwareinstallationen zu identifizieren.

Vergleiche

Traditionelle Methoden vs. PowerShell-Skript

Um Dateien nach ihrer Erweiterung zu finden, müssen Sie normalerweise Verzeichnisse manuell durchsuchen oder simple Befehlszeilen-Tools verwenden, was zeitaufwändig und fehleranfällig sein kann. Dieses PowerShell-Skript automatisiert den Prozess, bietet leistungsstarke Berichterstellung und behandelt Fehler zuverlässig, wodurch es manuellen Methoden oder einfacheren Skripts weit überlegen ist.

FAQs

1) Was passiert, wenn keine Erweiterungen angegeben werden?

Das Skript wird mit einer Fehlermeldung beendet, die darauf hinweist, dass eine Erweiterung für die Suche erforderlich ist.

2) Kann ich mehrere Verzeichnisse auf einmal durchsuchen?

Ja, wenn Sie eine durch Kommata getrennte Liste von Verzeichnissen im Parameter ‘-SearchPaths’ angeben, durchsucht das Skript jedes angegebene Verzeichnis und seine Unterverzeichnisse.

3) Was ist, wenn ich alle Laufwerke in meinem System durchsuchen muss?

Mit dem Parameter ‘-ScanAllDrives’ bezieht das Skript alle verfügbaren Laufwerke in die Suche ein, auch Flash-Laufwerke.

4) Wie geht das Skript mit großen Datenmengen um?

Das Skript enthält Mechanismen, um die Ausgabe abzuschneiden, wenn sie die Zeichenbeschränkungen für benutzerdefinierte Felder überschreitet, um zu garantieren, dass die Ergebnisse überschaubar und innerhalb der Systemgrenzen bleiben.

Folgen

Sicherheit und Compliance

Mithilfe dieses Skripts können IT-Experten die Sicherheit erhöhen, indem sie potenziell schädliche oder nicht autorisierte Dateien schnell identifizieren. Regelmäßige Audits mit diesem Skript können dazu beitragen, die Einhaltung von Unternehmensrichtlinien und gesetzlichen Vorschriften zu gewährleisten.

Empfehlungen

  • Regelmäßige Audits ausführen: Führen Sie das Skript regelmäßig aus, um ein aktuelles Inventar bestimmter Dateitypen zu erhalten.
  • Protokolle überprüfen: Überprüfen Sie immer die Skriptausgabe und die Protokolle auf Fehler oder Warnmeldungen.
  • Felder anpassen: Verwenden Sie die benutzerdefinierten Felder, um Ergebnisse zur besseren Dokumentation und Nachverfolgung zu speichern.

Abschließende Überlegungen

Dieses PowerShell-Skript ist ein leistungsfähiges Tool für IT-Experten, die die Dateisuche nach Erweiterungen automatisieren und entsprechende Berichte erstellen möchten. Seine umfassende Funktionalität in Kombination mit der Benutzerfreundlichkeit macht es zu einer unverzichtbaren Ergänzung für jedes IT-Toolkit. Für Unternehmen, die NinjaOne einsetzen, lässt sich dieses Skript nahtlos integrieren, wodurch die Möglichkeiten der Plattform für Systemmanagement und Sicherheit weiter verbessert werden.

Nächste Schritte

Der Aufbau eines effizienten und effektiven IT-Teams erfordert eine zentralisierte Lösung, die als einheitliches Tool zur Bereitstellung von IT-Dienstleistungen fungiert. NinjaOne ermöglicht es IT-Teams, alle Geräte zu überwachen, zu verwalten, zu sichern und zu unterstützen, unabhängig vom Standort, ohne dass eine komplexe Infrastruktur vor Ort erforderlich ist.

Erfahren Sie mehr über NinjaOne Remote Script Deployment, sehen Sie sich eine Live-Tour an oder starten Sie Ihre kostenlose Testversion unserer NinjaOne Plattform.

Kategorien:

Das könnte Sie auch interessieren

×

Sehen Sie NinjaOne in Aktion!

Mit dem Absenden dieses Formulars akzeptiere ich die Datenschutzerklärung von NinjaOne.

NinjaOne Allgemeine Geschäftsbedingungen für Skripte

Indem Sie unten auf die Schaltfläche “Ich akzeptiere” klicken, erklären Sie Ihr Einverständnis mit den folgenden rechtlichen Bedingungen sowie mit unseren Nutzungsbedingungen:

  • Eigentumsrechte: NinjaOne besitzt und wird weiterhin alle Rechte, Titel und Interessen an dem Skript (einschließlich des Urheberrechts) behalten. NinjaOne gewährt Ihnen eine eingeschränkte Lizenz zur Nutzung des Skripts in Übereinstimmung mit diesen rechtlichen Bedingungen.
  • Einschränkung der Nutzung: Sie dürfen das Skript nur für Ihre legitimen persönlichen oder internen Geschäftszwecke verwenden und es nicht an Dritte weitergeben.
  • Verbot der Wiederveröffentlichung: Sie sind unter keinen Umständen berechtigt, das Skript in einer Skriptbibliothek, die einem anderen Softwareanbieter gehört oder von diesem kontrolliert wird, erneut zu veröffentlichen.
  • Gewährleistungsausschluss: Das Skript wird “wie gesehen” und “wie verfügbar” bereitgestellt, ohne jegliche Garantie. NinjaOne gibt keine Versprechen oder Garantien, dass das Skript frei von Fehlern ist oder dass es Ihre speziellen Bedürfnisse oder Erwartungen erfüllt.
  • Risikoübernahme: Die Verwendung des Skripts erfolgt auf eigene Gefahr. Sie erkennen an, dass die Nutzung des Skripts mit bestimmten Risiken verbunden ist, und Sie verstehen und übernehmen jedes dieser Risiken.
  • Verzicht und Freigabe: Sie machen NinjaOne nicht für nachteilige oder unbeabsichtigte Folgen verantwortlich, die sich aus Ihrer Nutzung des Skripts ergeben, und Sie verzichten auf alle gesetzlichen oder billigkeitsrechtlichen Rechte oder Rechtsmittel, die Sie gegen NinjaOne im Zusammenhang mit Ihrer Nutzung des Skripts haben könnten.
  • EULA: Wenn Sie ein NinjaOne-Kunde sind, unterliegt Ihre Nutzung des Skripts dem für Sie geltenden Endbenutzer-Lizenzvertrag (EULA).