If you work in a large enterprise you will have had to deploy Flash Player to your workstations and if you have, you will know that it has more security holes than swiss cheese and needs updating very often. Trying to keep control of this is the road to madness so let’s automate the sh#! out of it.
In the past I used to disable the auto update as it just annoys the end user and would try to keep it up to date but this causes more problems than it solves.
Controlled automation is the solution.
Broadly what i did
- Create an application and deployment for Adobe Flash Player(IE and Firefox versions).
- Create a Configuration item to make sure it’s set to auto update.
- Create and deploy a Configuration Baseline.
- Update the Adobe Flash Player scheduled task.
- Never have to worry about flash again until Adobe retire the product.
Update existing versions
In my environment we use SNOW Licence Manager, this can give a detailed reports of all software and more importantly what versions of said software. What i found was not encouraging, the versions ranged from 9 to 22.
It was important to update all installations to the latest version and that can act as my baseline to work off for the future.
This was before, pretty bad.
Application Name | Installation |
Adobe Flash Player 9 | 42 |
Adobe Flash Player 10 | 89 |
Adobe Flash Player 11 | 368 |
Adobe Flash Player 14 | 97 |
Adobe Flash Player 17 | 1203 |
Adobe Flash Player 18 | 437 |
Adobe Flash Player 19 | 868 |
Adobe Flash Player 20 | 1489 |
Adobe Flash Player 22 | 107 |
Download Flash Player MSI
Go to the flash distribution page found here – https://www.adobe.com/uk/products/flashplayer/distribution5.html
Note:
- You will need to apply to Adobe for a distribution license to access this site
- As of windows 8 flash has been embed into IE and Edge
- Chrome has flash built in and its better to let chrome update itself rather than deploy the PPAPI version
Create and deploy Adobe Flash Player
Using the voodoo power of PowerShell create the adobe applications and deploy them to all workstations, obviously change as needed
Script;
<# .NOTES =========================================================================== Created on: 09/11/2016 10:56 Created by: Terence Beggs & Maurice Daly Organization: Filename: AdobeFlashDeployment.ps1 =========================================================================== .DESCRIPTION Adds Adobe Flash Player MSIs to your SCCM Application list. The Script assumes the following folder structure exists in your software repository path provided - "Adobe\Flash Player" .EXAMPLE AdobeFlashDeployment.ps1 -SiteCode SCM -RepositoryPath \\YOURSERVER\UNCSHARE -IconPath \\YOURSERVER\UNCSHARE\ICONS\ADOBEFLASH.ICO Note that you do not have to specify an icon .NOTES MSI Database Function sourced from https://msendpointmgr.com/2014/08/22/how-to-get-msi-file-information-with-powershell/ #> [CmdletBinding(SupportsShouldProcess = $true)] param (
[parameter(Mandatory = $true, HelpMessage = “SCCM Site Code Required”, Position = 1)]
[ValidateNotNullOrEmpty()] [string]$SiteCode,
[parameter(Mandatory = $true, HelpMessage = “Base UNC path of your packages”)]
[ValidateNotNullOrEmpty()] [ValidateScript({ Test-Path $_ })] [string]$RepositoryPath,
[parameter(Mandatory = $false, HelpMessage = “Please indicate if you wish to specify a custom icon, default is false”)]
[ValidateNotNullOrEmpty()] [bool]$SpecifyIcon = $false,
[parameter(Mandatory = $false, HelpMessage = “Location of .ICO or PNG to use as the application icon”)]
[ValidateNotNullOrEmpty()] [ValidateScript({ Test-Path $_ })] [string]$IconPath ) # Import SCCM PowerShell Module $ModuleName = (get-item $env:SMS_ADMIN_UI_PATH).parent.FullName + “\ConfigurationManager.psd1” Import-Module $ModuleName Write-Debug “Site Code In Use : $SiteCode” # Specify Adobe Flash Folder $AdobeFlashDir = “\Adobe Systems\Flash Player\” # Remove back slash if added to the RepositoryPath $RepositoryPath = $RepositoryPath.Trimend(“\”) Write-Debug “Package UNC Base Path In Use : $RepositoryPath” # Specify SCCM Collection $AllWksCollection = “All Active Workstations” function GetMSIDetails ($MSI, $Property) { Process { Write-Debug “Function $MSI” Write-Debug “Fuction $Property” try { # Read property from MSI database $WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer Write-Debug “FullName = $($MSI.FullName)” $MSIDatabase = $WindowsInstaller.GetType().InvokeMember(“OpenDatabase”, “InvokeMethod”, $null, $WindowsInstaller, @($MSI.FullName, 0)) Write-Debug “MSIDatabase = $MSIDatabase” # Read properties $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) Write-Debug “Value = $Value” # 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() } } foreach ($MSI in (Get-ChildItem -Path ($RepositoryPath + $AdobeFlashDir) -Filter *.MSI | Sort-Object $_.LastWriteTime | select -First 2)) { Write-Debug “Collecting details for $MSI file” $Property = “Manufacturer” $Manufacturer = (GetMSIDetails ($MSI)($Property)) $Manufacturer = ([string]$Manufacturer).Trim() Write-Debug “Manufacturer: $ProductName” $Property = “ProductName” $ProductName = (GetMSIDetails ($MSI)($Property)) $ProductName = ([string]$ProductName).Trim() Write-Debug “Product Name: $ProductName” $Property = “ProductVersion” $ProductVersion = (GetMSIDetails ($MSI)($Property)) $ProductVersion = ([string]$ProductVersion).Trim() Write-Debug “Querying MSI Details” Set-Location -Path ($SiteCode + “:”) if ((Get-CMApplication -Name $ProductName) -ne $null) { Write-Debug “Running Application Creation for $ProductName” ######################################### # Create Application with Icon ######################################### If ($SpecifyIcon -ne $false) { Write-Debug “Creating application with icon $IconPath specified” # Custom icon specified New-CMApplication -Name “$ProductName” -IconLocationFile $IconPath -LocalizedDescription $ProductName -LocalizedName $ProductName -Publisher $Manufacturer -SoftwareVersion $ProductVersion } else { Write-Debug “Creating application without optional icon specified” ######################################### # Create Application without Icon ######################################### New-CMApplication -Name “$ProductName” -LocalizedDescription $ProductName -LocalizedName $ProductName -Publisher $Manufacturer -SoftwareVersion $ProductVersion } ######################################### # Create Deployment Types ######################################### Add-CMDeploymentType -DeploymentTypeName $ProductName -ApplicationName $ProductName -InstallationFileLocation $MSI.FullName -MsiInstaller -AutoIdentifyFromInstallationFile -ForceForUnknownPublisher $true -InstallationBehaviorType InstallForSystem -Verbose ######################################### # Distripute Content ######################################### Start-CMContentDistribution -ApplicationName $ProductName -DistributionPointGroupName “All Distribution Points” -Verbose ######################################### # Create Application Deployment ######################################### Start-CMApplicationDeployment -CollectionName $AllWksCollection -Name $ProductName -AvailableDate (get-date) -AvailableTime (get-date) -DeployAction Install -DeployPurpose Required -TimeBaseOn LocalTime } else { Write-Warning -Message “$ProductName already exists. Skipping..” } } ######################################### # Refresh Policy on collection ######################################### Start-Sleep -Seconds 10 Invoke-CMClientNotification -DeviceCollectionName $AllWksCollection -NotificationType RequestMachinePolicyNow -Verbose ######################################### # Run the Deployment Summarization ######################################### Invoke-CMDeploymentSummarization -CollectionName $AllWksCollection -Verbose
Once you have deployed the latest version of flash everywhere you should end up with a baseline to work off, some clients won’t want to update from let’s say version 11 to 23 My buddy MVP Nickolaj Andersen has a good post about this – https://msendpointmgr.com/2013/05/23/upgrade-adobe-flash-player-11-7-x-fails-with-error-1603-in-configmgr-2012/
Creating a Configuration Item
Create a Configuration Item to ensure Adobe flash player updates itself:
Discovery Script
This script looks for the existence of the “mms.cfg” file, in this file you can enable or disable update and even more importantly make them silent. More details here https://www.adobe.com/devnet/flashplayer/articles/flash_player_admin_guide.html
Script;
if (Test-Path $env:WINDIR\SysWOW64) { if (Test-Path "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg") { $AutoUpdateDisable = Select-String -Path "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg" -Pattern AutoUpdateDisable=0 If ($AutoUpdateDisable -match "AutoUpdateDisable=0") {Write-Host $True} Else {Write-Host $False} $SilentAutoUpdateEnable = Select-String -Path "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg" -Pattern SilentAutoUpdateEnable=1 If ($SilentAutoUpdateEnable -match "SilentAutoUpdateEnable=1") {Write-Host $True} Else {Write-Host $False} } else { "File doesn't exist" Write-Host $False } } if (Test-Path $env:WINDIR\System32) { if (Test-Path "$env:WINDIR\System32\Macromed\Flash\mms.cfg") { $AutoUpdateDisable = Select-String -Path "$env:WINDIR\System32\Macromed\Flash\mms.cfg" -Pattern AutoUpdateDisable=0 If ($AutoUpdateDisable -match "AutoUpdateDisable=0") {Write-Host $True} Else {Write-Host $False} $SilentAutoUpdateEnable = Select-String -Path "$env:WINDIR\System32\Macromed\Flash\mms.cfg" -Pattern SilentAutoUpdateEnable=1 If ($SilentAutoUpdateEnable -match "SilentAutoUpdateEnable=1") {Write-Host $True} Else {Write-Host $False} } else { "File doesn't exist" Write-Host $False } }
If the script runs and doesn’t find the files it will return false(this is important later)
Remediation Script
This script creates the files and writes the entries;
Script;
if (Test-Path $env:WINDIR\SysWOW64) { Write-Host "Creating mms.cfg file" New-Item "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg" -type file -Force Add-Content "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg" "AutoUpdateDisable=0" Add-Content "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg" "SilentAutoUpdateEnable=1" (Get-Content -path "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg") | Set-Content -Encoding UTF8 -Path "$env:WINDIR\SysWOW64\Macromed\Flash\mms.cfg" } if (Test-Path $env:WINDIR\System32) { Write-Host "Creating mms.cfg file" New-Item "$env:WINDIR\System32\Macromed\Flash\mms.cfg" -type file -Force Add-Content "$env:WINDIR\System32\Macromed\Flash\mms.cfg" "AutoUpdateDisable=0" Add-Content "$env:WINDIR\System32\Macromed\Flash\mms.cfg" "SilentAutoUpdateEnable=1" (Get-Content -path "$env:WINDIR\System32\Macromed\Flash\mms.cfg") | Set-Content -Encoding UTF8 -Path "$env:WINDIR\System32\Macromed\Flash\mms.cfg" }
Compliance Rules
This means if the discovery is false it will run the script to create the files.
Creating a Configuration Baseline
Now create a configuration baseline
Deploy Configuration Baseline
Now deploy the baseline
Baseline deployment in action
If you delete the mms.cfg file or if you change any settings, discovery will report that something is wrong and the remediation script will repair it.
Click evaluate in the configuration manager client:
Within seconds the file is back:
Scheduling the automatic updates
When you install flash and allow it to update itself it creates a task schedule which runs once an hour every day which is nuts.
So either using a GPO or use PowerShell, for ease i used a GPO to change the schedule task.
Before
This is set to run way too often, adobe reader suffers from the same issue.
After
Group Policy
I run the updater twice a day three days a week, the reason we need to run it twice is the updating service can only update one component at a time. Use item level targeting as the updating files are located in different areas depending on your OS.
Pat Yourself On The Back!
When you take the steps above you can ensure that flash player is up to date on all workstations until the day Adobe retire the product.
Any questions you can catch me on twitter – @terencebeggs
Hello, i am trying voodoo PowerShell, but still write message: WARNING: Adobe Flash Player 29 ActiveX already exists. Skipping..
But in SCCM i dont have This Aplication , can you help me?
Umm, that’s very odd because the script reads the properties of the MSI it will look for another application with the same name in SCCM. Do you have any other flash applications?
SCCM is new, Clear, i have own 8 Testing aplications
I can try the script on my development server but it will be friday before i get a chance. thanks
Manny Thanks fro your time.
I have a few questions. This is how you installed one default version of Adobe Flash (currently 29). By setting up Compliance, you’re providing the environment for that version. If the Update ItSelf is on the client, where does the update update download and the context in which it is installed, Local System? How do you limit the installation to Windows7?
Best regards Marek
Yes the GPO scheduled task is run as system, the update is downloaded from adobe into a temp folder and then installs. I have set up operational collections using the https://www.systemcenterdudes.com/ script and limit the install to Windows 7 only. As windows 10 has it built in for Edge/IE and Google Chrome uses its own built in version.
I’ve already set everything up in SCCM except Adobe Flash through PowerShell, but I can do this manually.
Since we already run client installations on GPO and mms.cfg (we prohibit users from having USER permissions), I have tried your settings and the basic issue with your variants is that Adobe Flash on your computer runs in the context of a user who in our the organization does not have access to a proxy, do I think it right?
As i said the GPO is running as system so it gets around that, but it does need access to the outside world to get the update. I belive the download from adobe comes on port 443 (i think).
I understand, so I have to go another way, in any case, I learned at least something about using BaseLine. Thank you for your time. Marek
No problem Marek.
Hello, i dont speak english very well. Can you pls help me, in SCCM i am beginner and i cant realize your manual without missing pictures (google says too many redirect), can you help me. I can realize this workaround. Manny thanks.
When i checked the page non of the pictures were missing, are you using it on an Ipad or Iphone?
Hello, i am behind Proxy and Firewall, when leave this, Pictures are O.K.
I’ve found that when updating the mms.cfg file, it does not create a scheduled task if there wasn’t already one there. What is the exe that the scheduled task relates to please?
Hello Paul
The exe is here C:\Windows\System32\Macromed\Flash\FlashPlayerUpdateService.exe, as long as your using “replace” when creating the GPO it should create the scheduled task for you, but flash is not installed it wont create the task.
Hope that is helpful
Great, thank you.
Great article! Found an error though. Looks like $AdobeFlashDir = “\Adobe Systems\Flash Player\” or the assuming folder structure in the software repository path “Adobe\Flash Player” don’t match.
Does the compliance rule replace an existing mms.cfg?
Ah ok will have a look when i get a chance.
The compliance rule will read whats in the file and change it, so if the file doesn’t exist or is incorrectly set up it will fix it. Hope that helps