This is a small code snippet on how to add a content type to a site and how to install an app(or these days an Add-In). Notice that adding an app this way is not the recommended way. This is “cheating”, well the recommended way to add an app to a production environment is through a app catalog or a store BUT if you do need to add it for some reason through CSOM well this is the way. You could also apply the same technique to PowerShell:
private static void EnsureDeveloperFeature(ClientContext ctx) { var result = ctx.LoadQuery(ctx.Site.Features.Where(f => f.DefinitionId == DeveloperFeatureId)); ctx.ExecuteQuery(); if (result.Any()) return; var feature = ctx.Site.Features.Add(DeveloperFeatureId, true, FeatureDefinitionScope.None); ctx.ExecuteQuery(); } private static void DeleteDeveloperFeature(ClientContext ctx) { var result = ctx.LoadQuery(ctx.Site.Features.Where(f => f.DefinitionId == DeveloperFeatureId)); ctx.ExecuteQuery(); if (!result.Any()) return; ctx.Site.Features.Remove(DeveloperFeatureId, true); ctx.ExecuteQuery(); } private static void EnsureContentTypeAndRibbonApp(ClientContext ctxWorkspace, string administratorsEmail) { try { var contentTypeName = ConfigurationManager.AppSettings["ContentTypeName"].ToString(); var appFullPath = ConfigurationManager.AppSettings["RibbonAppFullPath"].ToString(); if (String.IsNullOrEmpty(contentTypeName) && String.IsNullOrEmpty(appFullPath)) return; Web currentWeb = ctxWorkspace.Web; ctxWorkspace.Load(currentWeb); var webContentTypes = currentWeb.ContentTypes; ctxWorkspace.Load(webContentTypes); var apps = currentWeb.GetAppInstances(); ctxWorkspace.Load(apps); ctxWorkspace.ExecuteQuery(); // Install the ribbon achieving ribbon app if the app file exists and does not exist already if (System.IO.File.Exists(appFullPath) && apps.SingleOrDefault(o => o.Title.Contains(ConfigurationManager.AppSettings["ArchivingRibbonAppName"].ToString())) == null) { EnsureDeveloperFeature(ctxWorkspace); using (var packageStream = System.IO.File.OpenRead(appFullPath)) { var appInstance = ctxWorkspace.Web.LoadAndInstallApp(packageStream); ctxWorkspace.Load(appInstance); ctxWorkspace.ExecuteQuery(); if (appInstance != null && appInstance.Status == AppInstanceStatus.Initialized) { Console.WriteLine("App was installed on:" + currentWeb.Url); } } DeleteDeveloperFeature(ctxWorkspace); } var contentType = webContentTypes.SingleOrDefault(o => o.Name.Contains(contentTypeName)); if(contentType != null) { ctxWorkspace.Load(contentType); ctxWorkspace.ExecuteQuery(); ListCollection lists = ctxWorkspace.Web.Lists; var sourceWeb = ctxWorkspace.Web; ctxWorkspace.Load(sourceWeb); ctxWorkspace.Load(lists); ctxWorkspace.ExecuteQuery(); foreach (List list in lists.Where(o => o.BaseType == BaseType.DocumentLibrary)) { if (list.Hidden || list.IsApplicationList || list.IsCatalog) continue; // Check for existing content types only if content type management is set to active if (list.ContentTypesEnabled) { var listCTs = list.ContentTypes; ctxWorkspace.Load(listCTs); ctxWorkspace.ExecuteQuery(); if (listCTs.SingleOrDefault(o => o.Name == contentType.Name) != null) continue; } list.ContentTypesEnabled = true; list.Update(); ctxWorkspace.ExecuteQuery(); list.ContentTypes.AddExistingContentType(contentType); list.Update(); ctxWorkspace.ExecuteQuery(); } } } catch (Exception ex) { } }