static void AddUserToAccount(string username) { //Reference taken from https://blogs.msdn.microsoft.com/buckh/2014/10/07/how-to-add-licensed-users-to-vs-online-via-the-api/ try { string _personalAccessToken = ConfigurationSettings.AppSettings["appsetting.pat"].ToString(); var creds = new VssBasicCredential("", _personalAccessToken); string _vstsaccountname = ConfigurationSettings.AppSettings["appsetting.vstsacountname"].ToString(); var vssConnection = new VssConnection(new Uri("https://" + _vstsaccountname + ".vssps.visualstudio.com"), creds); string aadtenantid = ConfigurationSettings.AppSettings["appsetting.aadtenantid"].ToString(); var licensingClient = vssConnection.GetClient <LicensingHttpClient>(); var identityClient = vssConnection.GetClient <IdentityHttpClient>(); var collectionScope = identityClient.GetScopeAsync(_vstsaccountname).Result; var licensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, GroupWellKnownSidConstants.LicensedUsersGroupSid); var identifier = String.Concat(SidIdentityHelper.GetDomainSid(collectionScope.Id), SidIdentityHelper.WellKnownSidType, licensedUsersGroupDescriptor.Identifier.Substring(SidIdentityHelper.WellKnownSidPrefix.Length)); var collectionLicensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, identifier); var upnIdentity = string.Format("upn:{0}\\{1}", aadtenantid, username); var newUserDesciptor = new IdentityDescriptor(IdentityConstants.BindPendingIdentityType, upnIdentity); bool result = identityClient.AddMemberToGroupAsync(collectionLicensedUsersGroupDescriptor, newUserDesciptor).Result; var userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, username).Result.FirstOrDefault(); var entitlement = licensingClient.AssignEntitlementAsync(userIdentity.Id, AccountLicense.Auto).Result; } catch (Exception e) { Console.WriteLine(e.Message); if (e.InnerException != null) { Console.WriteLine(e.InnerException.Message); } } }
private static void AddUserToAccount(string VssAccountName, string VssUserToAddMailAddress, License VssLicense) { try { // The first call is to see if the user already exists in the account. // Since this is the first call to the service, this will trigger the sign-in window to pop up. Console.WriteLine("Sign in as the admin of account {0}. You will see a sign-in window on the desktop.", VssAccountName); var userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, VssUserToAddMailAddress).Result.FirstOrDefault(); if (userIdentity == null) { var username = VssUserToAddMailAddress.Substring(0, VssUserToAddMailAddress.IndexOf("@")); userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.MailAddress, VssUserToAddMailAddress).Result.FirstOrDefault(); } // If the identity is null, this is a user that has not yet been added to the account. // We'll need to add the user as a "bind pending" - meaning that the email address of the identity is // recorded so that the user can log into the account, but the rest of the details of the identity // won't be filled in until first login. if (userIdentity == null) { Console.WriteLine("Creating a new identity and adding it to the collection's licensed users group."); // We are adding the user to a collection, and at the moment only one collection is supported per // account in VSO. var collectionScope = identityClient.GetScopeAsync(VssAccountName).Result; // First get the descriptor for the licensed users group, which is a well known (built in) group. var licensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, GroupWellKnownSidConstants.LicensedUsersGroupSid); // Now convert that into the licensed users group descriptor into a collection scope identifier. var identifier = String.Concat(SidIdentityHelper.GetDomainSid(collectionScope.Id), SidIdentityHelper.WellKnownSidType, licensedUsersGroupDescriptor.Identifier.Substring(SidIdentityHelper.WellKnownSidPrefix.Length)); // Here we take the string representation and create the strongly-type descriptor var collectionLicensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, identifier); // Get the domain from the user that runs this code. This domain will then be used to construct // the bind-pending identity. The domain is either going to be "Windows Live ID" or the Azure // Active Directory (AAD) unique identifier, depending on whether the account is connected to // an AAD tenant. Then we'll format this as a UPN string. var currUserIdentity = vssConnection.AuthorizedIdentity.Descriptor; var directory = "Windows Live ID"; // default to an MSA (fka Live ID) if (currUserIdentity.Identifier.Contains('\\')) { // The identifier is domain\userEmailAddress, which is used by AAD-backed accounts. // We'll extract the domain from the admin user. directory = currUserIdentity.Identifier.Split(new char[] { '\\' })[0]; } var upnIdentity = string.Format("upn:{0}\\{1}", directory, VssUserToAddMailAddress); // Next we'll create the identity descriptor for a new "bind pending" user identity. var newUserDesciptor = new IdentityDescriptor(IdentityConstants.BindPendingIdentityType, upnIdentity); // We are ready to actually create the "bind pending" identity entry. First we have to add the // identity to the collection's licensed users group. Then we'll retrieve the Identity object // for this newly-added user. Without being added to the licensed users group, the identity // can't exist in the account. bool result = identityClient.AddMemberToGroupAsync(collectionLicensedUsersGroupDescriptor, newUserDesciptor).Result; userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, VssUserToAddMailAddress).Result.FirstOrDefault(); } Console.WriteLine("Assigning license to user."); var entitlement = licensingClient.AssignEntitlementAsync(userIdentity.Id, VssLicense).Result; Console.WriteLine("Success!"); } catch (Exception e) { using (StreamWriter sw = File.AppendText("fubarAccounts.txt")) { sw.WriteLine("{0}, failed, {1}", VssUserToAddMailAddress, e.InnerException.Message); } Console.WriteLine("\r\nSomething went wrong..."); Console.WriteLine(e.Message); if (e.InnerException != null) { Console.WriteLine(e.InnerException.Message); } } }
private async static Task <Guid> AddMemberToAccount(Project project, TraceWriter log) { string username = ConfigurationManager.AppSettings.Get("VSTSUserName"); string pattoken = ConfigurationManager.AppSettings.Get("VSTSPat"); string accountName = ConfigurationManager.AppSettings.Get("VSTSAccountName"); if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(pattoken) || string.IsNullOrWhiteSpace(accountName)) { log.Error("AppSettings missing for VSTSUserName, VSTSPat or VSTSAccountName"); return(Guid.Empty); } try { VssBasicCredential credentials = new VssBasicCredential(username, pattoken); VssConnection connection = new VssConnection(new Uri($"https://{accountName}.vssps.visualstudio.com/"), credentials); var identityClient = connection.GetClient <IdentityHttpClient>(); var licensingClient = connection.GetClient <LicensingHttpClient>(); var userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, project.Owner).Result.FirstOrDefault(); // If the identity is null, this is a user that has not yet been added to the account. // We'll need to add the user as a "bind pending" - meaning that the email address of the identity is // recorded so that the user can log into the account, but the rest of the details of the identity // won't be filled in until first login. if (userIdentity != null) { log.Info($"User:{project.Owner} already exists in VSTS account with name: {accountName}"); return(userIdentity.Id); } log.Info("Creating a new identity and adding it to the collection's licensed users group."); var collectionScope = identityClient.GetScopeAsync(accountName).Result; // First get the descriptor for the licensed users group, which is a well known (built in) group. var licensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, GroupWellKnownSidConstants.LicensedUsersGroupSid); // Now convert that into the licensed users group descriptor into a collection scope identifier. var identifier = string.Concat(SidIdentityHelper.GetDomainSid(collectionScope.Id), SidIdentityHelper.WellKnownSidType, licensedUsersGroupDescriptor.Identifier.Substring(SidIdentityHelper.WellKnownSidPrefix.Length)); // Here we take the string representation and create the strongly-type descriptor var collectionLicensedUsersGroupDescriptor = new IdentityDescriptor(IdentityConstants.TeamFoundationType, identifier); // Get the domain from the user that runs this code. This domain will then be used to construct // the bind-pending identity. The domain is either going to be "Windows Live ID" or the Azure // Active Directory (AAD) unique identifier, depending on whether the account is connected to // an AAD tenant. Then we'll format this as a UPN string. var currUserIdentity = connection.AuthorizedIdentity.Descriptor; if (!currUserIdentity.Identifier.Contains('\\')) { log.Error("Could not find directory for user"); return(Guid.Empty); } // The identifier is domain\userEmailAddress, which is used by AAD-backed accounts. // We'll extract the domain from the admin user. var directory = currUserIdentity.Identifier.Split(new char[] { '\\' })[0]; var upnIdentity = string.Format("upn:{0}\\{1}", directory, project.Owner); // Next we'll create the identity descriptor for a new "bind pending" user identity. var newUserDesciptor = new IdentityDescriptor(IdentityConstants.BindPendingIdentityType, upnIdentity); // We are ready to actually create the "bind pending" identity entry. First we have to add the // identity to the collection's licensed users group. Then we'll retrieve the Identity object // for this newly-added user. Without being added to the licensed users group, the identity // can't exist in the account. bool result = identityClient.AddMemberToGroupAsync(collectionLicensedUsersGroupDescriptor, newUserDesciptor).Result; userIdentity = identityClient.ReadIdentitiesAsync(IdentitySearchFilter.AccountName, project.Owner).Result.FirstOrDefault(); log.Info("Assigning license to user."); Microsoft.VisualStudio.Services.Licensing.License licence = GetLicense(); var entitlement = licensingClient.AssignEntitlementAsync(userIdentity.Id, licence, false).Result; log.Info($"Added {project.Owner} as a user with license:{licence.ToString()} to account with name:{accountName}"); return(userIdentity.Id); } catch (Exception e) { log.Error(e.Message); return(Guid.Empty); } }