-
-
Save adeelnasir/6875c89b159245d57ae8619777d83150 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
using System; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using Microsoft.WindowsAzure.Storage; | |
using Microsoft.WindowsAzure.Storage.Blob; | |
using Microsoft.Azure; | |
using Microsoft.WindowsAzure.Storage.Auth; | |
using B2CGraph.Library.CodeBits; | |
using System.Text.RegularExpressions; | |
using B2CGraph.Library; | |
using System.Threading.Tasks; | |
using System.Collections.Generic; | |
namespace B2CGraphShell | |
{ | |
public class Program | |
{ | |
private static string tenant = CloudConfigurationManager.GetSetting("b2c:Tenant"); | |
private static string clientId = CloudConfigurationManager.GetSetting("b2c:ClientId"); | |
private static string clientSecret = CloudConfigurationManager.GetSetting("b2c:ClientSecret"); | |
private static string iefGraphAppId = CloudConfigurationManager.GetSetting("b2c:IEFGraphAppId"); | |
private static string customAttribute1 = CloudConfigurationManager.GetSetting("b2c:common:CustomAttribute1"); | |
private static string customAttribute2 = CloudConfigurationManager.GetSetting("b2c:common:CustomAttribute2"); | |
private static string customAttribute3 = CloudConfigurationManager.GetSetting("b2c:common:CustomAttribute3"); | |
private static string customAttribute3Value = CloudConfigurationManager.GetSetting("b2c:common:CustomAttribute3Value"); | |
private static string storageAccountName = CloudConfigurationManager.GetSetting("azure:StorageAccountName"); | |
private static string storageAccessKey = CloudConfigurationManager.GetSetting("azure:StorageAccessKey"); | |
private static string inputFileName = CloudConfigurationManager.GetSetting("azure:InputFileName"); | |
private static string logFileName = CloudConfigurationManager.GetSetting("azure:LogFileName"); | |
private static string outputFileName = CloudConfigurationManager.GetSetting("azure:OutputFileName"); | |
private static string passwordFileName = CloudConfigurationManager.GetSetting("azure:PasswordFileName"); | |
private static string exportPasswords = CloudConfigurationManager.GetSetting("azure:ExportPasswords"); | |
private static string containerName = CloudConfigurationManager.GetSetting("azure:common:ContainerName"); | |
private static B2CGraphClient client = null; | |
private static ConsoleColor init = ConsoleColor.White; | |
static void Main(string[] args) | |
{ | |
init = Console.ForegroundColor; | |
if (args.Length <= 0) | |
{ | |
Console.ForegroundColor = ConsoleColor.Red; | |
Console.WriteLine("Please enter a command as the first argument."); | |
Console.ForegroundColor = init; | |
return; | |
} | |
else | |
{ | |
try | |
{ | |
client = new B2CGraphClient(clientId, clientSecret, tenant); | |
if (client != null) | |
{ | |
try | |
{ | |
switch (args[0].ToUpper()) | |
{ | |
case "IMPORT-USERS": | |
ImportUsers(); | |
break; | |
default: | |
Console.ForegroundColor = ConsoleColor.Red; | |
Console.WriteLine("Invalid command."); | |
break; | |
} | |
} | |
catch (Exception ex) | |
{ | |
Console.ForegroundColor = ConsoleColor.Red; | |
var innerException = ex.InnerException; | |
if (innerException != null) | |
{ | |
while (innerException != null) | |
{ | |
Console.WriteLine(innerException.Message); | |
innerException = innerException.InnerException; | |
} | |
} | |
else | |
{ | |
Console.WriteLine(ex.Message); | |
} | |
} | |
finally | |
{ | |
Console.ForegroundColor = init; | |
} | |
} | |
} | |
catch (Exception ex) | |
{ | |
Console.ForegroundColor = ConsoleColor.Red; | |
var innerException = ex.InnerException; | |
if (innerException != null) | |
{ | |
while (innerException != null) | |
{ | |
Console.WriteLine(innerException.Message); | |
innerException = innerException.InnerException; | |
} | |
} | |
else | |
{ | |
Console.WriteLine(ex.Message); | |
} | |
} | |
} | |
} | |
private static dynamic GetExistingUsers(string filter) | |
{ | |
string result; | |
result = client.GetAllUsers(filter).Result; | |
dynamic dynJson = JsonConvert.DeserializeObject(result); | |
return dynJson; | |
} | |
private static async Task<dynamic> GetExistingUsers(string filter, List<string> objectIds) | |
{ | |
string result; | |
result = await client.GetAllUsers(filter); | |
dynamic dynJson = JsonConvert.DeserializeObject(result); | |
JObject originalObject = JObject.Parse(result); | |
objectIds.AddRange(originalObject.Descendants() | |
.OfType<JProperty>() | |
.Where(p => p.Name == "objectId") | |
.Select(x => x.Value.ToString()) | |
.ToList()); | |
return dynJson; | |
} | |
private static void ImportUsers() | |
{ | |
Console.WriteLine("Starting to import users"); | |
StringBuilder logString = new StringBuilder(); | |
StringBuilder outputString = new StringBuilder(); | |
StringBuilder passwordString = new StringBuilder(); | |
// Create storage account creds object. | |
StorageCredentials storageCredentials = new StorageCredentials(storageAccountName, storageAccessKey); | |
// Create storage account object. | |
CloudStorageAccount storageAccount = new CloudStorageAccount(storageCredentials, true); | |
// Create the blob client. | |
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); | |
// Retrieve reference to the bulkload container. | |
CloudBlobContainer container = blobClient.GetContainerReference(containerName); | |
// Retrieve reference to the input blob | |
CloudBlockBlob inputBlockBlob = container.GetBlockBlobReference(inputFileName); | |
string[] users; | |
var timeStamp = DateTime.Now.ToString("ddMMyyyyhhmmss"); | |
using (var memoryStream = new MemoryStream()) | |
{ | |
Console.WriteLine("Downloading the users to memory"); | |
inputBlockBlob.DownloadToStream(memoryStream); | |
users = Encoding.UTF8.GetString(memoryStream.ToArray()).Split(new[] { "\r\n", "\r", "\n" }, | |
StringSplitOptions.None | |
); | |
Console.WriteLine("Downloaded the users to memory"); | |
} | |
Console.WriteLine(@"Read input file with " + users.Length + " users"); | |
Parallel.ForEach(users, | |
new ParallelOptions { MaxDegreeOfParallelism = 10 }, | |
(user) => | |
{ | |
if (user.Length > 0) | |
{ | |
string userId = ""; | |
try | |
{ | |
var userAttributes = user.Split(','); | |
userId = userAttributes.Length > 0 ? userAttributes[0].Trim() : ""; | |
string email = userAttributes.Length > 1 ? userAttributes[1].Trim() : ""; | |
string phone = userAttributes.Length > 2 ? userAttributes[2].Trim().Replace(" ", "") : ""; | |
var contactIdExtensionProperty = "extension_" + iefGraphAppId + "_" + customAttribute1; | |
var filter = $"$filter=" + contactIdExtensionProperty + " eq '" + userId + "' and accountEnabled eq false"; | |
dynamic dynJson = GetExistingUsers(filter); | |
bool userExists = false; | |
foreach (var existingUser in dynJson.value) | |
{ | |
userExists = true; | |
break; | |
} | |
if (!userExists) | |
{ | |
Console.WriteLine(@"Generating password..."); | |
//https://docs.microsoft.com/en-us/azure/active-directory/active-directory-passwords-policy | |
const int requiredLength = 10; | |
var allowedCharacters = PasswordCharacters.UppercaseLetters | PasswordCharacters.LowercaseLetters | PasswordCharacters.Numbers; | |
PasswordCharacters[] requiredCharacters = { PasswordCharacters.UppercaseLetters, PasswordCharacters.LowercaseLetters, PasswordCharacters.Numbers, PasswordCharacters.Punctuations, PasswordCharacters.Punctuations }; | |
//generate a new password | |
var newPassword = PasswordGenerator.Generate(requiredLength, allowedCharacters, requiredCharacters, ".".ToArray()); | |
var country = phone.StartsWith("+") ? null : "AU"; | |
var jsonObject = new JObject | |
{ | |
{"accountEnabled", true}, | |
{"creationType", "LocalAccount"}, | |
{"extension_" + iefGraphAppId + "_" + customAttribute1, userId}, | |
{"displayName", email}, | |
{"extension_" + iefGraphAppId + "_"+customAttribute2, phone}, | |
{"extension_" + iefGraphAppId + "_"+customAttribute3, customAttribute3Value}, | |
{"passwordPolicies", "DisablePasswordExpiration"}, | |
{"country", country}, | |
{"passwordProfile", new JObject | |
{ | |
{"password", newPassword}, | |
{"forceChangePasswordNextLogin", false} | |
} | |
}, | |
{"signInNames", new JArray | |
{ | |
new JObject | |
{ | |
{"value", email}, | |
{"type", "emailAddress"} | |
} | |
} | |
} | |
}; | |
string json = JsonConvert.SerializeObject(jsonObject); | |
object formatted = JsonConvert.DeserializeObject(client.CreateUser(json).Result); | |
var jsonString = JsonConvert.SerializeObject(formatted, Formatting.Indented); | |
var objectId = JObject.Parse(jsonString)["objectId"].ToString(); | |
Console.ForegroundColor = ConsoleColor.White; | |
//append a line to the log string for log file | |
logString.AppendLine(timeStamp + ": User with Contact ID: " + userId + " imported successfully."); | |
outputString.AppendLine(userId + "," + objectId); | |
//if password needs to be exported then create a line of email,password for the password file | |
if (exportPasswords == "yes") | |
{ | |
passwordString.AppendLine(email + "," + newPassword); | |
} | |
Console.WriteLine(@"User created successfully..."); | |
} | |
else | |
{ | |
logString.AppendLine(timeStamp + ": User with Contact ID: " + userId + " already exists"); | |
Console.WriteLine(@"User already exists..."); | |
} | |
} | |
catch (Exception ex) | |
{ | |
var logMsg = ""; | |
var consoleMsg = ""; | |
var innerException = ex.InnerException; | |
if (innerException != null) | |
{ | |
while (innerException != null) | |
{ | |
logMsg = timeStamp + ": Contact ID: " + userId + " isnt imported due to the error:" + innerException.Message; | |
consoleMsg = "Error while creating user..." + innerException.Message; | |
innerException = innerException.InnerException; | |
} | |
} | |
else | |
{ | |
logMsg = timeStamp + ": Contact ID: " + userId + " isnt imported due to the error:" + ex.Message; | |
consoleMsg = "Error while creating user..." + ex.Message; | |
} | |
logString.AppendLine(logMsg); | |
Console.WriteLine(consoleMsg); | |
} | |
} | |
}); | |
//upload the log file | |
UploadFile(container, logFileName, logString.ToString(), "log"); | |
//upload the output file | |
UploadFile(container, outputFileName, outputString.ToString(), "output"); | |
//if password needs to be exported then upload the password file | |
if (exportPasswords == "yes") | |
{ | |
UploadFile(container, passwordFileName, passwordString.ToString(), "password"); | |
} | |
// Delete the input file from input blob storage container as well as working directory. | |
inputBlockBlob.Delete(); | |
Console.WriteLine(@"Deleted the input file after processing successfully"); | |
} | |
private static void UploadFile(CloudBlobContainer container, string fileName, string strToWrite, string type) | |
{ | |
// Retrieve reference to the blob | |
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName.Replace("timestamp", DateTime.Now.ToString("ddMMyyyyhhmmss"))); | |
//get bytes from the string | |
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(strToWrite)); | |
//write to the log folder | |
blockBlob.UploadFromStream(ms); | |
Console.ForegroundColor = ConsoleColor.Green; | |
Console.WriteLine(@"Uploaded the " + type + " file successfully"); | |
} | |
} | |
} |
Hi dipakfatania,
You can remove these lines of code that are referring to the library project. You wont need them.
if (phone.Length > 0)
phone = phone.ValidateMobileNumber();
{"extension_" + iefGraphAppId + "_"+customAttribute4, phone.MaskMobileNumber()},
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, Thank you for sharing great code to import bulk users. Can you please share the entire project? I am getting some problem to get this assembly B2CGraph.Library