private static void RecurseActions(ActionCollection collection, LogHelper logHelper, DateTime CurrentTime, BaseAction parentAction = null) { foreach (BaseAction action in collection) { logHelper.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Started '{0}'", action.GetType().FullName)); action.Run(parentAction, CurrentTime, logHelper); if (action.Actions != null && action.Actions.Count > 0) { RecurseActions(action.Actions, logHelper, CurrentTime, action); } logHelper.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Completed '{0}'", action.GetType().FullName)); } }
/// <summary> /// Executes the business logic /// </summary> /// <param name="logger">The logger.</param> public override void Run(BaseAction parentAction, DateTime CurrentTime, LogHelper logger) { CsvProcessor csvProcessor = new CsvProcessor(); logger.LogVerbose(string.Format("Attempting to read mapping CSV file '{0}'", this.UserMappingCSVFile)); using (StreamReader reader = new StreamReader(this.UserMappingCSVFile)) { csvProcessor.Execute(reader, (entries, y) => { IterateCollection(entries, logger); }, logger); } }
/// <summary> /// Defines the entry point of the application. /// </summary> /// <param name="args">The arguments.</param> private static void Main(string[] args) { LogHelper logHelper = null; Stopwatch sw = Stopwatch.StartNew(); sw.Start(); // Time stamp current time for delta value DateTime CurrentTime = DateTime.Now; try { if (args.Length == 0) { throw new Exception("Please specify the input file..."); } PropertyMapper mapper = null; using (TextReader reader = new StreamReader(args[0])) { mapper = Deserialize <PropertyMapper>(reader); } if (mapper == null) { throw new Exception("An error occurred whilst serializing the data. Ensure that the XML adheres to the schema"); } logHelper = LogHelper.Instance(mapper.Loggers); RecurseActions(mapper.Actions, logHelper, CurrentTime); } catch (Exception ex) { if (logHelper != null) { logHelper.LogException(string.Empty, ex); } } finally { sw.Stop(); if (logHelper != null) { logHelper.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Operation completed. Execution time (s) {0}", sw.Elapsed.TotalSeconds)); logHelper.Dispose(); } } }
/// <summary> /// Iterates the row from the CSV file /// </summary> /// <param name="context">The ClientContext instance.</param> /// <param name="entries">The collection values per row.</param> /// <param name="logger">The logger.</param> public override void IterateCollection(ClientContext context, Collection <string> entries, LogHelper logger) { List <PropertyData> data = new List <PropertyData>(); foreach (PropertyBase item in this.Properties) { if (item.Index < entries.Count) { try { string account = entries[this.UserNameIndex]; PropertyData property = new PropertyData(); property.Name = item.Name; property = item.Process(property, entries[item.Index], this) as PropertyData; data.Add(property); } catch (Exception ex) { logger.LogException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Error occured whilst processing account '{0}', Property '{1}'. Stack {2}", entries[this.UserNameIndex], item.Name, ex.ToString()), ex); } } } logger.LogVerbose(string.Format("Attempting to update profile for account '{0}'", entries[this.UserNameIndex])); try { this.profileService.ModifyUserPropertyByAccountName(entries[this.UserNameIndex], data.ToArray()); logger.LogOutcome(entries[this.UserNameIndex], "SUCCESS"); } catch (Exception ex) { logger.LogException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Error occured whilst processing account '{0}' - the account does not exist", entries[this.UserNameIndex]), ex); logger.LogOutcome(entries[this.UserNameIndex], "FAILURE"); } }
/// <summary> /// Iterates the row from the CSV file /// </summary> /// <param name="context">The ClientContext instance.</param> /// <param name="entries">The collection values per row.</param> /// <param name="logger">The logger.</param> public override void IterateCollection(ClientContext context, Collection<string> entries, LogHelper logger) { List<PropertyData> data = new List<PropertyData>(); foreach (PropertyBase item in this.Properties) { if (item.Index < entries.Count) { try { string account = entries[this.UserNameIndex]; PropertyData property = new PropertyData(); property.Name = item.Name; property = item.Process(property, entries[item.Index], this) as PropertyData; data.Add(property); } catch (Exception ex) { logger.LogException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Error occured whilst processing account '{0}', Property '{1}'. Stack {2}", entries[this.UserNameIndex], item.Name, ex.ToString()), ex); } } } logger.LogVerbose(string.Format("Attempting to update profile for account '{0}'", entries[this.UserNameIndex])); try { this.profileService.ModifyUserPropertyByAccountName(entries[this.UserNameIndex], data.ToArray()); logger.LogOutcome(entries[this.UserNameIndex], "SUCCESS"); } catch(Exception ex) { logger.LogException(string.Format(System.Globalization.CultureInfo.InvariantCulture, "Error occured whilst processing account '{0}' - the account does not exist", entries[this.UserNameIndex]), ex); logger.LogOutcome(entries[this.UserNameIndex], "FAILURE"); } }
/// <summary> /// Executes the business logic /// </summary> /// <param name="logger">The logger.</param> public override void Run(BaseAction parentAction, DateTime CurrentTime, LogHelper logger) { if (parentAction != null) { this.Properties = parentAction.Properties; } CsvProcessor csvProcessor = new CsvProcessor(); string[] csvFiles = Directory.GetFiles(this.CSVDirectoryLocation, "*.csv", SearchOption.TopDirectoryOnly); logger.LogVerbose(string.Format("Attempting to get files from directory 'location' {0}. Number of files found {1}", this.CSVDirectoryLocation, csvFiles.Length)); foreach (string csvFile in csvFiles) { logger.LogVerbose(string.Format("Attempting to read CSV file '{0}' from location {1}", csvFile, this.CSVDirectoryLocation)); logger.LogVerbose(string.Format("Pausing the utility for '{0}' seconds so ASMX service is not overloaded", this.SleepPeriod)); Thread.Sleep(this.SleepPeriod * 1000); using (StreamReader reader = new StreamReader(csvFile)) { logger.LogVerbose(string.Format("Establishing connection with tenant at '{0}'", this.TenantSiteUrl)); using (ClientContext context = new ClientContext(this.TenantSiteUrl)) { Uri site = new Uri(this.TenantSiteUrl); try { UserProfileService.UserProfileService profileService = new UserProfileService.UserProfileService(site.ToString() + ProfileService); this.profileService = profileService; profileService.UseDefaultCredentials = false; using (SecureString password = new SecureString()) { foreach (char c in this.TenantAdminPassword.ToCharArray()) { password.AppendChar(c); } logger.LogVerbose(string.Format("Attempting to authenticate against tenant with user name '{1}'", this.TenantSiteUrl, this.TenantAdminUserName)); var crudentials = new SharePointOnlineCredentials(this.TenantAdminUserName, password); string cookie = crudentials.GetAuthenticationCookie(site); profileService.CookieContainer = new CookieContainer(); profileService.CookieContainer.Add(new Cookie(FedAuthCookieName, cookie.TrimStart(SPOIDCookieValue.ToCharArray()), string.Empty, site.Authority)); csvProcessor.Execute(reader, (entries, y) => { IterateCollection(context, entries, logger); }, logger); } } finally { if (this.profileService != null) { this.profileService.Dispose(); } } } } // Clean up current CSV file System.IO.File.Delete(csvFile); } }
/// <summary> /// Iterates the row from the CSV file /// </summary> /// <param name="entries">The collection values per row.</param> /// <param name="logger">The logger.</param> public override void IterateCollection(Collection<string> entries, LogHelper logger) { Stopwatch IterationSW = new Stopwatch(); IterationSW.Start(); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Establishing context object to: '{0}'", entries[this.SiteIndex])); try { // Use context of current iteration URL for current user item using (ClientContext context = new ClientContext(entries[this.SiteIndex])) { using (SecureString password = new SecureString()) { foreach (char c in this.Password.ToCharArray()) { password.AppendChar(c); } context.Credentials = new SharePointOnlineCredentials(this.UserName, password); // Get file to upload from directory FileInfo theFileToUpload = new FileInfo(Path.Combine(this.DirectoryLocation + "\\", entries[this.FileIndex] + ".xlsx")); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Attempting to {0} file {1}", this.DocumentAction, theFileToUpload)); // Ensure account has permissions to access BasePermissions perm = new BasePermissions(); perm.Set(PermissionKind.AddListItems); ConditionalScope scope = new ConditionalScope(context, () => context.Web.DoesUserHavePermissions(perm).Value); using(scope.StartScope()) { Stopwatch tempSW = new Stopwatch(); tempSW.Start(); int success = 0; while(tempSW.Elapsed.TotalSeconds < 20) { var digest = context.GetFormDigestDirect(); string cookie = ((SharePointOnlineCredentials)context.Credentials).GetAuthenticationCookie(new Uri(entries[this.SiteIndex])).TrimStart("SPOIDCRL=".ToCharArray()); using (Stream s = theFileToUpload.OpenRead()) { // Define REST string request to upload document to context string theTargetUri = string.Format(CultureInfo.CurrentCulture, "{0}/_api/web/lists/getByTitle('Documents')/RootFolder/Files/add(url='{1}',overwrite='true')?", entries[this.SiteIndex], this.FileUploadName); // Define REST HTTP request obkect HttpWebRequest SPORequest = (HttpWebRequest)HttpWebRequest.Create(theTargetUri); // Define HTTP request action method if (this.DocumentAction == "Upload") { SPORequest.Method = "POST"; } else if (this.DocumentAction == "Delete") { SPORequest.Method = "DELETE"; } else { logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "There was a problem with the HTTP request in DocumentAction attribute of XML file")); throw new Exception("The HTTP Request operation is not supported, please check the value of DocumentAction in the XML file"); } // Build out additional HTTP request details SPORequest.Accept = "application/json;odata=verbose"; SPORequest.Headers.Add("X-RequestDigest", digest.DigestValue); SPORequest.ContentLength = s.Length; SPORequest.ContentType = "application/octet-stream"; // Handle authentication to context through cookie SPORequest.CookieContainer = new CookieContainer(); SPORequest.CookieContainer.Add(new Cookie("SPOIDCRL", cookie, string.Empty, new Uri(entries[this.SiteIndex]).Authority)); // Perform file upload/deletion using (Stream requestStream = SPORequest.GetRequestStream()) { s.CopyTo(requestStream); } // Get HTTP response to determine success of operation HttpWebResponse SPOResponse = (HttpWebResponse)SPORequest.GetResponse(); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Successfully '{0}' file {1}", this.DocumentAction, theFileToUpload)); logger.LogOutcome(entries[this.SiteIndex], "SUCCCESS"); success = 1; // Dispose of the HTTP response SPOResponse.Close(); break; } } tempSW.Stop(); if (success != 1) { throw new Exception("The HTTP Request operation exceeded the timeout of 20 seconds"); } } } } } catch(Exception ex) { logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "There was an issue performing '{0}' on to the URL '{1}' with exception: {2}", this.DocumentAction, entries[this.SiteIndex], ex.Message)); logger.LogOutcome(entries[this.SiteIndex], "FAILURE"); } finally { IterationSW.Stop(); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Completed processing URL:'{0}' in {1} seconds", entries[this.SiteIndex], IterationSW.ElapsedMilliseconds/1000)); } }
/// <summary> /// Iterates the row from the CSV file /// </summary> /// <param name="entries">The collection values per row.</param> /// <param name="logger">The logger.</param> public override void IterateCollection(Collection <string> entries, LogHelper logger) { Stopwatch IterationSW = new Stopwatch(); IterationSW.Start(); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Establishing context object to: '{0}'", entries[this.SiteIndex])); try { // Use context of current iteration URL for current user item using (ClientContext context = new ClientContext(entries[this.SiteIndex])) { using (SecureString password = new SecureString()) { foreach (char c in this.Password.ToCharArray()) { password.AppendChar(c); } context.Credentials = new SharePointOnlineCredentials(this.UserName, password); // Get file to upload from directory FileInfo theFileToUpload = new FileInfo(Path.Combine(this.DirectoryLocation + "\\", entries[this.FileIndex] + ".xlsx")); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Attempting to {0} file {1}", this.DocumentAction, theFileToUpload)); // Ensure account has permissions to access BasePermissions perm = new BasePermissions(); perm.Set(PermissionKind.AddListItems); ConditionalScope scope = new ConditionalScope(context, () => context.Web.DoesUserHavePermissions(perm).Value); using (scope.StartScope()) { Stopwatch tempSW = new Stopwatch(); tempSW.Start(); int success = 0; while (tempSW.Elapsed.TotalSeconds < 20) { var digest = context.GetFormDigestDirect(); string cookie = ((SharePointOnlineCredentials)context.Credentials).GetAuthenticationCookie(new Uri(entries[this.SiteIndex])).TrimStart("SPOIDCRL=".ToCharArray()); using (Stream s = theFileToUpload.OpenRead()) { // Define REST string request to upload document to context string theTargetUri = string.Format(CultureInfo.CurrentCulture, "{0}/_api/web/lists/getByTitle('Documents')/RootFolder/Files/add(url='{1}',overwrite='true')?", entries[this.SiteIndex], this.FileUploadName); // Define REST HTTP request obkect HttpWebRequest SPORequest = (HttpWebRequest)HttpWebRequest.Create(theTargetUri); // Define HTTP request action method if (this.DocumentAction == "Upload") { SPORequest.Method = "POST"; } else if (this.DocumentAction == "Delete") { SPORequest.Method = "DELETE"; } else { logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "There was a problem with the HTTP request in DocumentAction attribute of XML file")); throw new Exception("The HTTP Request operation is not supported, please check the value of DocumentAction in the XML file"); } // Build out additional HTTP request details SPORequest.Accept = "application/json;odata=verbose"; SPORequest.Headers.Add("X-RequestDigest", digest.DigestValue); SPORequest.ContentLength = s.Length; SPORequest.ContentType = "application/octet-stream"; // Handle authentication to context through cookie SPORequest.CookieContainer = new CookieContainer(); SPORequest.CookieContainer.Add(new Cookie("SPOIDCRL", cookie, string.Empty, new Uri(entries[this.SiteIndex]).Authority)); // Perform file upload/deletion using (Stream requestStream = SPORequest.GetRequestStream()) { s.CopyTo(requestStream); } // Get HTTP response to determine success of operation HttpWebResponse SPOResponse = (HttpWebResponse)SPORequest.GetResponse(); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Successfully '{0}' file {1}", this.DocumentAction, theFileToUpload)); logger.LogOutcome(entries[this.SiteIndex], "SUCCCESS"); success = 1; // Dispose of the HTTP response SPOResponse.Close(); break; } } tempSW.Stop(); if (success != 1) { throw new Exception("The HTTP Request operation exceeded the timeout of 20 seconds"); } } } } } catch (Exception ex) { logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "There was an issue performing '{0}' on to the URL '{1}' with exception: {2}", this.DocumentAction, entries[this.SiteIndex], ex.Message)); logger.LogOutcome(entries[this.SiteIndex], "FAILURE"); } finally { IterationSW.Stop(); logger.LogVerbose(string.Format(CultureInfo.CurrentCulture, "Completed processing URL:'{0}' in {1} seconds", entries[this.SiteIndex], IterationSW.ElapsedMilliseconds / 1000)); } }