{"id":353756,"date":"2024-09-18T08:24:14","date_gmt":"2024-09-18T08:24:14","guid":{"rendered":"https:\/\/www.ninjaone.com\/script-hub\/script-powershell-per-automatizzare-la-disinstallazione-di-applicazioni\/"},"modified":"2024-10-13T19:03:25","modified_gmt":"2024-10-13T19:03:25","slug":"script-powershell-per-automatizzare-la-disinstallazione-di-applicazioni","status":"publish","type":"script_hub","link":"https:\/\/www.ninjaone.com\/it\/script-hub\/script-powershell-per-automatizzare-la-disinstallazione-di-applicazioni\/","title":{"rendered":"Come automatizzare la disinstallazione di applicazioni in Windows utilizzando PowerShell"},"content":{"rendered":"<p>Nel mondo IT, la gestione del software su pi\u00f9 macchine \u00e8 un compito complesso e critico. Una delle sfide pi\u00f9 comuni che gli amministratori IT devono affrontare \u00e8 la disinstallazione delle applicazioni in modo <a href=\"https:\/\/www.ninjaone.com\/it\/efficienza-it\/\" target=\"_blank\" rel=\"noopener\">efficiente<\/a> e standardizzato.<\/p>\n<p>La disinstallazione manuale, soprattutto su pi\u00f9 endpoint, non solo richiede molto tempo, ma \u00e8 anche soggetta a errori. \u00c8 qui che entrano in gioco gli script <a href=\"https:\/\/www.ninjaone.com\/it\/it-hub\/gestione-degli-endpoint\/cos-e-powershell\/\" target=\"_blank\" rel=\"noopener\">PowerShell<\/a>, come quello di cui parleremo in questo articolo.<\/p>\n<p>Questo particolare script \u00e8 utile per automatizzare <strong>la disinstallazione di applicazioni<\/strong>, e lo fa utilizzando il cmdlet UninstallString e argomenti personalizzati, fornendo un approccio semplificato alla gestione della rimozione del software.<\/p>\n<h2>La necessit\u00e0 di uno script per automatizzare la disinstallazione di applicazioni<\/h2>\n<p>La disinstallazione del software, soprattutto nelle grandi organizzazioni, non \u00e8 un compito semplice. I professionisti IT e i <a href=\"https:\/\/www.ninjaone.com\/it\/cos-e-un-msp\" target=\"_blank\" rel=\"noopener\">Managed Service Provider (MSP)<\/a> hanno spesso a che fare con una serie di applicazioni diverse installate su vari computer. Ogni applicazione potrebbe richiedere comandi di disinstallazione diversi o seguire protocolli diversi.<\/p>\n<p>Lo script che stiamo analizzando \u00e8 progettato per gestire queste sfumature, aggiungendo automaticamente gli argomenti necessari come \/qn \/norestart o \/S, che sono essenziali per le disinstallazioni silenziose e senza riavvio. Questa automazione \u00e8 fondamentale per mantenere la coerenza e l&#8217;<a href=\"https:\/\/www.ninjaone.com\/it\/efficienza-it\/\" target=\"_blank\" rel=\"noopener\">efficienza<\/a> degli ambienti IT su larga scala.<\/p>\n<h2>Lo script per automatizzare la disinstallazione delle applicazioni:<\/h2>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">#Requires -Version 5.1\r\n\r\n&lt;#\r\n.SYNOPSIS\r\n    Uninstall an application using the UninstallString and custom arguments. This script will auto-add \/qn \/norestart or \/S arguments.\r\n\r\n    This script will only uninstall apps that follow typical uninstall patterns such as msiexec \/X{GUID} \/qn \/norestart.\r\n.DESCRIPTION\r\n    Uninstall an application using the UninstallString and custom arguments. This script will auto-add \/qn \/norestart or \/S arguments.\r\n\r\n    This script will only uninstall apps that follow typical uninstall patterns such as msiexec \/X{GUID} \/qn \/norestart.\r\n.EXAMPLE\r\n    -Name \"VLC media Player\"\r\n    \r\n    Beginning uninstall of VLC media player using MsiExec.exe \/X{9675011C-2395-4AD7-B1CC-92910F991F58} \/qn \/norestart...\r\n    Exit Code for VLC media player: 0\r\n    Successfully uninstalled your requested apps!\r\n\r\nPARAMETER: -Name \"ReplaceMeWithNameOfApp\"\r\n    Exact name of the application to uninstall, separated by commas. E.g., 'VLC media player, Everything 1.4.1.1024 (x64)'.\r\n\r\nPARAMETER: -Arguments \"\/SILENT, \/NOREBOOT\"\r\n    Additional arguments to use when uninstalling the app, separated by commas. E.g., '\/SILENT, \/NOREBOOT'.\r\n\r\nPARAMETER: -Reboot\r\n    Schedules a reboot for 1 minute after the uninstall process succeeds.\r\n\r\nPARAMETER: -Timeout \"ReplaceMeWithTheNumberOfMinutesToWait\"\r\n    Specify the amount of time in minutes to wait for the uninstall process to complete. \r\n    If the process exceeds this time, the script and uninstall process will be terminated.\r\n\r\n.NOTES\r\n    Minimum OS Architecture Supported: Windows 10, Windows Server 2016\r\n    Release Notes: Initial Release\r\n.COMPONENT\r\n    Misc\r\n#&gt;\r\n\r\n[CmdletBinding()]\r\nparam (\r\n    [Parameter()]\r\n    [String]$Name,\r\n    [Parameter()]\r\n    [String]$Arguments,\r\n    [Parameter()]\r\n    [switch]$Reboot = [System.Convert]::ToBoolean($env:reboot),\r\n    [Parameter()]\r\n    [int]$Timeout = 10\r\n)\r\n\r\nbegin {\r\n    # Replace parameters with dynamic script variables\r\n    if ($env:nameOfAppToUninstall -and $env:nameOfAppToUninstall -notlike \"null\") { $Name = $env:nameOfAppToUninstall }\r\n    if ($env:arguments -and $env:arguments -notlike \"null\") { $Arguments = $env:arguments }\r\n    if ($env:timeoutInMinutes -and $env:timeoutInMinutes -notlike \"null\") { $Timeout = $env:timeoutInMinutes }\r\n\r\n    # Check if application name is provided\r\n    if (-not $Name) {\r\n        Write-Host -Object \"[Error] No name given, please enter in the name of an app to uninstall!\"\r\n        exit 1\r\n    }\r\n\r\n    # Check if timeout is provided\r\n    if (-not $Timeout) {\r\n        Write-Host -Object \"[Error] No timeout given!\"\r\n        Write-Host -Object \"[Error] Please enter in a timeout that's greater than or equal to 1 minute or less than or equal to 60 minutes.\"\r\n        exit 1\r\n    }\r\n\r\n    # Validate the timeout is within the acceptable range\r\n    if ($Timeout -lt 1 -or $Timeout -gt 60) {\r\n        Write-Host -Object \"[Error] An invalid timeout was given of $Timeout minutes.\"\r\n        Write-Host -Object \"[Error] Please enter in a timeout that's greater than or equal to 1 minute or less than or equal to 60 minutes.\"\r\n        exit 1\r\n    }\r\n\r\n    # Create a list to hold application names after splitting\r\n    $AppNames = New-Object System.Collections.Generic.List[String]\r\n    $Name -split ',' | ForEach-Object {\r\n        $AppNames.Add($_.Trim())\r\n    }\r\n\r\n    # Function to check if the script is run with elevated permissions\r\n    function Test-IsElevated {\r\n        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()\r\n        $p = New-Object System.Security.Principal.WindowsPrincipal($id)\r\n        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)\r\n    }\r\n\r\n    # Get all users registry hive locations\r\n    function Get-UserHives {\r\n        param (\r\n            [Parameter()]\r\n            [ValidateSet('AzureAD', 'DomainAndLocal', 'All')]\r\n            [String]$Type = \"All\",\r\n            [Parameter()]\r\n            [String[]]$ExcludedUsers,\r\n            [Parameter()]\r\n            [switch]$IncludeDefault\r\n        )\r\n    \r\n        # User account SID's follow a particular pattern depending on if they're Azure AD, a Domain account, or a local \"workgroup\" account.\r\n        $Patterns = switch ($Type) {\r\n            \"AzureAD\" { \"S-1-12-1-(\\d+-?){4}$\" }\r\n            \"DomainAndLocal\" { \"S-1-5-21-(\\d+-?){4}$\" }\r\n            \"All\" { \"S-1-12-1-(\\d+-?){4}$\" ; \"S-1-5-21-(\\d+-?){4}$\" } \r\n        }\r\n    \r\n        # We'll need the NTUSER.DAT file to load each user's registry hive. So we grab it if their account SID matches the above pattern. \r\n        $UserProfiles = Foreach ($Pattern in $Patterns) { \r\n            Get-ItemProperty \"HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\*\" |\r\n                Where-Object { $_.PSChildName -match $Pattern } | \r\n                Select-Object @{Name = \"SID\"; Expression = { $_.PSChildName } },\r\n                @{Name = \"UserName\"; Expression = { \"$($_.ProfileImagePath | Split-Path -Leaf)\" } }, \r\n                @{Name = \"UserHive\"; Expression = { \"$($_.ProfileImagePath)\\NTuser.dat\" } }, \r\n                @{Name = \"Path\"; Expression = { $_.ProfileImagePath } }\r\n        }\r\n    \r\n        # There are some situations where grabbing the .Default user's info is needed.\r\n        switch ($IncludeDefault) {\r\n            $True {\r\n                $DefaultProfile = \"\" | Select-Object UserName, SID, UserHive, Path\r\n                $DefaultProfile.UserName = \"Default\"\r\n                $DefaultProfile.SID = \"DefaultProfile\"\r\n                $DefaultProfile.Userhive = \"$env:SystemDrive\\Users\\Default\\NTUSER.DAT\"\r\n                $DefaultProfile.Path = \"C:\\Users\\Default\"\r\n    \r\n                $DefaultProfile | Where-Object { $ExcludedUsers -notcontains $_.UserName }\r\n            }\r\n        }\r\n    \r\n        $UserProfiles | Where-Object { $ExcludedUsers -notcontains $_.UserName }\r\n    }\r\n\r\n    # Function to find the uninstallation key of an application\r\n    function Find-UninstallKey {\r\n        [CmdletBinding()]\r\n        param (\r\n            [Parameter(ValueFromPipeline = $True)]\r\n            [String]$DisplayName,\r\n            [Parameter()]\r\n            [Switch]$UninstallString\r\n        )\r\n        process {\r\n            $UninstallList = New-Object System.Collections.Generic.List[Object]\r\n\r\n            # Search for uninstall key in 32-bit registry location\r\n            $Result = Get-ChildItem \"Registry::HKEY_USERS\\*\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\" | Get-ItemProperty | Where-Object { $_.DisplayName -match \"$([regex]::Escape($DisplayName))\" }\r\n            if ($Result) { $UninstallList.Add($Result) }\r\n\r\n            # Search for uninstall key in 32-bit user locations\r\n            $Result = Get-ChildItem HKLM:\\Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | Get-ItemProperty | Where-Object { $_.DisplayName -match \"$([regex]::Escape($DisplayName))\" }\r\n            if ($Result) { $UninstallList.Add($Result) }\r\n\r\n            # Search for uninstall key in 64-bit registry location\r\n            $Result = Get-ChildItem HKLM:\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | Get-ItemProperty | Where-Object { $_.DisplayName -match \"$([regex]::Escape($DisplayName))\" }\r\n            if ($Result) { $UninstallList.Add($Result) }\r\n\r\n            # Search for uninstall key in 64-bit user locations\r\n            $Result = Get-ChildItem \"Registry::HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\*\" | Get-ItemProperty | Where-Object { $_.DisplayName -match \"$([regex]::Escape($DisplayName))\" }\r\n            if ($Result) { $UninstallList.Add($Result) }\r\n    \r\n            # Optionally return the DisplayName and UninstallString\r\n            if ($UninstallString) {\r\n                $UninstallList | ForEach-Object { $_ | Select-Object DisplayName, UninstallString -ErrorAction SilentlyContinue }\r\n            }\r\n            else {\r\n                $UninstallList\r\n            }\r\n        }\r\n    }\r\n\r\n    # Initialize the exit code variable\r\n    $ExitCode = 0\r\n}\r\nprocess {\r\n    # Check for administrative privileges\r\n    if (-not (Test-IsElevated)) {\r\n        Write-Host -Object \"[Error] Access Denied. Please run with Administrator privileges.\"\r\n        exit 1\r\n    }\r\n\r\n    # Load unloaded profiles\r\n    $UserProfiles = Get-UserHives -Type \"All\"\r\n    $ProfileWasLoaded = New-Object System.Collections.Generic.List[string]\r\n\r\n    # Loop through each profile on the machine.\r\n    Foreach ($UserProfile in $UserProfiles) {\r\n        # Load user's NTUSER.DAT if it's not already loaded.\r\n        If ((Test-Path Registry::HKEY_USERS\\$($UserProfile.SID)) -eq $false) {\r\n            Start-Process -FilePath \"cmd.exe\" -ArgumentList \"\/C reg.exe LOAD HKU\\$($UserProfile.SID) `\"$($UserProfile.UserHive)`\"\" -Wait -WindowStyle Hidden\r\n            $ProfileWasLoaded.Add(\"$($UserProfile.SID)\")\r\n        }\r\n    }\r\n\r\n    # Retrieve similar applications based on names provided\r\n    $SimilarAppsToName = $AppNames | ForEach-Object { Find-UninstallKey -DisplayName $_ -UninstallString }\r\n    if (-not $SimilarAppsToName) {\r\n        Write-Host \"[Error] The requested app(s) was not found and none were found that are similar!\"\r\n        exit 1\r\n    }\r\n\r\n    # Unload all hives that were loaded for this script.\r\n    ForEach ($UserHive in $ProfileWasLoaded) {\r\n        If ($ProfileWasLoaded -eq $false) {\r\n            [gc]::Collect()\r\n            Start-Sleep 1\r\n            Start-Process -FilePath \"cmd.exe\" -ArgumentList \"\/C reg.exe UNLOAD HKU\\$($UserHive)\" -Wait -WindowStyle Hidden | Out-Null\r\n        }\r\n    }\r\n\r\n    # Create a list to store apps that are confirmed for uninstallation\r\n    $AppsToUninstall = New-Object System.Collections.Generic.List[Object]\r\n    $SimilarAppsToName | ForEach-Object {\r\n        foreach ($AppName in $AppNames) {\r\n            if ($AppName -eq $_.DisplayName) {\r\n                # A matching app has been found\r\n                $ExactMatch = $True\r\n    \r\n                if ($_.UninstallString) {\r\n                    # Uninstall string is available\r\n                    $UninstallStringFound = $True\r\n                    # Add app to uninstall list\r\n                    $AppsToUninstall.Add($_)\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    # Check if any exact matches were found\r\n    if (-not $ExactMatch) {\r\n        Write-Host \"[Error] Your requested apps were not found. Please see the below list and try again.\"\r\n        $SimilarAppsToName | Format-Table DisplayName | Out-String | Write-Host\r\n        exit 1\r\n    }\r\n\r\n    # Check if uninstall strings were found for the apps\r\n    if (-not $UninstallStringFound) {\r\n        Write-Host \"[Error] No uninstall string found for any of your requested apps!\"\r\n        exit 1\r\n    }\r\n\r\n    # Check if there are apps without uninstall strings or not found at all\r\n    $AppNames | ForEach-Object {\r\n        if ($AppsToUninstall.DisplayName -notcontains $_) {\r\n            Write-Host \"[Error] Either the uninstall string was not present or the app itself was not found for one of your selected apps! See the below list of similar apps and try again.\"\r\n            $SimilarAppsToName | Format-Table DisplayName | Out-String | Write-Host\r\n            $ExitCode = 1\r\n        }\r\n    }\r\n\r\n    # Convert timeout from minutes to seconds\r\n    $TimeoutInSeconds = $Timeout * 60\r\n    $StartTime = Get-Date\r\n\r\n    # Process each app to uninstall\r\n    $AppsToUninstall | ForEach-Object {\r\n        $AdditionalArguments = New-Object System.Collections.Generic.List[String]\r\n\r\n        # If the uninstall string contains msiexec that's what our executable will be.\r\n        if($_.UninstallString -match \"msiexec\"){\r\n            $Executable = \"msiexec.exe\"\r\n        }\r\n\r\n        # If it contains a filepath we'll use that as our executable.\r\n        if($_.UninstallString -notmatch \"msiexec\" -and $_.UninstallString -match '[a-zA-Z]:\\\\(?:[^\\\\\\\/:*?\"&lt;&gt;|\\r\\n]+\\\\)*[^\\\\\\\/:*?\"&lt;&gt;|\\r\\n]*'){\r\n            $Executable = $Matches[0]\r\n        }\r\n\r\n        # Confirm we have an executable.\r\n        if(-not $Executable){\r\n            Write-Host -Object \"[Error] Unable to find uninstall executable!\"\r\n            exit 1\r\n        }\r\n\r\n        # Split uninstall string into executable and possible arguments\r\n        $PossibleArguments = $_.UninstallString -split ' ' | ForEach-Object { $_.Trim() } | Where-Object { $_ -match \"^\/\"}\r\n\r\n        # Decide executable and additional arguments based on uninstall string analysis\r\n        $i = 0\r\n        foreach ($PossibleArgument in $PossibleArguments) {\r\n            if (-not ($PossibleArgument -match \"^\/I{\") -and $PossibleArgument) {\r\n                $AdditionalArguments.Add($PossibleArgument)\r\n            }\r\n\r\n            if ($PossibleArgument -match \"^\/I{\") {\r\n                $AdditionalArguments.Add(\"$($PossibleArgument -replace '\/I', '\/X')\")\r\n            }\r\n\r\n            $i++\r\n        }\r\n\r\n        # Add custom arguments from the user\r\n        if ($Arguments) {\r\n            $Arguments.Split(',') | ForEach-Object {\r\n                $AdditionalArguments.Add($_.Trim())\r\n            }\r\n        }\r\n\r\n        # Add the usual silent uninstall arguments if not present\r\n        if($Executable -match \"Msiexec\"){\r\n            if($AdditionalArguments -notcontains \"\/qn\"){\r\n                $AdditionalArguments.Add(\"\/qn\")\r\n            }\r\n\r\n            if($AdditionalArguments -notcontains \"\/norestart\"){\r\n                $AdditionalArguments.Add(\"\/norestart\")\r\n            }\r\n        }elseif($Executable -match \"\\.exe\"){\r\n            if($AdditionalArguments -notcontains \"\/S\"){\r\n                $AdditionalArguments.Add(\"\/S\")\r\n            }\r\n\r\n            if($AdditionalArguments -notcontains \"\/norestart\"){\r\n                $AdditionalArguments.Add(\"\/norestart\")\r\n            }\r\n        }\r\n\r\n        # Verify that executable for uninstallation is found\r\n        if (-not $Executable) {\r\n            Write-Host \"[Error] Could not find the executable from the uninstall string!\"\r\n            exit 1\r\n        }\r\n\r\n        # Start the uninstallation process\r\n        Write-Host -Object \"Beginning uninstall of $($_.DisplayName) using $Executable $AdditionalArguments...\"\r\n        try{\r\n            if ($AdditionalArguments) {\r\n                $Uninstall = Start-Process $Executable -ArgumentList $AdditionalArguments -NoNewWindow -PassThru\r\n            }\r\n            else {\r\n                $Uninstall = Start-Process $Executable -NoNewWindow -PassThru\r\n            }\r\n        }catch{\r\n            Write-Host \"[Error] $($_.Exception.Message)\"\r\n            return\r\n        }\r\n\r\n        # Calculate the remaining time for the uninstall process and enforce timeout\r\n        $TimeElapsed = (Get-Date) - $StartTime\r\n        $RemainingTime = $TimeoutInSeconds - $TimeElapsed.TotalSeconds\r\n\r\n        # Wait for the uninstall process to complete within the remaining time\r\n        try {\r\n            $Uninstall | Wait-Process -Timeout $RemainingTime -ErrorAction Stop\r\n        }\r\n        catch {\r\n            Write-Host -Object \"[Alert] The uninstall process for $($_.DisplayName) has exceeded the specified timeout of $Timeout minutes.\"\r\n            Write-Host -Object \"[Alert] The script is now terminating.\"\r\n            $Uninstall | Stop-Process -Force\r\n            $ExitCode = 1\r\n        }\r\n\r\n        # Check and report the exit code of the uninstallation process\r\n        Write-Host -Object \"Exit code for $($_.DisplayName): $($Uninstall.ExitCode)\"\r\n        if ($Uninstall.ExitCode -ne 0) {\r\n            Write-Host -Object \"[Error] Exit code does not indicate success!\"\r\n            $ExitCode = 1\r\n        }\r\n    }\r\n\r\n    # Pause for 30 seconds before final checks\r\n    Start-Sleep -Seconds 30\r\n\r\n    $UserProfiles = Get-UserHives -Type \"All\"\r\n    $ProfileWasLoaded = New-Object System.Collections.Generic.List[string]\r\n\r\n    # Loop through each profile on the machine.\r\n    Foreach ($UserProfile in $UserProfiles) {\r\n        # Load user's NTUSER.DAT if it's not already loaded.\r\n        If ((Test-Path Registry::HKEY_USERS\\$($UserProfile.SID)) -eq $false) {\r\n            Start-Process -FilePath \"cmd.exe\" -ArgumentList \"\/C reg.exe LOAD HKU\\$($UserProfile.SID) `\"$($UserProfile.UserHive)`\"\" -Wait -WindowStyle Hidden\r\n            $ProfileWasLoaded.Add(\"$($UserProfile.SID)\")\r\n        }\r\n    }\r\n\r\n    # Re-check for any remaining apps to confirm they were uninstalled\r\n    $SimilarAppsToName = $AppNames | ForEach-Object { Find-UninstallKey -DisplayName $_ }\r\n    $SimilarAppsToName | ForEach-Object {\r\n        foreach ($AppName in $AppNames) {\r\n            if ($_.DisplayName -eq $AppName) {\r\n                Write-Host -Object \"[Error] Failed to uninstall $($_.DisplayName).\"\r\n                $UninstallFailure = $True\r\n                $ExitCode = 1\r\n            }\r\n        }\r\n    }\r\n\r\n    # Unload all hives that were loaded for this script.\r\n    ForEach ($UserHive in $ProfileWasLoaded) {\r\n        If ($ProfileWasLoaded -eq $false) {\r\n            [gc]::Collect()\r\n            Start-Sleep 1\r\n            Start-Process -FilePath \"cmd.exe\" -ArgumentList \"\/C reg.exe UNLOAD HKU\\$($UserHive)\" -Wait -WindowStyle Hidden | Out-Null\r\n        }\r\n    }\r\n\r\n    # Confirm successful uninstallation if no failures detected\r\n    if (-not $UninstallFailure) {\r\n        Write-Host \"Successfully uninstalled your requested apps!\"\r\n    }\r\n\r\n    # Handle reboot if requested and there were no uninstall failures\r\n    if ($Reboot -and -not $UninstallFailure) {\r\n        Write-Host -Object \"[Alert] a reboot was requested. Scheduling restart for 60 seconds from now...\"\r\n        Start-Process shutdown.exe -ArgumentList \"\/r \/t 60\" -Wait -NoNewWindow\r\n    }\r\n\r\n    # Exit script with the final exit code\r\n    exit $ExitCode\r\n}\r\nend {\r\n    \r\n    \r\n    \r\n}\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n\n<div class=\"blog-cta-new blog-cta-style-1\"><div class=\"cta-left\"><h2><\/h2><p><\/p><\/div><div class=\"cta-right\"><a class=\"button\" href=\"\"><\/a><\/div><\/div>\n<h2>Come funziona lo script<\/h2>\n<p>Questo script \u00e8 stato progettato per automatizzare la disinstallazione delle applicazioni in base ai loro nomi e gestisce una serie di scenari che potrebbero verificarsi durante il processo di disinstallazione. Di seguito viene illustrato passo per passo il funzionamento dello script:<\/p>\n<h3>1. Definizione dei parametri e gestione dell\u2019input:<\/h3>\n<ul>\n<li>Lo script per automatizzare la disinstallazione delle applicazioni inizia definendo diversi parametri, come -Name per il nome dell&#8217;applicazione, -Arguments per gli argomenti aggiuntivi della disinstallazione, -Reboot per pianificare un riavvio e -Timeout per specificare quanto tempo lo script deve attendere per il processo di disinstallazione.<\/li>\n<li>Lo script per automatizzare la disinstallazione delle applicazioni controlla quindi se questi parametri sono stati forniti e li convalida, assicurandosi che soddisfino criteri specifici, come ad esempio che il valore di timeout sia compreso tra 1 e 60 minuti.<\/li>\n<\/ul>\n<h3>2. Gestione del profilo e dell&#8217;hive utente:<\/h3>\n<ul>\n<li>Include una funzione per caricare e gestire i profili utente e gli hive del registro di sistema, necessari per accedere alle stringhe di disinstallazione per ogni applicazione. Questo \u00e8 fondamentale perch\u00e9 la disinstallazione di un&#8217;applicazione richiede spesso l&#8217;accesso al registro di sistema per individuare il percorso di disinstallazione corretto.<\/li>\n<\/ul>\n<h3>3. Identificazione dell&#8217;applicazione e recupero della chiave di disinstallazione:<\/h3>\n<ul>\n<li>Lo script per automatizzare la disinstallazione delle applicazioni utilizza una funzione chiamata Find-UninstallKey per cercare nel registro di sistema e individuare la chiave di disinstallazione associata al nome dell&#8217;applicazione fornito. Questa operazione viene eseguita in diverse posizioni del registro, sia a 32 che a 64 bit, per garantire una copertura completa.<\/li>\n<\/ul>\n<h3>4. Processo di disinstallazione:<\/h3>\n<ul>\n<li>Una volta identificata la stringa di disinstallazione, lo script per automatizzare la disinstallazione delle applicazioni la elabora per estrarre il percorso dell&#8217;eseguibile e gli argomenti necessari per la disinstallazione.<\/li>\n<li>Assicura che vengano aggiunti gli argomenti necessari per la disinstallazione silenziosa, come \/qn, \/norestart o \/S, se non sono gi\u00e0 presenti. Questo assicura che la disinstallazione venga eseguita senza l&#8217;interazione dell&#8217;utente e senza forzare il riavvio del sistema, a meno che non sia specificato.<\/li>\n<\/ul>\n<h3>5. Gestione degli errori e controlli finali:<\/h3>\n<ul>\n<li>Lo script per automatizzare la disinstallazione delle applicazioni include una solida gestione degli errori, che garantisce che, se qualcosa dovesse storto durante la disinstallazione, l&#8217;amministratore ne verrebbe informato e lo script terminerebbe con un codice di errore appropriato.<\/li>\n<li>Dopo la disinstallazione, lo script controlla nuovamente che l&#8217;applicazione sia stata effettivamente rimossa, assicurandosi che non rimangano componenti residui.<\/li>\n<\/ul>\n<h2>Campi di applicazione pratici: Un caso di studio<\/h2>\n<p>Immagina uno scenario in cui un amministratore IT deve disinstallare una versione obsoleta di VLC Media Player da 200 computer di un&#8217;organizzazione. Fare questa operazione manualmente richiederebbe molto tempo. L&#8217;amministratore potrebbe invece distribuire questo script PowerShell per automatizzare la disinstallazione delle applicazioni su tutti i computer, specificando &#8220;VLC Media Player&#8221; come nome dell&#8217;applicazione.<\/p>\n<p>Lo script individuerebbe automaticamente la stringa di disinstallazione appropriata, eseguirebbe la disinstallazione in modo silenzioso e, se necessario, programmerebbe un riavvio. L&#8217;intero processo, che avrebbe potuto richiedere giorni, grazie allo script per automatizzare la disinstallazione delle applicazioni viene completato in pochi minuti.<\/p>\n<h2>Confronto con altri metodi<\/h2>\n<p>Tradizionalmente, gli amministratori possono utilizzare il Pannello di controllo o uno strumento di disinstallazione di terze parti per rimuovere le applicazioni. Tuttavia, questi metodi richiedono un intervento manuale, non sono scalabili e spesso mancano della flessibilit\u00e0 necessaria per aggiungere argomenti personalizzati o gestire efficacemente le disinstallazioni silenziose.<\/p>\n<p>Questo script, invece, offre un approccio altamente automatizzato e personalizzabile, consentendo ai professionisti IT di gestire le disinstallazioni su pi\u00f9 macchine in modo efficiente e con una necessit\u00e0 minima di input manuale.<\/p>\n<h2>Domande frequenti<\/h2>\n<ol>\n<li><strong>Cosa succede se il nome dell&#8217;applicazione non viene trovato?<\/strong> Se lo script per automatizzare la disinstallazione delle applicazioni non riesce a trovare un&#8217;applicazione con il nome esatto fornito, cercher\u00e0 nomi simili e fornir\u00e0 un elenco di possibili corrispondenze. In questo modo l&#8217;amministratore pu\u00f2 modificare l\u2019input e riprovare.<\/li>\n<li><strong>Lo script pu\u00f2 gestire pi\u00f9 applicazioni contemporaneamente?<\/strong>\u00a0S\u00ec, il parametro -Name pu\u00f2 accettare un elenco di applicazioni separate da virgole, consentendo allo script di disinstallare pi\u00f9 applicazioni in una sola volta.<\/li>\n<li><strong>Cosa succede se il processo di disinstallazione supera il periodo di timeout?<\/strong>\u00a0Lo script terminer\u00e0 il processo di disinstallazione ed uscir\u00e0 con un codice di errore, assicurando che nessun processo venga eseguito all&#8217;infinito.<\/li>\n<\/ol>\n<h2>Implicazioni per la sicurezza e la gestione dell&#8217;IT<\/h2>\n<p>L&#8217;automazione del processo di disinstallazione con script di questo tipo ha implicazioni significative per la gestione e la <a href=\"https:\/\/www.ninjaone.com\/it\/blog\/checklist-della-sicurezza-informatica-per-proteggere-le-aziende\/\" target=\"_blank\" rel=\"noopener\">sicurezza IT<\/a>. Assicurandosi che il software obsoleto o vulnerabile venga rimosso rapidamente e in modo coerente su tutti i computer, le organizzazioni possono ridurre il rischio di <a href=\"https:\/\/www.ninjaone.com\/it\/it-hub\/sicurezza-degli-endpoint\/cos-e-una-violazione-dei-dati\/\" target=\"_blank\" rel=\"noopener\">violazioni di sicurezza<\/a>. Inoltre, l&#8217;automazione <a href=\"https:\/\/www.ninjaone.com\/it\/blog\/come-l-errore-umano-influisce-sui-rischi-di-cybersecurity\/\" target=\"_blank\" rel=\"noopener\">riduce l&#8217;errore umano<\/a>, garantendo che nessuna applicazione venga disinstallata a causa di una svista.<\/p>\n<h2>Best practice per l&#8217;utilizzo dello script<\/h2>\n<ul>\n<li><strong>Testa sempre lo script per automatizzare la disinstallazione delle applicazioni in un ambiente controllato:<\/strong> Prima di distribuire lo script per automatizzare la disinstallazione delle applicazioni su pi\u00f9 macchine, testalo in un ambiente controllato per assicurarti che funzioni come previsto.<\/li>\n<li><strong>Conserva i log:<\/strong>\u00a0Conserva i log dei processi di disinstallazione per scopi di revisione e risoluzione dei problemi.<\/li>\n<li><strong>Esegui il backup prima della disinstallazione:<\/strong>\u00a0Assicurati di eseguire il backup dei dati importanti prima di eseguire gli script di disinstallazione, in particolare per le applicazioni che potrebbero memorizzare i dati in locale.<\/li>\n<li><strong>Aggiorna regolarmente lo script per automatizzare la disinstallazione delle applicazioni:<\/strong> Quando vengono rese disponibili nuove applicazioni e aggiornamenti, aggiorna lo script per gestire le nuove stringhe e i nuovi metodi di disinstallazione.<\/li>\n<\/ul>\n<h2>Considerazioni finali<\/h2>\n<p>Gli script PowerShell come quello per automatizzare la disinstallazione delle applicazioni sono strumenti indispensabili per i professionisti IT che gestiscono reti di grandi dimensioni. Automatizzando la disinstallazione delle applicazioni, permettono di risparmiare tempo, di ridurre gli errori e di migliorare la sicurezza. <a href=\"https:\/\/www.ninjaone.com\/it\/\" target=\"_blank\" rel=\"noopener\">NinjaOne<\/a> pu\u00f2 integrare questi script con i suoi strumenti completi di gestione IT, fornendo <a href=\"https:\/\/www.ninjaone.com\/it\/blog\/tutto-quello-che-bisogna-sapere-sull-automazione-it\/\" target=\"_blank\" rel=\"noopener\">ulteriori livelli di automazione<\/a>, monitoraggio e controllo, e assicurando che la tua infrastruttura IT rimanga solida, <a href=\"https:\/\/www.ninjaone.com\/it\/i-5-principali-fondamenti-della-sicurezza-it\" target=\"_blank\" rel=\"noopener\">sicura<\/a> e aggiornata.<\/p>\n","protected":false},"author":35,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"_acf_changed":false,"_relevanssi_hide_post":"","_relevanssi_hide_content":"","_relevanssi_pin_for_all":"","_relevanssi_pin_keywords":"","_relevanssi_unpin_keywords":"","_relevanssi_related_keywords":"","_relevanssi_related_include_ids":"","_relevanssi_related_exclude_ids":"","_relevanssi_related_no_append":"","_relevanssi_related_not_related":"","_relevanssi_related_posts":"","_relevanssi_noindex_reason":"","_lmt_disableupdate":"","_lmt_disable":""},"operating_system":[4212],"use_cases":[4269],"class_list":["post-353756","script_hub","type-script_hub","status-publish","hentry","script_hub_category-windows"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/script_hub\/353756","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/script_hub"}],"about":[{"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/types\/script_hub"}],"author":[{"embeddable":true,"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/users\/35"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/comments?post=353756"}],"wp:attachment":[{"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/media?parent=353756"}],"wp:term":[{"taxonomy":"script_hub_category","embeddable":true,"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/operating_system?post=353756"},{"taxonomy":"use_cases","embeddable":true,"href":"https:\/\/www.ninjaone.com\/it\/wp-json\/wp\/v2\/use_cases?post=353756"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}