How do I get all Teams in MS Graph C#? - c#

I have created a Team in the group successfully, now I need to cycle through the Teams so I can get their names and IDs.
I have tried the following code but without any success.
IGraphServiceTeamsCollectionPage teams = graphServiceClient
.Teams
.Request()
.GetAsync()
.Result;
foreach (Team team in teams)
{
Console.WriteLine(team.Id);
}
I get
Code: UnknownError
Message:
{
"message":"No HTTP resource was found that matches the request URI 'https://api.teams.skype.com/v1.0/teams'."
}
I've also tried doing the same against Groups without success:
var groups = await graphServiceClient.Groups
.Request()
.GetAsync();
foreach (var group in groups)
{
Console.WriteLine(group.DisplayName);
Console.WriteLine(group.Team.Id);
}
Now I get the displayName of the Group, but when trying to access the Group's Team Id I get
Object reference not set to an instance of an object.
EDIT:
I have realized that Group ID = Teams ID, however, last week I was able to update the specific team with the following command:
await graphServiceClient
.Teams[groupID]
.Request()
.UpdateAsync(team3);
but now it does not work and says:
No team found with Group Id {9032fa63-50bb-4....}
I have confirmed in PowerShell and Graph Explorer, that the Id is correct and, as I've said, it worked on Friday of last week.

Further to my comment, it seems the PageIterator class doesn't work with group collection that's returned (or I'm doing something wrong, which is possible!). In any event, this code works for getting all the groups with Teams in my environment, so you should be able to pass the Id property of each group to the Teams endpoint in Graph to carry on:
var groups = await client.Groups.Request().Select("id,displayName,resourceProvisioningOptions").Filter("resourceProvisioningOptions/Any(x:x eq 'Team')").GetAsync();
do
{
foreach(var g in groups)
{
Console.WriteLine(g.DisplayName);
Console.WriteLine(g.Id);
}
if(groups.NextPageRequest != null)
{
groups = await groups.NextPageRequest.GetAsync();
}
}
while (groups.NextPageRequest != null);
Note that filtering on resource provisioning options requires using the Beta endpoint in Graph, this currently isn't available in V1.

I am using the groupID which is equal to teamID.
var groups = await graphServiceClient.Groups.Request().GetAsync();
foreach (var group in groups)
{
Console.WriteLine(group.DisplayName);
Console.WriteLine(group.Id);
}

Related

More than one ManagedBy entity on an Active Directory group

Is it possible to have more than one entity/person listed as a manager of an AD group?
I have a distribution group created using Exchange. The group has multiple ManagedBy entities when viewed from the Exchange side.
When I query using DirectorySearcher AD only shows just one entry for ManagedBy, the first entry.
I can update the ManagedBy with a string value of a known user but using something like the below doesn't seem to work.
Code snippet A:
using (var context = new PrincipalContext(ContextType.Domain, _connection.Domain, _connection.ServiceUserName, _connection.ServicePassword))
{
using (var searcher = new PrincipalSearcher())
{
var sp = new GroupSearchPrincipal(context, groupDn);
searcher.QueryFilter = sp;
var groupSearch = searcher.FindOne();
if (groupSearch is null)
{
throw new Exception($"The Group with SamAccountName {groupDn} could not be found");
}
var directoryEntry = (DirectoryEntry)groupSearch.GetUnderlyingObject();
directoryEntry.Properties["managedBy"].Add(managerDn);
directoryEntry.CommitChanges();
directoryEntry.Close();
}
return SuccessResponse();
}
Committing the change yields the result shown in this screenshot:
The error possibly means that I'm adding a value that already exists with the included new value from 'managerDn'. Clearing the value seems to confirm this.
directoryEntry.Properties["managedBy"].Clear();
Are multiple managedBy entries exclusive to Exchange?
If the group was created with Exchange it'll likely contain the attribute
msExchCoManagedByLink
This identifies the additional ManagedBy entities I was looking for.

How to get LDAP nested groups from attribute

I can search the user and find only the groups that the user belongs to. And now i want to return all the groups/roles and assign a user to a specific group/role.
DirectoryEntry and PrincipalContext doesn't work in my case and i have tried that for days.
This is my working code for searching user group/roles which is working fine.
How can i get all the groups/roles?
And Add user to a group/role
Container = “ou=containername,ou=xx,ou=xx,O=xxxxx”
Domain = “mydomain.com”
group = ou=groups,ou=containername,ou=xx,ou=xx,O=xxxx
List<string> roles = new List<string>();
SearchRequest request = new SearchRequest("", "(&(objectClass=person)(mail=myusername))", System.DirectoryServices.Protocols.SearchScope.Subtree);
SearchResponse response = (SearchResponse)con.SendRequest(request);
if (response.Entries.Count == 0)
{
return null;
}
else
{
foreach (SearchResultEntry entry in response.Entries)
{
if (entry.Attributes["member"] != null)
{
roles = (entry.Attributes["member"].GetValues(typeof(string))).ToArray().Select(r => r.ToString()
.Substring(r.ToString().IndexOf("cn=") + 3,
r.ToString().IndexOf(",") - 3))
.ToList();
}
}
}
return roles;
I don't think you're using Active Directory. What tipped me off is that you're getting data from the member attribute of a user. That's not how it works with Active Directory (it would be memberOf).
I'm not entirely sure what you're asking for. Your title mentioned "nested groups", which means when one group is a member of another group. So I assume that would mean that you want to find every group the user is a member of and all groups that those groups are members of, etc. If that's the case, you will really have to find out what type of server you're connecting to before anyone can give you a good answer on that.
But in your question you say "How can i get all the groups/roles?" So does that mean you just want to find every group that exists? To do that, you can just do a new search and use this as the filter:
(objectClass=group)
For adding a user to a group, I think it would be something like this (where userDn is the distinguishedName of the user you want to add, and groupDn is that of the group):
var mod = new DirectoryAttributeModification {
Name = "member",
Operation = DirectoryAttributeOperation.Add
}
mod.Add(userDn);
var response = (ModifyResponse) connectionObject.SendRequest(
new ModifyRequest {
DistinguishedName = groupDn,
Modifications = { mod }
}
);
But I've never actually used LdapConnection, so you might need to tweak it.
By default, the ADLDS or AD MemberOf (User object) Member (Group object) attribute is not retrieved.
Example Solution for User
SearchRequest request = new SearchRequest("", "(&(objectClass=user)(mail=myusername))", System.DirectoryServices.Protocols.SearchScope.Subtree);
request.Attributes.Add("memberOf");
or Group
SearchRequest request = new SearchRequest("", "(&(objectClass=group))", System.DirectoryServices.Protocols.SearchScope.Subtree);
request.Attributes.Add("member");
Default LDAP Filters and Attributes for Users, Groups and Containers

Getting email addresses from AD Group MVC

I have the name of my AD Group and I need to return a list of every single email address of the users found inside. I've been looking around trying to find the answer to this but all of the results I've found are aimed at checking an AD Group for a single users email address. Often by using their windows log on username.
However, what I'm wanting to do is to grab every email address inside my target active directory group. As eventually this will be turned into an automated email that needs to be sent to only those individuals within the active directory group.
The project I'm building is making use of MVC 5.
Could someone please point me in the right direction for this?
You need to split this into two steps:
Find the group (I assume you just have the name of the group)
Get all the members.
Finding the group
You can use GroupPrincipal.FindByIdentity, which is arguably easier, but I find that's quite slow (slower the bigger your group is). I prefer to use DirectorySearcher/DirectoryEntry (which is what GroupPrincipal uses behind the scenes anyway).
To find the group, your code would look something like this:
var groupName = "MyGroup";
var search = new DirectorySearcher() {
Filter = $"(&(objectClass=group)(cn={groupName}))"
};
search.PropertiesToLoad.Add("cn"); //this is just to prevent it from returning every attribute
//This will throw an exception if the group is not found
var group = ((SearchResult)search.FindOne()).GetDirectoryEntry();
If you already have the distinguishedName of the group, you can actually skip that and just make a DirectoryEntry:
var group = new DirectoryEntry($"LDAP://{disginguishedName}");
Getting the members
I wrote an article on how to do this, with example C# code: Find all the members of a group
The example code in that article returns the DOMAIN\username, so here is the same method, modified to return a list of email addresses for all the members that have one.
Pass this method the DirectoryEntry object we found for the group. Set recursive to true if you want it to look inside nested groups.
public static IEnumerable<string> GetGroupMemberList(DirectoryEntry group, bool recursive = false) {
var members = new List<string>();
group.RefreshCache(new[] { "member" });
while (true) {
var memberDns = group.Properties["member"];
foreach (string member in memberDns) {
using (var memberDe = new DirectoryEntry($"LDAP://{member.Replace("/", "\\/")}")) {
memberDe.RefreshCache(new[] { "objectClass", "mail" });
if (recursive && memberDe.Properties["objectClass"].Contains("group")) {
members.AddRange(GetGroupMemberList(memberDe, true));
} else {
var email = memberDe.Properties["mail"].Value.ToString();
if (!string.IsNullOrEmpty(email)) {
members.Add(email);
}
}
}
}
if (memberDns.Count == 0) break;
try {
group.RefreshCache(new[] {$"member;range={members.Count}-*"});
} catch (COMException e) {
if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
break;
}
throw;
}
}
return members;
}
In my article, I also talk about primary groups and Foreign Security Principals, but you don't need to worry about that here since it's not applicable to distribution lists.

Finding changesets associated with the work item or having specific comment TFS Api

I'm trying to find all changesets associated with the work item using Microsoft.TeamFoundation.WorkItemTracking.Client. Using query I was able to get the information about the work items in question, however I cannot find any changeset information on the object I'm getting back. In addition to that there are some changesets that are not linked to specific work item but easy identifiable by the comment. Is there a quick way to find these using tfs api?
Edit: this is not a duplicate of How to get work items associated with a changeset id using tfs api? b/c in that question person has a changeset and would like to find associated work items. In my case I have a work items and I would like to find all changesets associated with the specific work items. In addition to that I need to find all changesets that have specific string in the comment.
After more googling on the subject and exploring tfs API here is what I ended up with:
If all you changesets are linked to the work items (not really my case but this is what I originally was asking about):
// based on https://etoptanci.wordpress.com/2011/05/04/seeing-all-code-changes-for-a-work-item/
private static void GetChangesForWorkItem()
{
var configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(new Uri(#"http://myserver:8080/tfs"));
var tpcService = configurationServer.GetService<ITeamProjectCollectionService>();
var collectionNodes = configurationServer.CatalogNode.QueryChildren(
new[] { CatalogResourceTypes.ProjectCollection },
false, CatalogQueryOptions.None);
var collectionNode = collectionNodes.First(x => x.Resource.DisplayName == "<collection name>");
// Use the InstanceId property to get the team project collection
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection collection = configurationServer.GetTeamProjectCollection(collectionId);
var vcs = collection.GetService<VersionControlServer>();
var store = new WorkItemStore(collection);
var workItems = new List<WorkItem>()
{
store.GetWorkItem(1123),
store.GetWorkItem(1145),
};
var associatedChangesets = new List<Changeset>();
foreach (var workItem in workItems)
{
foreach (var link in workItem.Links)
{
if((link==null) || !(link is ExternalLink))
continue;
string externalLink = ((ExternalLink)link).LinkedArtifactUri;
var artifact =LinkingUtilities.DecodeUri(externalLink);
if (artifact.ArtifactType == "Changeset")
associatedChangesets.Add(vcs.ArtifactProvider.GetChangeset(new Uri(externalLink)));
}
}
Console.WriteLine(associatedChangesets.Select(x=>x.ChangesetId).OrderBy(x => x));
}
If you need to get by comment as well then you gate all changesets for the daterange and then filter out by Changeset.Comment which is a string.
Check the REST API:
GET https://{instance}/defaultcollection/_apis/tfvc/changesets/{id}?api-version={version}[&includedetails={boolean}&includeworkitems={boolean}&includesourcerenames={boolean}&maxchangecount={int}&maxcommentlength={int}]
You can also use RestAPI (as stated in the first answer)
https://www.visualstudio.com/en-us/docs/integrate/api/wit/work-items#with-links-and-attachments
You need to filter out "relations" array with rel == "ArtifactLink"

Azure Active Directory search in hebrew

Using the Graph API I am attempting to load a list of Azure Active Directory Users according to their department. I do it like this:
public List<User> GetUsersByDepartment(string dept)
{
QueryOperationResponse<User> response;
var users = DirectoryService.users;
users = (DataServiceQuery<User>)(users.Where(user => user.department.Equals(dept)));
response = users.Execute() as QueryOperationResponse<User>;
List<User> deptUsers = response.ToList();
return deptUsers;
}
If dept is in English, I get corresponding results. If dept is in Hebrew, I get no results at all... The following works but requires a full load of the Users list:
public List<User> GetUsersByDepartment(string dept)
{
var users = DirectoryService.users.ToList();
List<User> deptUsers = users.Where(user => user.department.Equals(dept)).ToList();
return deptUsers;
}
Does the Azure Active Directory support searches in Hebrew? If so, what am I missing in my first example? Could there be a setting in the Azure Active Directory itself?
This was an issue in the service side that has now been fixed.
You should be able to verify this easily at https://graphexplorer.cloudapp.net. Just sign in to a directory with users with Unicode characters in the DisplayName (or department), and try the REST query:
https://graph.windows.net/<your domain name>/users()?$filter=startswith(displayName,'%C3%80%C3%A0%C3%88')`
(Changing the encoded Unicode characters to whatever you're looking for.)

Categories

Resources