Imports DigitalData.Modules.Database Imports DigitalData.Modules.Logging Imports DigitalData.Modules.Base Namespace SyncUsers Public Class SyncUsersMSSQL Implements ISyncUsers Private _logConfig As LogConfig Private _logger As Logger Private _mssql As MSSQLServer Private Const ADDED_WHO = "Active Directory Sync" Public Sub New(LogConfig As LogConfig, MSSQL As MSSQLServer) _logConfig = LogConfig _logger = LogConfig.GetLogger() _mssql = MSSQL End Sub Public Function SyncUsers(GroupName As String, Users As List(Of ADUser), PropertyMapping As List(Of AttributeMapping)) As List(Of ADUser) Implements ISyncUsers.SyncUsers Dim oGroupId As Integer Dim oSyncedUsers As New List(Of ADUser) Dim oSyncedUserIds As New List(Of Int64) Dim oCreatedUsers As New List(Of ADUser) Dim oUpdatedUsers As New List(Of ADUser) Try _logger.Debug("Getting group Id for group {0}", GroupName) oGroupId = GetGroupId(GroupName) If oGroupId = 0 Then _logger.Debug("Group {0} does not exist in database. Exiting.", GroupName) Return oSyncedUsers End If _logger.Debug("Using group Id {0}", oGroupId) Catch ex As Exception _logger.Error(ex) Return oSyncedUsers End Try For Each oUser In Users Dim oUserId As Long Dim oUserExists As Boolean ' Check if user already exists Try _logger.Debug("Checking if user [{0}] exists", oUser) oUserId = GetUserId(oUser.samAccountName) oUserExists = oUserId > 0 _logger.Debug("User [{0}] exists in database: [{1}]", oUser, oUserExists) Catch ex As Exception _logger.Error(ex) _logger.Warn("Could not get UserId for user. Skipping.") Continue For End Try ' Collect user ids from existing users If oUserExists Then oSyncedUserIds.Add(oUserId) End If ' Create or update user Try If Not oUserExists Then _logger.Debug("Creating new user for [{0}]", oUser) oUserId = CreateUser(oUser) _logger.Debug("User created with Id [{0}]", oUserId) _logger.Info("Added new User [{0}]", oUser) oCreatedUsers.Add(oUser) Else _logger.Debug("Updating user [{0}]", oUser) oUserId = UpdateUser(oUser) If oUserId <> 0 Then _logger.Debug("User created with Id [{0}]", oUserId) _logger.Info("Updated User [{0}]", oUser) oUpdatedUsers.Add(oUser) End If End If Catch ex As Exception _logger.Error(ex) _logger.Warn("Could Not create/update user [{0}]. Skipping.", oUser) Continue For End Try ' Add custom attributes to user Try AddCustomAttributesToUser(oUser, oUserId) Catch ex As Exception _logger.Error(ex) _logger.Debug("Could Not add custom attributes to user {0}. Continuing.", oUser) End Try ' Add the user to group Try If AddUserToGroup(oUserId, oGroupId) Then _logger.Info("User [{0}] added to group [{1}]", oUser, GroupName) End If Catch ex As Exception _logger.Error(ex) _logger.Warn("Could Not add user {0} to group {1}. Skipping.", oUser, GroupName) Continue For End Try oSyncedUsers.Add(oUser) Next ' Delete users that are assigned to the group but no longer exist in active directory Dim oUserIdString = String.Join(",", oSyncedUserIds) If oSyncedUserIds.Count = 0 Then _logger.Info("Group {0} does not contain any users.", GroupName) oUserIdString = 0 End If Dim oSQL As String = $"DELETE FROM TBDD_GROUPS_USER WHERE USER_ID NOT IN ({oUserIdString}) AND GROUP_ID = {oGroupId}" Dim oDeletedRelations = _mssql.GetScalarValue(oSQL) If oCreatedUsers.Count > 0 Then _logger.Info("Created [{0}] new users", oCreatedUsers.Count) End If _logger.Info("Updated [{0}] users", oUpdatedUsers.Count) If oDeletedRelations > 0 Then _logger.Info("Removed [{0}] users from Group [{1}]", oDeletedRelations, GroupName) End If Return oSyncedUsers End Function Private Function AddUserToGroup(UserId As Integer, GroupId As Integer) As Boolean Implements ISyncUsers.AddUserToGroup Try Dim oSQL = $"SELECT COUNT(*) FROM TBDD_GROUPS_USER WHERE USER_ID = {UserId} And GROUP_ID = {GroupId}" Dim oResult = True If _mssql.GetScalarValue(oSQL) = 0 Then oSQL = $"INSERT INTO TBDD_GROUPS_USER (USER_ID, GROUP_ID, ADDED_WHO) VALUES ({UserId}, {GroupId}, '{ADDED_WHO}')" oResult = _mssql.ExecuteNonQuery(oSQL) Else _logger.Debug($"UserGroup-Relation [{UserId}/{GroupId}] already existing") Return False End If If oResult = False Then Throw New Exception("Error while adding user to group!") End If Return True Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Private Function GetGroupId(GroupName As String) As Integer Implements ISyncUsers.GetGroupId Try Dim oSQL As String = $"SELECT GUID FROM TBDD_GROUPS WHERE UPPER(NAME) = UPPER('{GroupName}') AND AD_SYNC = 1 AND ACTIVE = 1" Dim oGroupId = _mssql.GetScalarValue(oSQL) If IsDBNull(oGroupId) OrElse oGroupId = 0 Then _logger.Debug("Group {0} not found in database.", GroupName) Return 0 End If Return oGroupId Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Private Function GetUserId(UserName As String) As Integer Implements ISyncUsers.GetUserId Try Dim oSQL As String = $"SELECT GUID FROM TBDD_USER WHERE UPPER(USERNAME) = UPPER('{UserName}')" Dim oUserId = _mssql.GetScalarValue(oSQL) If IsDBNull(oUserId) OrElse IsNothing(oUserId) OrElse oUserId = 0 Then _logger.Debug("User [{0}] does not exist", UserName) Return 0 End If Return oUserId Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Private Function CreateUser(User As ADUser) As Integer Implements ISyncUsers.CreateUser Try If User Is Nothing Then _logger.Warn("Argument [User] is nothing. Exiting.") Throw New ArgumentNullException("User") End If Dim oUserId As Integer = GetUserId(User.samAccountName) _logger.Debug("UserId of User [{0}] is [{1}]", User, oUserId) If oUserId = 0 Then Dim oPrename = User.GivenName.EscapeForSQL() Dim oSurname = User.Surname.EscapeForSQL() Dim oUsername = User.samAccountName.EscapeForSQL() Dim oEmail = User.Email.EscapeForSQL() Dim oSQL As String = $"INSERT INTO TBDD_USER (PRENAME, NAME, USERNAME, EMAIL, ADDED_WHO) VALUES ('{oPrename}', '{oSurname}', UPPER('{oUsername}'), '{oEmail}', '{ADDED_WHO}')" Dim oResult = _mssql.ExecuteNonQuery(oSQL) If oResult = True Then oUserId = _mssql.GetScalarValue("SELECT MAX(GUID) FROM TBDD_USER") Return oUserId Else Throw New Exception($"Error while inserting user {User.samAccountName}!") End If Else Return oUserId End If Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Private Function UpdateUser(User As ADUser) As Integer Try If User Is Nothing Then _logger.Warn("Error in UpdateUser - User object is nothing") Return 0 End If If User.samAccountName Is Nothing Then _logger.Warn("Error in UpdateUser - User samAccountName is nothing") Return 0 End If Dim oUserId As Integer = GetUserId(User.samAccountName) If Not IsNothing(oUserId) Then If oUserId > 0 Then Dim oPrename = User.GivenName.EscapeForSQL() Dim oSurname = User.Surname.EscapeForSQL() Dim oEmail = User.Email.EscapeForSQL() Dim oSQL As String = $"UPDATE TBDD_USER SET PRENAME = '{oPrename}', NAME = '{oSurname}', EMAIL = '{oEmail}', CHANGED_WHO = '{ADDED_WHO}' WHERE GUID = {oUserId}" Dim oResult = _mssql.ExecuteNonQuery(oSQL) If oResult = True Then Return oUserId Else Throw New Exception($"Error while updating user {User.samAccountName}!") End If Else Return oUserId End If Else _logger.Warn("Error in UpdateUser - Could not get a userid for samAccountName: " + User.samAccountName) Return 0 End If Catch ex As Exception _logger.Error(ex) Throw ex End Try End Function Public Sub AddCustomAttributesToUser(User As ADUser, UserId As Integer) Implements ISyncUsers.AddCustomAttributesToUser Dim oCustomAttributes = User.CustomAttributes _logger.Debug("Adding {0} Custom Attributes to User {1}", oCustomAttributes.Count, User) For Each oAttribute In oCustomAttributes _logger.Debug("Adding Custom Attribute [{0}] with value [{1}] to User [{2}]", oAttribute.MSSQLColumn, oAttribute.Value, User) Dim oSQL As String = $"UPDATE TBDD_USER SET {oAttribute.MSSQLColumn} = '{oAttribute.Value}', CHANGED_WHO = '{ADDED_WHO}' WHERE GUID = {UserId}" Dim oResult = _mssql.ExecuteNonQuery(oSQL) If oResult = False Then _logger.Debug("Custom Attribute {0} could not be added to user {1}", oAttribute.Name, User.samAccountName) Continue For End If Next End Sub End Class End Namespace