Yet another fix for "App with the same version and product ID" on-premises

"The provided App differs from another App with the same version and product ID"

Ever since the beginning of 2013, we have this this problem when you deploy and redeploy App (now SharePoint Add-in) to either SharePoint 2013 on-premises or Office 365's SharePoint Online.

If you Bingle about - you will find various fixes, in order of severity:

1 - you can try to retry Installing the App, or removing it from Site Content http://www.mavention.nl/blog/provided-App-differs-another-App-same-version-product-ID

2 - try removing it from Site and Site Collection recycle bins.  Also remember the second level recycle bin.  This one is usually good enough for Office 365.

3 - Jeremy Thake says don't use the same farm account http://www.jeremythake.com/2013/10/sharepoint-2013-apps-the-provided-app-differs-from-another-app-with-the-same-version-and-product-id/

4 - You can also just increment the version number.  This is difficult when you work in a team and you don't want to bump _everyone_'s number

5 - Delete the offending Site Collection and create a new one

I found a new, TOTALLY UNSUPPORTED WAY.

Sometimes, you really just want to delete the old one.  But the Object Model doesn't have objects that go that deep.  Hence there are no way to do this via command-line either.

You need AppInstance to perform an uninstall.  If you can't get an AppInstance, but the AppPackage is still in your Site Collection, you are pretty much stuck.

Let's go check out the content database.  Disclaimer: Do this if you are curious.  Also, don't do this on your production.

SELECT [PackageFingerprint]
      ,[ProductId]
      ,[Package]
      ,[Title]
      ,[IsDownloadInvalidated]
      ,[SiteId]
  FROM [WSS_CONTENT_DB].[dbo].[AppPackages]

You want to know which Site Collection it is.  So figure out which AppPackage is the one SharePoint can't delete - by cross-checking the SiteId

PackageFingerprint is an important field that we'll need in a minute.  It acts like a unique identifier.
IsDownloadInvalidated is probably 0 (meaning it is valid).  You just can't delete it.

SharePoint has a few nice store procedures.

exec [WSS_CONTENT_DB].[dbo].proc_App_InvalidatePackage
    @PackageFingerprint, @SiteId

-- example
exec [WSS_CONTENT_DB].[dbo].proc_App_InvalidatePackage
    0x9DB9C067E1B970AD1258E28AE26EC3AE17CF772BC093D0CCF8E1832FF3B171261A09812778830621AA63FD4C9D1EA922DC5432E1CACDEA00B1CDA82F9A28CAE2, 
    '282292D5-3686-460D-9AB4-9354272FB2A1'

This stored procedure will flag the AppPackage as Invalid.  If you do SELECT * FROM AppPackages again, you'll see it is now IsDownloadInvalidated = 1

So SharePoint now thinks there was something wrong with the download of this package :-)Let's invoke SharePoint's auto-immune system and nuke the AppPackage

exec [WSS_CONTENT_DB].[dbo].proc_App_DeleteInvalidatedDownloadApp
    @PackageFingerprint, @SiteId

-- same arguments.  

This one will nuke the AppPackage clean.

You can now go back to PowerShell and redeploy your App.

PS> $App = Import-SPAppPackage -Path <Path> -Site <Url> -Source <Source>
PS> Install-SPApp -Web <Url> -Identity $App 

This works really well.  But you REALLY shouldn't touch the Content DB