Wenn man im Enterpriseumfeld nach einem Windows 10 Update wieder all die schönen Nicht-Enterprise Apps hat will man die gerne löschen (Remove-AppxPackage bzw. Remove-AppxProvisionedPackage) – kann man auch, nur bleiben dann bei allen Benutzern die auf der Kiste schon mal angemeldet waren Leichen im Startmenü. Warum? Das weiß offenbar nicht mal Microsoft wenn man die hilflosen Antworten in diversen Foren liest.

Wers wirklich Hardcore will kann in die Standard ESENT DB die die Grundlage für das neue (tolle) Startmenü bildet reinfummeln und die nicht gewollten Apps rauslöschen (Api ist in Microsoft.Isam.Esent.Interop Namespace von ESENT Managed Interface):

JET_INSTANCE oInstance;
JET_SESID oSession;
JET_DBID oDB;
JET_TABLEID oTable;
JET_COLUMNDEF oColDefAppRef, oColDefID;
string sTable = "Tile";
string sAppsToDelete = "WindowsFeedbackHub|Messaging|WindowsReadingList|CommsPhone|Microsoft.SkypeApp|OneNote|ConnectivityStore|Microsoft.MicrosoftOfficeHub|Microsoft.Office.Sway|Microsoft.MicrosoftSolitaireCollection|Microsoft.XboxApp|Microsoft.Getstarted|Microsoft.BingSports|Microsoft.BingNews|Microsoft.BingFinance|Microsoft.3DBuilder|Microsoft.OneConnect|Microsoft.3DBuilder|microsoft.windowscommunicationsapps|Microsoft.BingFoodAndDrink|Microsoft.BingHealthAndFitness|Microsoft.BingTravel|Windows.ContactSupport"
string sIDstoDelete = "PreInstalled.DefaultStartLayout";
string sAppRef;
string sID;
string sDB=@"C:\Users\whatever\AppData\Local\TileDataLayer\Database\vedatamodel.edb";

Console.WriteLine($"Doing {sDB}");

Api.JetCreateInstance(out oInstance, "instance");
Api.JetSetSystemParameter(oInstance, JET_SESID.Nil, JET_param.CircularLog, 1, null);
Api.JetInit(ref oInstance);
Api.JetBeginSession(oInstance, out oSession, null, null);


Api.JetAttachDatabase(oSession, sDB, AttachDatabaseGrbit.None);
Api.JetOpenDatabase(oSession, sDB, null, out oDB, OpenDatabaseGrbit.None);

Api.JetOpenTable(oSession, oDB, sTable, null, 0, OpenTableGrbit.None, out oTable);
Api.JetGetColumnInfo(oSession, oDB, sTable, "APPREF", out oColDefAppRef);
Api.JetGetColumnInfo(oSession, oDB, sTable, "ID", out oColDefID);

if (!Api.TryMoveFirst(oSession, oTable))
{
   Console.WriteLine("   ===> Tile table is empty");
}
else
{
   do
   {
      sAppRef = Api.RetrieveColumnAsString(oSession, oTable, oColDefAppRef.columnid);
      sID = Api.RetrieveColumnAsString(oSession, oTable, oColDefID.columnid);
      if (Regex.Match(sAppRef, sAppsToDelete, RegexOptions.IgnoreCase).Success || Regex.Match(sID, sIDstoDelete, RegexOptions.IgnoreCase).Success)
      {
         Console.WriteLine($"    ===> DELETING {sID}/{sAppRef}");
         Api.JetDelete(oSession, oTable);
      }
   }
   while (Api.TryMoveNext(oSession, oTable));
}

Api.JetCloseTable(oSession, oTable);
Api.JetCloseDatabase(oSession, oDB, CloseDatabaseGrbit.None);
Api.JetDetachDatabase(oSession, sDB);
Api.JetEndSession(oSession, EndSessionGrbit.None);
Api.JetTerm(oInstance);

Btw: Mit ESEDatabaseViewer kann man sich die Datenbank auch ansehen, steht zwar nicht allzuviel Sinnvolles/Lesbares drin aber he, manchmal will man es genau wissen 😀