Maintaining Adobe Flash
Although as we all know Adobe Flash is a product which has caused quite a lot of security related news over the past number and years, and Adobe is to discontinue it in 2020, however for some organisations there is still a requirement to maintain the product.
Exit Code 1603
Recently I was asked to push out an upgraded version of the Flash PPAPI for use with Google Chrome, and quickly came up against the 1603 exit code issue that Nickolaj covers in an earlier post from 2013 (https://msendpointmgr.com/2013/05/23/upgrade-adobe-flash-player-11-7-x-fails-with-error-1603-in-configmgr-2012/).
I decided to write a PowerShell script to cater for upgrading Flash. The script perform the following actions:
- Search the registry for Uninstall strings for versions earlier than the detected MSI version from both the “HKLM:SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall” and “HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall” locations
- Run the MSIEXEC command silently with the uninstall string
- Query WMI to obtain a list of registered versions
Legacy Adobe Flash PPAPI Example – Listed in WMI - Remove earlier registered Flash versions from the Regsitry
- Install the MSI contained within the package.
Prerequisite’s
- To deploy Flash you will need an account with Adobe and to sign up for their distribution license (https://www.adobe.com/products/flashplayer/distribution.html).
PowerShell Script
<# .SYNOPSIS Adobe Flash Upgrade Script. .DESCRIPTION This script will uninstall and remove entries for Adobe Flash installers. Package the script up with the installer MSI and it will remove previous versions and install the version contained within the pacakge. If the same version is found, no action will be taken. .EXAMPLE .\AdobeFlashUpgrade.ps1 .NOTES FileName: AdobeFlashUpgrade.ps1 Authors: Maurice Daly Contact: @modaly_it Created: 2017-08-18 Updated: 2017-08-22 Version history: 1.0.0 - (2017-08-18) Script created (Maurice Daly) 1.0.1 - (2017-08-22) Updated old product detection method to check registry entries as opposed WMI and attempt to locate the legacy installer to uninstall the product. Added command to close all browsers prior to the uninstall/installation #> function GetMSIFileInformation { param (
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()] [System.IO.FileInfo]$Path,
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()] [ValidateSet(“ProductCode”, “ProductVersion”, “ProductName”, “Manufacturer”, “ProductLanguage”, “FullVersion”)] [string]$Property ) Process { try { # Read property from MSI database $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer $MSIDatabase = $WindowsInstaller.GetType().InvokeMember(“OpenDatabase”, “InvokeMethod”, $null, $WindowsInstaller, @($Path.FullName, 0)) $Query = “SELECT Value FROM Property WHERE Property = ‘$($Property)'” $View = $MSIDatabase.GetType().InvokeMember(“OpenView”, “InvokeMethod”, $null, $MSIDatabase, ($Query)) $View.GetType().InvokeMember(“Execute”, “InvokeMethod”, $null, $View, $null) $Record = $View.GetType().InvokeMember(“Fetch”, “InvokeMethod”, $null, $View, $null) $Value = $Record.GetType().InvokeMember(“StringData”, “GetProperty”, $null, $Record, 1) # Commit database and close view $MSIDatabase.GetType().InvokeMember(“Commit”, “InvokeMethod”, $null, $MSIDatabase, $null) $View.GetType().InvokeMember(“Close”, “InvokeMethod”, $null, $View, $null) $MSIDatabase = $null $View = $null # Return the value return $Value } catch { Write-Warning -Message $_.Exception.Message; break } } End { # Run garbage collection and release ComObject [System.Runtime.Interopservices.Marshal]::ReleaseComObject($WindowsInstaller) | Out-Null [System.GC]::Collect() } } function Uninstall { param (
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()] $Installations ) foreach ($Installation in $Installations) { if ($Installation -ne $null) { try { $UninstallArgs = $((($Installation.UninstallString).Split(” “) | Select -Last 1) + ” /qn”) Start-Process msiexec.exe -ArgumentList $UninstallArgs -Wait } catch { Write-Warning -Message $_.Exception.Message; break } } } } function Install { param (
[parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()] $AdobeMSI ) if ($AdobeMSI -ne $null) { try { Start-Process msiexec.exe -ArgumentList (“/i” + $AdobeMSI.fullName + ” /qn”) -Wait } catch { Write-Warning -Message $_.Exception.Message; break } } } # Get OS Architecture $OSArchitecture = (Get-WmiObject -Query “Select OSArchitecture from Win32_OperatingSystem”).OSArchitecture # Get Adobe Flash Full Product Name $AdobeMSI = Get-ChildItem -Filter *.msi | Sort-Object LastWriteTime -Descending | select -First 1 $AdobeProductName = ([string](GetMSIFileInformation -Path $AdobeMSI.FullName -Property ProductName)).Trim() $AdobeProductVersion = ([string](GetMSIFileInformation -Path $AdobeMSI.FullName -Property ProductVersion)).Trim() # Attempt Uninstall $32BitInstallations = Get-ChildItem -Path “HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall” | Get-ItemProperty | Where-Object { ($_.DisplayName -match ($AdobeProductName.Split(” “) | select -Last 1)) -and ($_.DisplayName -match “Adobe”) } if (($32BitInstallations -ne $null) -and ($32BitInstallations.DisplayVersion -ne $AdobeProductVersion)) { Get-Process | Where-Object { ($_.ProcessName -eq “MicrosoftEdge”) -or ($_.ProcessName -eq “Chrome”) -or ($_.ProcessName -eq “Iexplore”) -or ($_.ProcessName -eq “Firefox”) } | Stop-Process -Force Uninstall -Installations $32BitInstallations } if ($OSArchitecture -match “64”) { $64BitInstallations = Get-ChildItem -Path “HKLM:SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall” | Get-ItemProperty | Where-Object { ($_.DisplayName -match ($AdobeProductName.Split(” “) | select -Last 1)) -and ($_.DisplayName -match “Adobe”) } if (($64BitInstallations -ne $null) -and ($64BitInstallations.DisplayVersion -ne $AdobeProductVersion)) { Get-Process | Where-Object { ($_.ProcessName -eq “MicrosoftEdge”) -or ($_.ProcessName -eq “Chrome”) -or ($_.ProcessName -eq “Iexplore”) -or ($_.ProcessName -eq “Firefox”) } | Stop-Process -Force Uninstall -Installations $64BitInstallations } } # List all Adobe Flash Installs $FlashInstallations = Get-ChildItem -Path “HKLM:\SOFTWARE\Classes\Installer\Products” | Get-ItemProperty | Where-Object { ($_.ProductName -notmatch $AdobeProductName) -and ($_.Name -match ($AdobeProductName.Split(” “) | select -Last 1)) } # Remove Adobe Flash product entries from the Registry foreach ($FlashInstallation in $FlashInstallations) { if (!([string]::IsNullOrEmpty($FlashInstallation.PSChildName))) { $RegistryBase = “HKLM:\SOFTWARE\Classes\Installer\Products\” $RegistryEntry = $RegistryBase + $FlashInstallation.PSChildName $InstallerDetails = Get-ChildItem -Path (“HKLM:\SOFTWARE\Classes\Installer\Products\” + $FlashInstallation.PSChildName) | Get-ItemProperty $InstallerSource = ($InstallerDetails.LastUsedSource).Split(“;”) | select -Last 1 if ((Test-Path -Path $InstallerSource) -eq $true) { $LegacyUninstallArgs = “/X ” + $InstallerSource + ” /qn” try { Start-Process msiexec.exe -ArgumentList $LegacyUninstallArgs } catch { Write-Warning -Message $_.Exception.Message; break } } if (($RegistryEntry -ne $RegistryBase) -and (test-path $RegistryEntry -eq $true)) { Write-Host “Removing Registry Entries” $RegistryEntry | Remove-Item -Recurse -Force } } } # Install Adobe Flash if (($32BitInstallations -eq $null) -or ($32BitInstallations.DisplayVersion -ne $AdobeProductVersion) -and ($OSArchitecture -match “32”)) { # Install latest Adobe Flash component Install $AdobeMSI } elseif (($64BitInstallations -eq $null) -or ($64BitInstallations.DisplayVersion -ne $AdobeProductVersion) -and ($OSArchitecture -match “64”)) { # Install latest Adobe Flash component Install $AdobeMSI }
Creating the Application Package
Now let’s go about creating the Application package using the script installer method. First things first is to create a location where both the MSI and PS1 are stored, then proceed with the below;
- Open the Systems Center Configuration Manager Console
- Click on the Software Library tab
- Expand Application Management and right click on Applications
- Right click and click Create Application
- Select the option to “Manually specify the application information“
- Name your package and make sure to include the Software Version as this will be used to cross reference against the GUID used for detection and uninstalling the software
- Add in an Icon to make it look good in the Software Center
- On the Deployment Types screen click on the Add button
- Select Script Installer as the type
- Specify the content location and enter the following details
- Installation Program
- PowerShell.exe -ExecutionPolicy Bypass -File AdobeFlashUpgrade.ps1
- Uninstall Program
- Msiexec /x {GUID} /qn
- The GUID can be obtained for the particular version of Adobe Flash you are deploying from the following URL – https://helpx.adobe.com/flash-player/kb/msi-guids-windows.html
- Installation Program
- You should now have something that looks similar to the below
- For the Detection Method use the Setting Type “Windows Installer” and enter the GUID obtained previously
- Finish the Wizard
- Deploy the Application
Software Center
Refresh the computer policy on a machine within the collection you deployed the application to. Select the Adobe Flash Player app and click install.
FUTURE DEPLOYMENTS
Using this method the only thing you need to do is change the detection and uninstall GUID values, as the script will take care of uninstalling the currently installed version.
They actually make a small uninstall utility available that handles this: https://helpx.adobe.com/flash-player/kb/uninstall-flash-player-windows.html
Adobe do indeed provide this and you could automate a process to use the “uninstall_flash_player.exe -uninstall” command to silently remove the flash components. I wanted to explore PowerShell methods though as not all applications have uninstall utilities and the 1603 exit code is something that often comes up, so the logic contained within the script can be tailored for this.
Hi.
That uninstaller utility will uninstall all versions of Flash players, even if you need to remove only ActiveX, or plugin, which is unacceptable for automated deployments, like with SCCM
Hi,
Nice write up.
I have been using something similar, but the simpler script to remove older versions of the Flash Player. I wrote a post about it last year: https://www.itninja.com/blog/view/deploying-adobe-flash-player-currently-23-0-0-205-with-sccm2012-current-branch-previously-removing-all-old-versions
I know versions changed, but the script is almost the same, may need changing of the installed filename.