11using System ;
22using System . Collections . Generic ;
33using System . Linq ;
4- using System . Text ;
5- using System . Threading . Tasks ;
6- using Microsoft . Extensions . DependencyInjection ;
74using Microsoft . Extensions . Logging ;
85using Microsoft . Extensions . Options ;
9- using Microsoft . TeamFoundation . Common ;
106using Microsoft . TeamFoundation . Server ;
117using Microsoft . TeamFoundation . WorkItemTracking . Client ;
12- using Microsoft . VisualStudio . Services . Commerce ;
138using MigrationTools . DataContracts ;
14- using MigrationTools . Enrichers ;
15- using MigrationTools . Processors ;
169using MigrationTools . Processors . Infrastructure ;
1710using MigrationTools . Tools . Infrastructure ;
1811
@@ -29,7 +22,6 @@ public TfsUserMappingTool(IOptions<TfsUserMappingToolOptions> options, IServiceP
2922 {
3023 }
3124
32-
3325 private List < string > GetUsersFromWorkItems ( List < WorkItemData > workitems , List < string > identityFieldsToCheck )
3426 {
3527 List < string > foundUsers = new List < string > ( ) ;
@@ -52,22 +44,6 @@ private List<string> GetUsersFromWorkItems(List<WorkItemData> workitems, List<st
5244 return foundUsers ;
5345 }
5446
55-
56-
57- private void MapUserIdentityField ( FieldItem field )
58- {
59- if ( Options . Enabled && Options . IdentityFieldsToCheck . Contains ( field . ReferenceName ) )
60- {
61- Log . LogDebug ( $ "TfsUserMappingTool::MapUserIdentityField [ReferenceName|{ field . ReferenceName } ]") ;
62- var mapps = GetMappingFileData ( ) ;
63- if ( mapps != null && mapps . ContainsKey ( field . Value . ToString ( ) ) )
64- {
65- field . Value = mapps [ field . Value . ToString ( ) ] ;
66- }
67-
68- }
69- }
70-
7147 public void MapUserIdentityField ( Field field )
7248 {
7349 if ( Options . Enabled && Options . IdentityFieldsToCheck . Contains ( field . ReferenceName ) )
@@ -80,7 +56,6 @@ public void MapUserIdentityField(Field field)
8056 field . Value = mapps [ field . Value . ToString ( ) ] ;
8157 Log . LogDebug ( $ "TfsUserMappingTool::MapUserIdentityField::Map:[original|{ original } ][new|{ field . Value } ]") ;
8258 }
83-
8459 }
8560 }
8661
@@ -99,78 +74,79 @@ private Dictionary<string, string> GetMappingFileData()
9974 try
10075 {
10176 var fileMaps = Newtonsoft . Json . JsonConvert . DeserializeObject < List < IdentityMapData > > ( fileData ) ;
102- _UserMappings = fileMaps . ToDictionary ( x => x . Source . FriendlyName , x => x . target ? . FriendlyName ) ;
77+ _UserMappings = fileMaps . ToDictionary ( x => x . Source . FriendlyName , x => x . Target ? . FriendlyName ) ;
10378 }
10479 catch ( Exception )
10580 {
10681 _UserMappings = new Dictionary < string , string > ( ) ;
10782 Log . LogError ( $ "TfsUserMappingTool::GetMappingFileData [UserMappingFile|{ Options . UserMappingFile } ] <-- invalid - No mapping are applied!") ;
10883 }
109-
11084 }
11185 return _UserMappings ;
11286 }
11387
11488 private List < IdentityItemData > GetUsersListFromServer ( IGroupSecurityService gss )
11589 {
116- Identity SIDS = gss . ReadIdentity ( SearchFactor . AccountName , "Project Collection Valid Users" , QueryMembership . Expanded ) ;
117- var people = SIDS . Members . ToList ( ) . Where ( x => x . Contains ( " \\ " ) ) . Select ( x => x ) ;
90+ Identity allIdentities = gss . ReadIdentity ( SearchFactor . AccountName , "Project Collection Valid Users" , QueryMembership . Expanded ) ;
91+ Log . LogInformation ( "TfsUserMappingTool::GetUsersListFromServer Found {count} identities (users and groups) in server." , allIdentities . Members . Length ) ;
11892
11993 List < IdentityItemData > foundUsers = new List < IdentityItemData > ( ) ;
120- Log . LogTrace ( "TfsUserMappingTool::GetUsersListFromServer:foundUsers\\ {@foundUsers}" , foundUsers ) ;
121- foreach ( string user in people )
94+ foreach ( string sid in allIdentities . Members )
12295 {
123- Log . LogDebug ( "TfsUserMappingTool::GetUsersListFromServer::[user:{user}] Atempting to load user" , user ) ;
96+ Log . LogDebug ( "TfsUserMappingTool::GetUsersListFromServer::[user:{user}] Atempting to load user" , sid ) ;
12497 try
12598 {
126- var bits = user . Split ( '\\ ' ) ;
127- Identity sids = gss . ReadIdentity ( SearchFactor . AccountName , bits [ 1 ] , QueryMembership . Expanded ) ;
128- if ( sids != null )
99+ Identity identity = gss . ReadIdentity ( SearchFactor . Sid , sid , QueryMembership . Expanded ) ;
100+ if ( identity is null )
129101 {
130- foundUsers . Add ( new IdentityItemData ( ) { FriendlyName = sids . DisplayName , AccountName = sids . AccountName } ) ;
102+ Log . LogDebug ( "TfsUserMappingTool::GetUsersListFromServer::[user:{user}] ReadIdentity returned null" , sid ) ;
103+ }
104+ else if ( ( identity . Type == IdentityType . WindowsUser ) || ( identity . Type == IdentityType . UnknownIdentityType ) )
105+ {
106+ // UnknownIdentityType is set for users in Azure Entra ID.
107+ foundUsers . Add ( new IdentityItemData ( )
108+ {
109+ FriendlyName = identity . DisplayName ,
110+ AccountName = identity . AccountName
111+ } ) ;
131112 }
132113 else
133114 {
134- Log . LogDebug ( "TfsUserMappingTool::GetUsersListFromServer::[user:{user}] ReadIdentity returned null for {@bits }" , user , bits ) ;
115+ Log . LogDebug ( "TfsUserMappingTool::GetUsersListFromServer::[user:{user}] Not applicable identity type {identityType }" , sid , identity . Type ) ;
135116 }
136-
137117 }
138118 catch ( Exception ex )
139119 {
140120 Telemetry . TrackException ( ex , null ) ;
141- Log . LogWarning ( "TfsUserMappingTool::GetUsersListFromServer::[user:{user}] Failed With {Exception}" , user , ex . Message ) ;
121+ Log . LogWarning ( "TfsUserMappingTool::GetUsersListFromServer::[user:{user}] Failed With {Exception}" , sid , ex . Message ) ;
142122 }
143-
144123 }
124+ Log . LogInformation ( "TfsUserMappingTool::GetUsersListFromServer {count} user identities are applicable for mapping" , foundUsers . Count ) ;
145125 return foundUsers ;
146126 }
147127
148-
149128 public List < IdentityMapData > GetUsersInSourceMappedToTarget ( TfsProcessor processor )
150129 {
151130 Log . LogDebug ( "TfsUserMappingTool::GetUsersInSourceMappedToTarget" ) ;
152131 if ( Options . Enabled )
153132 {
133+ Log . LogInformation ( $ "TfsUserMappingTool::GetUsersInSourceMappedToTarget Loading identities from source server") ;
154134 var sourceUsers = GetUsersListFromServer ( processor . Source . GetService < IGroupSecurityService > ( ) ) ;
155- Log . LogDebug ( $ "TfsUserMappingTool::GetUsersInSourceMappedToTarget [SourceUsersCount| { sourceUsers . Count } ] ") ;
135+ Log . LogInformation ( $ "TfsUserMappingTool::GetUsersInSourceMappedToTarget Loading identities from target server ") ;
156136 var targetUsers = GetUsersListFromServer ( processor . Target . GetService < IGroupSecurityService > ( ) ) ;
157- Log . LogDebug ( $ "TfsUserMappingTool::GetUsersInSourceMappedToTarget [targetUsersCount|{ targetUsers . Count } ]") ;
158- return sourceUsers . Select ( sUser => new IdentityMapData { Source = sUser , target = targetUsers . SingleOrDefault ( tUser => tUser . FriendlyName == sUser . FriendlyName ) } ) . ToList ( ) ;
137+ return sourceUsers . Select ( sUser => new IdentityMapData { Source = sUser , Target = targetUsers . SingleOrDefault ( tUser => tUser . FriendlyName == sUser . FriendlyName ) } ) . ToList ( ) ;
159138 }
160139 else
161140 {
162141 Log . LogWarning ( "TfsUserMappingTool is disabled in settings. You may have users in the source that are not mapped to the target. " ) ;
163142 return null ;
164143 }
165-
166144 }
167145
168-
169146 public List < IdentityMapData > GetUsersInSourceMappedToTargetForWorkItems ( TfsProcessor processor , List < WorkItemData > sourceWorkItems )
170147 {
171148 if ( Options . Enabled )
172149 {
173-
174150 Dictionary < string , string > result = new Dictionary < string , string > ( ) ;
175151 List < string > workItemUsers = GetUsersFromWorkItems ( sourceWorkItems , Options . IdentityFieldsToCheck ) ;
176152 Log . LogDebug ( $ "TfsUserMappingTool::GetUsersInSourceMappedToTargetForWorkItems [workItemUsers|{ workItemUsers . Count } ]") ;
@@ -188,7 +164,6 @@ public List<IdentityMapData> GetUsersInSourceMappedToTargetForWorkItems(TfsProce
188164
189165 public class CaseInsensativeStringComparer : IEqualityComparer < string >
190166 {
191-
192167 public bool Equals ( string x , string y )
193168 {
194169 return x ? . IndexOf ( y , StringComparison . OrdinalIgnoreCase ) >= 0 ;
0 commit comments