function Remove-PackagesThatAreAlreadyInstalled { <# .SYNOPSIS Given a list of packages, and a hashtable of packagename->unique-versions-of-package, return a list of packages that actually need to be installed. .PARAMETER PackagesToInstall An array of packages to be installed .PARAMETER PackageMetadata The giant list of all the things from Classify Packages. .PARAMETER DebugMetadata Not used, but supplied from Classify Packages. Intentionally left here with the expectation of adding additional properties to it which might be passed through. #> [CmdletBinding()] [Diagnostics.CodeAnalysis.SuppressMessageAttribute("DebugMetadata", '', Justification="Intentionally left here with the expectation of adding additional properties to it which might be passed through.", Scope = "Function")] param ( [array]$PackagesToInstall, $PackageMetadata, $DebugMetadata ) if (Test-IsCollectionNullOrEmpty $PackagesToInstall) { return @() } # Declare a hashtable to track which packages we are going to preserve from the install list. $packagesToKeep = @{ } # Cache the combinations of serversToInstall so we don't recreate them / resize arrays thousands of times. $serversToInstallCache = @{} # Filter packages to be installed by what is installed in the environment. foreach ($package in $PackagesToInstall) { $lowerName = $package.Name.ToLower() $packageIsInstalled = $PackageMetadata.PackageToVersions.ContainsKey($lowerName) $packageIsInUninstallList = ($PackageMetadata.WebPackagesToUninstall.Name -contains $package.Name) -or ($PackageMetadata.AppPackagesToUninstall.Name -contains $package.Name) # Install the package if it's not installed at all. if (!$packageIsInstalled) { $packagesToKeep[$lowerName] = $true continue } # Install the package if it is in either uninstall list # Case 1 - Uninstalling from App to Install on Web in the case of a misplaced widget # Case 2 - Forcing an uninstall/reinstall - maybe the wrong version got installed or partly installed if ($packageIsInUninstallList) { $packagesToKeep[$lowerName] = $true continue } # Otherwise figure out if we need to install/force-reinstall the package. # Get the different versions of the package on-hand. [array]$versionsOfPackage = $PackageMetadata.PackageToVersions[$lowerName] # We are reinstalling ORB if ($PackageMetadata.ForceReinstallPackages) { # If it's a package type that is reinstalled with ORB, or must reinstall for the same version of the package, keep the package. if ($package.ReinstallWithORB -or $package.ForceSameVersion) { $packagesToKeep[$lowerName] = $true continue } } # If there are multiple versions of the package installed, keep the package. # Hopefully this will standardize that same version everywhere. if ($versionsOfPackage.Count -gt 1) { $packagesToKeep[$lowerName] = $true continue } # Otherwise if there is one version of the package, keep it only if it is NOT the version we are trying to install. if ($packageIsInstalled -and ($versionsOfPackage.Count -eq 1) -and ($versionsOfPackage[0] -ne $package.Version)) { $packagesToKeep[$lowerName] = $true continue } # Make sure that this package is on all of the servers its supposed to be installed on. # Produce the combination of servers that the package needs to be installed to. # Cache the combinations of serversToInstall so that we don't recreate them thousands of times. $serversToInstallKey = 1 * [int]($package.InstallToWeb) + 2 * [int]($package.InstallToFab) + 4 * [int]($package.InstallToMic) + 8 * [int]($package.InstallToApp) if($serversToInstallCache.ContainsKey($serversToInstallKey)) { $serversToInstall = $serversToInstallCache[$serversToInstallKey] } else { $serversToInstall = @() if($package.InstallToWeb) { $serversToInstall += $PackageMetadata.WebServers; } if($package.InstallToFab) { $serversToInstall += $PackageMetadata.FabServers; } if($package.InstallToMic) { $serversToInstall += $PackageMetadata.MicServers; } if($package.InstallToApp) { $serversToInstall += $PackageMetadata.AppServers; } $serversToInstall = $serversToInstall | Where-Object { $null -ne $_ } $serversToInstallCache[$serversToInstallKey] = $serversToInstall } # If the package is not installed on all of the servers it should be installed on, then keep the package. $installedServers = $PackageMetadata.PackageToServers[$lowerName] $installedToAllServers = $true foreach($server in $serversToInstall) { if($installedServers -notcontains $server) { $installedToAllServers = $false break } } if(!$installedToAllServers -or $packageIsInUninstallList) { $packagesToKeep[$lowerName] = $true continue } Write-Host "Package $($package.Name) is already installed on all servers. Removing from list of packages to deploy" # Now only packages we care to install/reinstall are in $packagesToKeep! } # Filter the install packages down to the packages we intend on keeping. [array]$PackagesToInstall = $PackagesToInstall | Where-Object { $packagesToKeep.ContainsKey($_.Name.ToLower()) } return $PackagesToInstall }