initial
This commit is contained in:
161
LIAM.sln
Normal file
161
LIAM.sln
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.6.33723.286
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamTestTeams", "LiamTestTeams\LiamTestTeams.csproj", "{6197C490-07C6-4313-8E0F-AADC27776473}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{451CEE78-7CF7-4691-AAB6-4D636BF22E04}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
_shared\Matrix42.Common.dll = _shared\Matrix42.Common.dll
|
||||||
|
SharedAssemblyInfo.cs = SharedAssemblyInfo.cs
|
||||||
|
_shared\System.Web.Http.dll = _shared\System.Web.Http.dll
|
||||||
|
_shared\update4u.SPS.DataLayer.dll = _shared\update4u.SPS.DataLayer.dll
|
||||||
|
_shared\update4u.SPS.DataLayer_alt.dll = _shared\update4u.SPS.DataLayer_alt.dll
|
||||||
|
_shared\update4u.SPS.Security.dll = _shared\update4u.SPS.Security.dll
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamBaseClasses", "LiamBaseClasses\LiamBaseClasses.csproj", "{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamMsTeams", "LiamMsTeams\LiamMsTeams.csproj", "{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamHelper", "LiamHelper\LiamHelper.csproj", "{6B0E73A6-F918-42D5-9525-D59D4D16283D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamMsGraph", "LiamMsGraph\LiamMsGraph.csproj", "{452827DB-14FF-469E-AF41-1A24E1875BDA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamM42WebApi", "LiamM42WebApi\LiamM42WebApi.csproj", "{007A69B8-3BEA-44F3-BD61-C5354C707F3A}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{452827DB-14FF-469E-AF41-1A24E1875BDA} = {452827DB-14FF-469E-AF41-1A24E1875BDA}
|
||||||
|
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C} = {DACBD3DC-1866-4B39-964A-D2A8DEA2774C}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamNtfs", "LiamNtfs\LiamNtfs.csproj", "{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamWorkflowActivities", "LiamWorkflowActivities\LiamWorkflowActivities.csproj", "{5840BB2D-88BF-4E1C-8FF6-510305894B42}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamWorkflowActivitiesDesign", "LiamWorkflowActivitiesDesign\LiamWorkflowActivitiesDesign.csproj", "{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamActiveDirectory", "LIAMActiveDirectory\LiamActiveDirectory.csproj", "{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiamExchange", "LiamExchange\LiamExchange.csproj", "{12586A29-BB1E-49B4-B971-88E520D6A77C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug_and_copy|Any CPU = Debug_and_copy|Any CPU
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6197C490-07C6-4313-8E0F-AADC27776473}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6197C490-07C6-4313-8E0F-AADC27776473}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6197C490-07C6-4313-8E0F-AADC27776473}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DACBD3DC-1866-4B39-964A-D2A8DEA2774C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6B0E73A6-F918-42D5-9525-D59D4D16283D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{452827DB-14FF-469E-AF41-1A24E1875BDA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug_and_copy|Any CPU.ActiveCfg = Debug_and_copy|Any CPU
|
||||||
|
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug_and_copy|Any CPU.Build.0 = Debug_and_copy|Any CPU
|
||||||
|
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{007A69B8-3BEA-44F3-BD61-C5354C707F3A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5840BB2D-88BF-4E1C-8FF6-510305894B42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{03D5EBBD-3147-4B30-AE90-6D5C57335E0A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug_and_copy|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{12586A29-BB1E-49B4-B971-88E520D6A77C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {0EC9AD55-4DBA-49C3-BEEF-5EC07E361909}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(TeamFoundationVersionControl) = preSolution
|
||||||
|
SccNumberOfProjects = 12
|
||||||
|
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
||||||
|
SccTeamFoundationServer = https://consulting4it.visualstudio.com/
|
||||||
|
SccLocalPath0 = .
|
||||||
|
SccProjectUniqueName1 = LiamBaseClasses\\LiamBaseClasses.csproj
|
||||||
|
SccProjectName1 = LiamBaseClasses
|
||||||
|
SccLocalPath1 = LiamBaseClasses
|
||||||
|
SccProjectUniqueName2 = LiamHelper\\LiamHelper.csproj
|
||||||
|
SccProjectName2 = LiamHelper
|
||||||
|
SccLocalPath2 = LiamHelper
|
||||||
|
SccProjectUniqueName3 = LiamM42WebApi\\LiamM42WebApi.csproj
|
||||||
|
SccProjectName3 = LiamM42WebApi
|
||||||
|
SccLocalPath3 = LiamM42WebApi
|
||||||
|
SccProjectUniqueName4 = LiamMsGraph\\LiamMsGraph.csproj
|
||||||
|
SccProjectName4 = LiamMsGraph
|
||||||
|
SccLocalPath4 = LiamMsGraph
|
||||||
|
SccProjectUniqueName5 = LiamMsTeams\\LiamMsTeams.csproj
|
||||||
|
SccProjectName5 = LiamMsTeams
|
||||||
|
SccLocalPath5 = LiamMsTeams
|
||||||
|
SccProjectUniqueName6 = LiamTestTeams\\LiamTestTeams.csproj
|
||||||
|
SccProjectName6 = LiamTestTeams
|
||||||
|
SccLocalPath6 = LiamTestTeams
|
||||||
|
SccProjectUniqueName7 = LiamNtfs\\LiamNtfs.csproj
|
||||||
|
SccProjectName7 = LiamNtfs
|
||||||
|
SccLocalPath7 = LiamNtfs
|
||||||
|
SccProjectUniqueName8 = LiamWorkflowActivities\\LiamWorkflowActivities.csproj
|
||||||
|
SccProjectName8 = LiamWorkflowActivities
|
||||||
|
SccLocalPath8 = LiamWorkflowActivities
|
||||||
|
SccProjectUniqueName9 = LiamWorkflowActivitiesDesign\\LiamWorkflowActivitiesDesign.csproj
|
||||||
|
SccProjectName9 = LiamWorkflowActivitiesDesign
|
||||||
|
SccLocalPath9 = LiamWorkflowActivitiesDesign
|
||||||
|
SccProjectUniqueName10 = LIAMActiveDirectory\\LiamActiveDirectory.csproj
|
||||||
|
SccProjectName10 = LIAMActiveDirectory
|
||||||
|
SccLocalPath10 = LIAMActiveDirectory
|
||||||
|
SccProjectUniqueName11 = LiamExchange\\LiamExchange.csproj
|
||||||
|
SccProjectName11 = LiamExchange
|
||||||
|
SccLocalPath11 = LiamExchange
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
371
LIAMActiveDirectory/C4IT.LIAM.AD.cs
Normal file
371
LIAMActiveDirectory/C4IT.LIAM.AD.cs
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.DirectoryServices.AccountManagement;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using C4IT.Logging;
|
||||||
|
using C4IT.Matrix42.ServerInfo;
|
||||||
|
using LiamAD;
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
using static LiamAD.ADServiceGroupCreator;
|
||||||
|
using static LiamAD.cActiveDirectoryBase;
|
||||||
|
|
||||||
|
namespace C4IT.LIAM
|
||||||
|
{
|
||||||
|
public static class LiamInitializer
|
||||||
|
{
|
||||||
|
static public cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||||
|
{
|
||||||
|
return new cLiamProviderAD(LiamConfiguration, ProviderData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamProviderAD : cLiamProviderBase
|
||||||
|
{
|
||||||
|
public static Guid adModuleId = new Guid("e820a625-0653-ee11-b886-00155d300101");
|
||||||
|
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||||||
|
private readonly ADServiceGroupCreator _serviceGroupCreator;
|
||||||
|
|
||||||
|
|
||||||
|
public cLiamProviderAD(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) :
|
||||||
|
base(LiamConfiguration, ProviderData)
|
||||||
|
{
|
||||||
|
_serviceGroupCreator = new ADServiceGroupCreator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Tuple<string, string, string, string>> CreateServiceGroups(
|
||||||
|
string serviceName,
|
||||||
|
string description = null,
|
||||||
|
eLiamAccessRoleScopes gruppenbereich = eLiamAccessRoleScopes.Universal,
|
||||||
|
ADGroupType gruppentyp = ADGroupType.Distribution,
|
||||||
|
IEnumerable<string> ownerSidList = null,
|
||||||
|
IEnumerable<string> memberSidList = null)
|
||||||
|
{
|
||||||
|
return _serviceGroupCreator.EnsureServiceGroups(
|
||||||
|
serviceName,
|
||||||
|
description,
|
||||||
|
gruppenbereich,
|
||||||
|
gruppentyp,
|
||||||
|
ownerSidList,
|
||||||
|
memberSidList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> LogonAsync()
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||||
|
{
|
||||||
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return await LogonAsync(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> LogonAsync(bool force = false)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var LI = new cADLogonInfo()
|
||||||
|
{
|
||||||
|
Domain = Domain,
|
||||||
|
User = Credential?.Identification,
|
||||||
|
UserSecret = Credential?.Secret,
|
||||||
|
TargetGroupPath = this.GroupPath
|
||||||
|
};
|
||||||
|
var RetVal = await activeDirectoryBase.LogonAsync(LI);
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getDataAreasAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||||
|
{
|
||||||
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
if (!await LogonAsync())
|
||||||
|
return null;
|
||||||
|
if (string.IsNullOrEmpty(this.GroupPath))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 1. Alle Roh-Resultate einlesen
|
||||||
|
var rawList = await activeDirectoryBase.RequestSecurityGroupsListAsync(this.GroupFilter);
|
||||||
|
if (rawList == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 2. Nur die, die dem RegEx entsprechen und deren Wert extrahieren
|
||||||
|
var allResults = rawList
|
||||||
|
.Where(entry =>
|
||||||
|
string.IsNullOrEmpty(this.GroupRegEx)
|
||||||
|
|| Regex.Match(entry.Value.DisplayName, this.GroupRegEx).Success)
|
||||||
|
.Select(entry => (cSecurityGroupResult)entry.Value)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// 3. ManagedBySID-Werte sammeln (ohne Null-/Leereinträge)
|
||||||
|
var managedBySids = new HashSet<string>(
|
||||||
|
allResults
|
||||||
|
.Select(r => r.ManagedBySID)
|
||||||
|
.Where(m => !string.IsNullOrEmpty(m))
|
||||||
|
);
|
||||||
|
|
||||||
|
// 4. Nur die Gruppen, deren ID nicht in managedBySids enthalten ist
|
||||||
|
var filteredResults = allResults
|
||||||
|
.Where(r => !managedBySids.Contains(r.ID))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// 5. In DataArea-Objekte umwandeln
|
||||||
|
var SecurityGroups = new List<cLiamDataAreaBase>();
|
||||||
|
foreach (var secGroup in filteredResults)
|
||||||
|
{
|
||||||
|
SecurityGroups.Add(new cLiamAdGroupAsDataArea(this, secGroup));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SecurityGroups;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter)
|
||||||
|
{
|
||||||
|
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||||
|
{
|
||||||
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
if (!await LogonAsync())
|
||||||
|
return null;
|
||||||
|
if (string.IsNullOrEmpty(this.GroupPath))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var SecurityGroups = new List<cLiamDataAreaBase>();
|
||||||
|
|
||||||
|
var SGL = await activeDirectoryBase.RequestSecurityGroupsListAsync(groupFilter);
|
||||||
|
if (SGL == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
foreach (var Entry in SGL)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(this.GroupRegEx) && !Regex.Match(Entry.Value.DisplayName, this.GroupRegEx).Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
|
||||||
|
var SecurityGroup = new cLiamAdGroup2(this, (cSecurityGroupResult)Entry.Value);
|
||||||
|
SecurityGroups.Add(SecurityGroup);
|
||||||
|
}
|
||||||
|
return SecurityGroups;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public int getDepth(string path)
|
||||||
|
{
|
||||||
|
return getDepth(this.RootPath, path);
|
||||||
|
}
|
||||||
|
public static int getDepth(DirectoryInfo root, DirectoryInfo folder)
|
||||||
|
{
|
||||||
|
var rootDepth = root.FullName.TrimEnd(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar).Length;
|
||||||
|
var folderDepth = folder.FullName.TrimEnd(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar).Length;
|
||||||
|
return folderDepth - rootDepth;
|
||||||
|
|
||||||
|
}
|
||||||
|
public static int getDepth(string root, string folder)
|
||||||
|
{
|
||||||
|
return getDepth(new DirectoryInfo(root), new DirectoryInfo(folder));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetLastErrorMessage()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
||||||
|
{
|
||||||
|
//TODO implement LoadDataArea
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid || !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(adModuleId))
|
||||||
|
{
|
||||||
|
LogEntry($"Error: License not valid", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var res = new cLiamAdGroupAsDataArea(this, new cSecurityGroupResult()
|
||||||
|
{
|
||||||
|
Path = UID
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class cLiamAdGroupAsDataArea : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderAD Provider = null;
|
||||||
|
public readonly string dn = null;
|
||||||
|
public readonly string scope = null;
|
||||||
|
public readonly string ManagedBySID;
|
||||||
|
|
||||||
|
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
public cLiamAdGroupAsDataArea(cLiamProviderAD Provider, cSecurityGroupResult secGroup) : base(Provider)
|
||||||
|
{
|
||||||
|
this.UID = secGroup.ID;
|
||||||
|
this.TechnicalName = secGroup.Path;
|
||||||
|
this.DisplayName = secGroup.DisplayName;
|
||||||
|
this.Description = secGroup.Description;
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.dn = secGroup.Path;
|
||||||
|
this.scope = secGroup.Scope.ToString();
|
||||||
|
this.ManagedBySID = secGroup.ManagedBySID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await GetMembersAsync(true);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task<List<cLiamUserInfo>> GetMembersAsync(bool owners)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var AD = this.Provider?.activeDirectoryBase;
|
||||||
|
if (AD == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not get ad class from Provider for folder '{this.TechnicalName}'", LogLevels.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cADCollectionBase lstMembers;
|
||||||
|
if (owners && !string.IsNullOrEmpty(OwnerRef))
|
||||||
|
lstMembers = await AD.GetMembersAsync(OwnerRef);
|
||||||
|
else if (owners && !string.IsNullOrEmpty(dn))
|
||||||
|
lstMembers = await AD.GetManagedByMembersAsync(this.dn);
|
||||||
|
else
|
||||||
|
lstMembers = null;
|
||||||
|
if (lstMembers == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not get owner list for folder '{this.TechnicalName}'", LogLevels.Warning);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var RetVal = new List<cLiamUserInfo>(lstMembers.Count);
|
||||||
|
LogEntry($"Owners for folder found: {lstMembers.Count}", LogLevels.Debug);
|
||||||
|
foreach (var MemberEntry in lstMembers.Values)
|
||||||
|
{
|
||||||
|
var User = new cLiamUserInfo()
|
||||||
|
{
|
||||||
|
DisplayName = MemberEntry.DisplayName,
|
||||||
|
UserPrincipalName = (MemberEntry as cADUserResult).UserPrincipalName,
|
||||||
|
SID = MemberEntry.ID
|
||||||
|
};
|
||||||
|
RetVal.Add(User);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class cLiamAdGroup2 : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderAD Provider = null;
|
||||||
|
public readonly string dn = null;
|
||||||
|
public readonly string scope = null;
|
||||||
|
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
public cLiamAdGroup2(cLiamProviderAD Provider, cSecurityGroupResult secGroup) : base(Provider)
|
||||||
|
{
|
||||||
|
this.DisplayName = secGroup.DisplayName;
|
||||||
|
this.UID = secGroup.ID;
|
||||||
|
this.TechnicalName = secGroup.DisplayName;
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.dn = secGroup.Path;
|
||||||
|
this.scope = secGroup.Scope.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
LIAMActiveDirectory/LIAMActiveDirectory.csproj.vspscc
Normal file
10
LIAMActiveDirectory/LIAMActiveDirectory.csproj.vspscc
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
""
|
||||||
|
{
|
||||||
|
"FILE_VERSION" = "9237"
|
||||||
|
"ENLISTMENT_CHOICE" = "NEVER"
|
||||||
|
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||||
|
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||||
|
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||||
|
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||||
|
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||||
|
}
|
||||||
74
LIAMActiveDirectory/LiamActiveDirectory.csproj
Normal file
74
LIAMActiveDirectory/LiamActiveDirectory.csproj
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{AECA0AD2-8B91-4767-9AFA-E160F6662DBE}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>LIAMActiveDirectory</RootNamespace>
|
||||||
|
<AssemblyName>LiamActiveDirectory</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<SccProjectName>SAK</SccProjectName>
|
||||||
|
<SccLocalPath>SAK</SccLocalPath>
|
||||||
|
<SccAuxPath>SAK</SccAuxPath>
|
||||||
|
<SccProvider>SAK</SccProvider>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.DirectoryServices" />
|
||||||
|
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||||
|
<Reference Include="System.ValueTuple, Version=4.0.5.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.ValueTuple.4.6.1\lib\net462\System.ValueTuple.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="cActiveDirectoryBase.cs" />
|
||||||
|
<Compile Include="C4IT.LIAM.AD.cs" />
|
||||||
|
<Compile Include="cADBase.cs" />
|
||||||
|
<Compile Include="cADServiceGroupCreator.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiamBaseClasses\LiamBaseClasses.csproj">
|
||||||
|
<Project>{3531c9e6-cf6e-458e-b604-4a5a8d1c7ab0}</Project>
|
||||||
|
<Name>LiamBaseClasses</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\LiamHelper\LiamHelper.csproj">
|
||||||
|
<Project>{6b0e73a6-f918-42d5-9525-d59d4d16283d}</Project>
|
||||||
|
<Name>LiamHelper</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
36
LIAMActiveDirectory/Properties/AssemblyInfo.cs
Normal file
36
LIAMActiveDirectory/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("LIAMActiveDirectory")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("LIAMActiveDirectory")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2024")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("aeca0ad2-8b91-4767-9afa-e160f6662dbe")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Debug/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/Newtonsoft.Json.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Debug/System.ValueTuple.dll
Normal file
BIN
LIAMActiveDirectory/bin/Debug/System.ValueTuple.dll
Normal file
Binary file not shown.
1299
LIAMActiveDirectory/bin/Debug/System.ValueTuple.xml
Normal file
1299
LIAMActiveDirectory/bin/Debug/System.ValueTuple.xml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.pdb
Normal file
BIN
LIAMActiveDirectory/bin/Release/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/Newtonsoft.Json.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/bin/Release/System.ValueTuple.dll
Normal file
BIN
LIAMActiveDirectory/bin/Release/System.ValueTuple.dll
Normal file
Binary file not shown.
1299
LIAMActiveDirectory/bin/Release/System.ValueTuple.xml
Normal file
1299
LIAMActiveDirectory/bin/Release/System.ValueTuple.xml
Normal file
File diff suppressed because it is too large
Load Diff
142
LIAMActiveDirectory/cADBase.cs
Normal file
142
LIAMActiveDirectory/cADBase.cs
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
using C4IT.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.DirectoryServices.AccountManagement;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LiamAD
|
||||||
|
{
|
||||||
|
public class cADBase
|
||||||
|
{
|
||||||
|
private cADLogonInfo privLogonInfo = null;
|
||||||
|
private int scanningDepth;
|
||||||
|
public PrincipalContext adContext = null;
|
||||||
|
public Exception LastException { get; private set; } = null;
|
||||||
|
public string LastErrorMessage { get; private set; } = null;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void ResetError()
|
||||||
|
{
|
||||||
|
LastException = null;
|
||||||
|
LastErrorMessage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void SetErrorException(string Action, Exception E, LogLevels lev = LogLevels.Error)
|
||||||
|
{
|
||||||
|
LastException = E;
|
||||||
|
LastErrorMessage = Action + ": " + E.Message;
|
||||||
|
cLogManager.LogEntry(Action, lev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport("mpr.dll")]
|
||||||
|
private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags);
|
||||||
|
|
||||||
|
[DllImport("mpr.dll")]
|
||||||
|
private static extern int WNetCancelConnection2(string name, int flags,
|
||||||
|
bool force);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class cADLogonInfo
|
||||||
|
{
|
||||||
|
public string Domain;
|
||||||
|
public string User;
|
||||||
|
public string UserSecret;
|
||||||
|
public string TargetGroupPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public class NetResource
|
||||||
|
{
|
||||||
|
public ResourceScope Scope;
|
||||||
|
public ResourceType ResourceType;
|
||||||
|
public ResourceDisplaytype DisplayType;
|
||||||
|
public int Usage;
|
||||||
|
public string LocalName;
|
||||||
|
public string RemoteName;
|
||||||
|
public string Comment;
|
||||||
|
public string Provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ResourceScope : int
|
||||||
|
{
|
||||||
|
Connected = 1,
|
||||||
|
GlobalNetwork,
|
||||||
|
Remembered,
|
||||||
|
Recent,
|
||||||
|
Context
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum ResourceType : int
|
||||||
|
{
|
||||||
|
Any = 0,
|
||||||
|
Disk = 1,
|
||||||
|
Print = 2,
|
||||||
|
Reserved = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ResourceDisplaytype : int
|
||||||
|
{
|
||||||
|
Generic = 0x0,
|
||||||
|
Domain = 0x01,
|
||||||
|
Server = 0x02,
|
||||||
|
Share = 0x03,
|
||||||
|
File = 0x04,
|
||||||
|
Group = 0x05,
|
||||||
|
Network = 0x06,
|
||||||
|
Root = 0x07,
|
||||||
|
Shareadmin = 0x08,
|
||||||
|
Directory = 0x09,
|
||||||
|
Tree = 0x0a,
|
||||||
|
Ndscontainer = 0x0b
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum NetError : uint
|
||||||
|
{
|
||||||
|
NERR_Success = 0,
|
||||||
|
NERR_BASE = 2100,
|
||||||
|
NERR_UnknownDevDir = (NERR_BASE + 16),
|
||||||
|
NERR_DuplicateShare = (NERR_BASE + 18),
|
||||||
|
NERR_BufTooSmall = (NERR_BASE + 23),
|
||||||
|
}
|
||||||
|
public enum SHARE_TYPE : uint
|
||||||
|
{
|
||||||
|
STYPE_DISKTREE = 0,
|
||||||
|
STYPE_PRINTQ = 1,
|
||||||
|
STYPE_DEVICE = 2,
|
||||||
|
STYPE_IPC = 3,
|
||||||
|
STYPE_SPECIAL = 0x80000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
public struct SHARE_INFO_1
|
||||||
|
{
|
||||||
|
public string shi1_netname;
|
||||||
|
public uint shi1_type;
|
||||||
|
public string shi1_remark;
|
||||||
|
public SHARE_INFO_1(string sharename, uint sharetype, string remark)
|
||||||
|
{
|
||||||
|
this.shi1_netname = sharename;
|
||||||
|
this.shi1_type = sharetype;
|
||||||
|
this.shi1_remark = remark;
|
||||||
|
}
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return shi1_netname;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
288
LIAMActiveDirectory/cADServiceGroupCreator.cs
Normal file
288
LIAMActiveDirectory/cADServiceGroupCreator.cs
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
using System;
|
||||||
|
using System.DirectoryServices;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using C4IT.Logging;
|
||||||
|
using C4IT.LIAM;
|
||||||
|
using LiamAD;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace LiamAD
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helfer für cLiamProviderAD: Erstellt AD Member- und Owner-Gruppen für Services
|
||||||
|
/// nach konfigurierter Namenskonvention und setzt ManagedBy.
|
||||||
|
/// </summary>
|
||||||
|
public class ADServiceGroupCreator
|
||||||
|
{
|
||||||
|
private readonly cLiamProviderAD _provider;
|
||||||
|
private readonly cActiveDirectoryBase _adBase;
|
||||||
|
private readonly string _ldapRoot;
|
||||||
|
private readonly string _user;
|
||||||
|
private readonly string _password;
|
||||||
|
public enum ADGroupType
|
||||||
|
{
|
||||||
|
Security, // Sicherheit
|
||||||
|
Distribution // Verteiler
|
||||||
|
}
|
||||||
|
public ADServiceGroupCreator(cLiamProviderAD provider)
|
||||||
|
{
|
||||||
|
_provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||||
|
_adBase = provider.activeDirectoryBase;
|
||||||
|
_ldapRoot = $"LDAP://{provider.Domain}/{provider.GroupPath}";
|
||||||
|
_user = provider.Credential.Identification;
|
||||||
|
_password = new System.Net.NetworkCredential(_user, provider.Credential.Secret).Password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Erstellt oder findet beide AD-Gruppen (Member & Owner) für einen Service.
|
||||||
|
/// Neu mit: gruppenbereich (Scope) und gruppentyp (für Member-Gruppe).
|
||||||
|
/// Owner-Gruppe ist immer Security.
|
||||||
|
/// </summary>
|
||||||
|
public List<Tuple<string, string, string, string>> EnsureServiceGroups(
|
||||||
|
string serviceName,
|
||||||
|
string description = null,
|
||||||
|
eLiamAccessRoleScopes gruppenbereich = eLiamAccessRoleScopes.Universal,
|
||||||
|
ADGroupType gruppentyp = ADGroupType.Distribution,
|
||||||
|
IEnumerable<string> ownerSidList = null,
|
||||||
|
IEnumerable<string> memberSidList = null)
|
||||||
|
{
|
||||||
|
const int MaxLoop = 50;
|
||||||
|
var result = new List<Tuple<string, string, string, string>>();
|
||||||
|
|
||||||
|
// Konventionen für Member und Owner
|
||||||
|
var ownerConv = _provider.NamingConventions
|
||||||
|
.FirstOrDefault(nc => nc.AccessRole == eLiamAccessRoles.ADOwner);
|
||||||
|
var memberConv = _provider.NamingConventions
|
||||||
|
.FirstOrDefault(nc => nc.AccessRole == eLiamAccessRoles.ADMember);
|
||||||
|
if (ownerConv == null || memberConv == null)
|
||||||
|
throw new InvalidOperationException("Namenskonvention für ADMember oder ADOwner fehlt.");
|
||||||
|
|
||||||
|
// Tags
|
||||||
|
_provider.CustomTags.TryGetValue("ADGroupPrefix", out var prefix);
|
||||||
|
_provider.CustomTags.TryGetValue("ADOwner", out var ownerPostfix);
|
||||||
|
_provider.CustomTags.TryGetValue("ADMember", out var memberPostfix);
|
||||||
|
|
||||||
|
// 1) Owner-Gruppe (immer Security)
|
||||||
|
string ownerName = null;
|
||||||
|
for (int loop = 0; loop <= MaxLoop; loop++)
|
||||||
|
{
|
||||||
|
string loopPart = loop > 0 ? "_" + loop : string.Empty;
|
||||||
|
ownerName = ownerConv.NamingTemplate
|
||||||
|
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||||
|
.Replace("{{NAME}}", serviceName)
|
||||||
|
.Replace("{{_LOOP}}", loopPart)
|
||||||
|
.Replace("{{GROUPTYPEPOSTFIX}}", ownerPostfix);
|
||||||
|
if (!GroupExists(ownerName)) break;
|
||||||
|
if (loop == MaxLoop) throw new InvalidOperationException($"Kein eindeutiger Owner-Name für '{serviceName}' nach {MaxLoop} Versuchen.");
|
||||||
|
}
|
||||||
|
EnsureGroup(ownerName, ownerConv, description, managedByDn: null, gruppenbereich, ADGroupType.Security);
|
||||||
|
AddMembersBySid(ownerName, ownerSidList); // NEU: SIDs als Owner hinzufügen
|
||||||
|
var ownerDn = GetDistinguishedName(ownerName);
|
||||||
|
var ownerSid = GetSid(ownerName);
|
||||||
|
result.Add(Tuple.Create(eLiamAccessRoles.ADOwner.ToString(), ownerSid, ownerName, ownerDn));
|
||||||
|
|
||||||
|
|
||||||
|
// 2) Member-Gruppe (Gruppentyp nach Parameter)
|
||||||
|
string memberName = null;
|
||||||
|
for (int loop = 0; loop <= MaxLoop; loop++)
|
||||||
|
{
|
||||||
|
string loopPart = loop > 0 ? "_" + loop : string.Empty;
|
||||||
|
memberName = memberConv.NamingTemplate
|
||||||
|
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||||
|
.Replace("{{NAME}}", serviceName)
|
||||||
|
.Replace("{{_LOOP}}", loopPart)
|
||||||
|
.Replace("{{GROUPTYPEPOSTFIX}}", memberPostfix);
|
||||||
|
if (!GroupExists(memberName)) break;
|
||||||
|
if (loop == MaxLoop) throw new InvalidOperationException($"Kein eindeutiger Member-Name für '{serviceName}' nach {MaxLoop} Versuchen.");
|
||||||
|
}
|
||||||
|
EnsureGroup(memberName, memberConv, description, managedByDn: ownerDn, gruppenbereich, gruppentyp);
|
||||||
|
AddMembersBySid(memberName, memberSidList); // NEU: SIDs als Member hinzufügen
|
||||||
|
var memberDn = GetDistinguishedName(memberName);
|
||||||
|
var memberSid = GetSid(memberName);
|
||||||
|
result.Add(Tuple.Create(eLiamAccessRoles.ADMember.ToString(), memberSid, memberName, memberDn));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Fügt einer bestehenden Gruppe per SID die entsprechenden AD-Objekte hinzu.
|
||||||
|
/// </summary>
|
||||||
|
private void AddMembersBySid(string groupName, IEnumerable<string> sidList)
|
||||||
|
{
|
||||||
|
if (sidList == null) return;
|
||||||
|
|
||||||
|
// Basis für die Suche: komplette Domäne, nicht nur der OU-Pfad
|
||||||
|
string domainRoot = $"LDAP://{_provider.Domain}";
|
||||||
|
using (var root = new DirectoryEntry(domainRoot, _user, _password, AuthenticationTypes.Secure))
|
||||||
|
using (var grpSearch = new DirectorySearcher(root))
|
||||||
|
{
|
||||||
|
grpSearch.Filter = $"(&(objectCategory=group)(sAMAccountName={groupName}))";
|
||||||
|
var grpRes = grpSearch.FindOne();
|
||||||
|
if (grpRes == null) return;
|
||||||
|
|
||||||
|
var grpEntry = grpRes.GetDirectoryEntry();
|
||||||
|
foreach (var sidStr in sidList)
|
||||||
|
{
|
||||||
|
// Leere oder null überspringen
|
||||||
|
if (string.IsNullOrWhiteSpace(sidStr))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SecurityIdentifier sid;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sid = new SecurityIdentifier(sidStr);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Ungültige SID-String-Darstellung überspringen
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In LDAP-Filter-Notation umwandeln
|
||||||
|
var bytes = new byte[sid.BinaryLength];
|
||||||
|
sid.GetBinaryForm(bytes, 0);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var b in bytes)
|
||||||
|
sb.AppendFormat("\\{0:X2}", b);
|
||||||
|
string octetSid = sb.ToString();
|
||||||
|
|
||||||
|
// Suche nach dem Objekt in der Domäne
|
||||||
|
using (var usrSearch = new DirectorySearcher(root))
|
||||||
|
{
|
||||||
|
usrSearch.Filter = $"(objectSid={octetSid})";
|
||||||
|
var usrRes = usrSearch.FindOne();
|
||||||
|
if (usrRes == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var userDn = usrRes.Properties["distinguishedName"][0].ToString();
|
||||||
|
// Doppelteinträge vermeiden
|
||||||
|
if (!grpEntry.Properties["member"].Contains(userDn))
|
||||||
|
grpEntry.Properties["member"].Add(userDn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grpEntry.CommitChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wandelt eine SID (String-Form) in das für LDAP nötige Oktet-String-Format um.
|
||||||
|
/// </summary>
|
||||||
|
private string SidStringToLdapFilter(string sidString)
|
||||||
|
{
|
||||||
|
var sid = new SecurityIdentifier(sidString);
|
||||||
|
var bytes = new byte[sid.BinaryLength];
|
||||||
|
sid.GetBinaryForm(bytes, 0);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var b in bytes)
|
||||||
|
sb.AppendFormat("\\{0:X2}", b);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GetSid(string name)
|
||||||
|
{
|
||||||
|
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
|
||||||
|
using (var ds = new DirectorySearcher(root))
|
||||||
|
{
|
||||||
|
ds.Filter = $"(&(objectCategory=group)(sAMAccountName={name}))";
|
||||||
|
var r = ds.FindOne();
|
||||||
|
if (r == null) return null;
|
||||||
|
var de = r.GetDirectoryEntry();
|
||||||
|
var sidBytes = (byte[])de.Properties["objectSid"][0];
|
||||||
|
return new SecurityIdentifier(sidBytes, 0).Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string FormatName(cLiamNamingConvention conv, string serviceName, System.Collections.Generic.IDictionary<string, string> tags)
|
||||||
|
{
|
||||||
|
string tmpl = conv.NamingTemplate.Replace("{{NAME}}", serviceName);
|
||||||
|
foreach (var kv in tags)
|
||||||
|
tmpl = tmpl.Replace("{{" + kv.Key + "}}", kv.Value);
|
||||||
|
return tmpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stellt sicher, dass die Gruppe existiert – neu mit Scope & Type.
|
||||||
|
/// </summary>
|
||||||
|
private void EnsureGroup(
|
||||||
|
string groupName,
|
||||||
|
cLiamNamingConvention conv,
|
||||||
|
string description,
|
||||||
|
string managedByDn,
|
||||||
|
eLiamAccessRoleScopes groupScope,
|
||||||
|
ADGroupType groupType)
|
||||||
|
{
|
||||||
|
if (!GroupExists(groupName))
|
||||||
|
{
|
||||||
|
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
|
||||||
|
{
|
||||||
|
var grp = root.Children.Add("CN=" + groupName, "group");
|
||||||
|
grp.Properties["sAMAccountName"].Value = groupName;
|
||||||
|
grp.Properties["displayName"].Value = groupName;
|
||||||
|
// Hier: Security-Bit (0x80000000) nur, wenn Security, sonst 0
|
||||||
|
int typeBit = (groupType == ADGroupType.Security)
|
||||||
|
? unchecked((int)0x80000000)
|
||||||
|
: 0;
|
||||||
|
// Scope-Bit aus Param
|
||||||
|
grp.Properties["groupType"].Value = unchecked(typeBit | GetScopeBit(groupScope));
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(description))
|
||||||
|
grp.Properties["description"].Value = description;
|
||||||
|
if (managedByDn != null)
|
||||||
|
grp.Properties["managedBy"].Value = managedByDn;
|
||||||
|
grp.CommitChanges();
|
||||||
|
}
|
||||||
|
WaitReplication(groupName, TimeSpan.FromMinutes(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GroupExists(string name)
|
||||||
|
{
|
||||||
|
return _adBase.directoryEntry.Children.Cast<DirectoryEntry>()
|
||||||
|
.Any(c => string.Equals(
|
||||||
|
c.Properties["sAMAccountName"]?.Value?.ToString(), name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WaitReplication(string groupName, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
var sw = System.Diagnostics.Stopwatch.StartNew();
|
||||||
|
while (sw.Elapsed < timeout)
|
||||||
|
{
|
||||||
|
if (GroupExists(groupName))
|
||||||
|
return;
|
||||||
|
Thread.Sleep(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetDistinguishedName(string name)
|
||||||
|
{
|
||||||
|
using (var root = new DirectoryEntry(_ldapRoot, _user, _password, AuthenticationTypes.Secure))
|
||||||
|
using (var ds = new DirectorySearcher(root))
|
||||||
|
{
|
||||||
|
ds.Filter = "(&(objectClass=group)(sAMAccountName=" + name + "))";
|
||||||
|
var res = ds.FindOne();
|
||||||
|
return res?.Properties["distinguishedName"]?[0]?.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetScopeBit(eLiamAccessRoleScopes scope)
|
||||||
|
{
|
||||||
|
switch (scope)
|
||||||
|
{
|
||||||
|
case eLiamAccessRoleScopes.Universal:
|
||||||
|
return 0x8;
|
||||||
|
case eLiamAccessRoleScopes.Global:
|
||||||
|
return 0x2;
|
||||||
|
case eLiamAccessRoleScopes.DomainLocal:
|
||||||
|
return 0x4;
|
||||||
|
default:
|
||||||
|
return 0x8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
516
LIAMActiveDirectory/cActiveDirectoryBase.cs
Normal file
516
LIAMActiveDirectory/cActiveDirectoryBase.cs
Normal file
@@ -0,0 +1,516 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.DirectoryServices;
|
||||||
|
using System.DirectoryServices.AccountManagement;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.AccessControl;
|
||||||
|
using System.Security.Principal;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using C4IT.Logging;
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
|
||||||
|
namespace LiamAD
|
||||||
|
{
|
||||||
|
public class cActiveDirectoryBase
|
||||||
|
{
|
||||||
|
private cADLogonInfo privLogonInfo = null;
|
||||||
|
public PrincipalContext adContext = null;
|
||||||
|
public DirectoryEntry directoryEntry = null;
|
||||||
|
public Exception LastException { get; private set; } = null;
|
||||||
|
public string LastErrorMessage { get; private set; } = null;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void ResetError()
|
||||||
|
{
|
||||||
|
LastException = null;
|
||||||
|
LastErrorMessage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void SetErrorException(string Action, Exception E, LogLevels lev = LogLevels.Error)
|
||||||
|
{
|
||||||
|
LastException = E;
|
||||||
|
LastErrorMessage = Action + ": " + E.Message;
|
||||||
|
cLogManager.LogEntry(Action, lev);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> privLogonAsync(cADLogonInfo LogonInfo)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//TODO: remove dummy delay?
|
||||||
|
await Task.Delay(0);
|
||||||
|
ResetError();
|
||||||
|
adContext = new PrincipalContext(ContextType.Domain, LogonInfo.Domain, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
|
||||||
|
var ldapPath = $"LDAP://{LogonInfo.Domain}/{LogonInfo.TargetGroupPath}";
|
||||||
|
directoryEntry = new DirectoryEntry
|
||||||
|
{
|
||||||
|
Path = ldapPath,
|
||||||
|
Username = LogonInfo.User,
|
||||||
|
Password = new NetworkCredential(LogonInfo.User, LogonInfo.UserSecret).Password,
|
||||||
|
AuthenticationType = AuthenticationTypes.Secure | AuthenticationTypes.Sealing
|
||||||
|
};
|
||||||
|
return adContext != null;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
SetErrorException("exception error while ad login", E, LogLevels.Debug);
|
||||||
|
cLogManager.LogException(E, LogLevels.Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> privRelogon()
|
||||||
|
{
|
||||||
|
if (privLogonInfo == null)
|
||||||
|
return false;
|
||||||
|
var RetVal = await privLogonAsync(privLogonInfo);
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> LogonAsync(cADLogonInfo LogonInfo)
|
||||||
|
{
|
||||||
|
var RetVal = await privLogonAsync(LogonInfo);
|
||||||
|
if (RetVal == true)
|
||||||
|
privLogonInfo = LogonInfo;
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal AuthorizationRuleCollection GetAccessControlList(string path)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DirectoryInfo dADir = new DirectoryInfo(path);
|
||||||
|
var dAACL = dADir.GetAccessControl();
|
||||||
|
return dAACL.GetAccessRules(true, false, typeof(System.Security.Principal.SecurityIdentifier));
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string resolveSid(string sid)
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString();
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<cADCollectionBase> RequestSecurityGroupsListAsync(string groupFilter)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
|
||||||
|
var Result = privRequestSecurityGroupsListAsync(groupFilter);
|
||||||
|
if (Result != null)
|
||||||
|
{
|
||||||
|
var RetVal = new cADCollectionBase(Result.Count);
|
||||||
|
foreach (var Entry in Result)
|
||||||
|
{
|
||||||
|
var res = new cSecurityGroupResult(Entry);
|
||||||
|
RetVal.Add(res);
|
||||||
|
}
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<cSecurityGroupResult> privRequestSecurityGroupsListAsync(string groupFilter = null, string rawLDAPFilter = null)
|
||||||
|
{
|
||||||
|
ResetError();
|
||||||
|
List<cSecurityGroupResult> securityGroups = new List<cSecurityGroupResult>();
|
||||||
|
|
||||||
|
if (String.IsNullOrEmpty(privLogonInfo.TargetGroupPath) ||
|
||||||
|
(string.IsNullOrEmpty(groupFilter) && string.IsNullOrEmpty(rawLDAPFilter)))
|
||||||
|
{
|
||||||
|
return new List<cSecurityGroupResult>();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var ctx = adContext;
|
||||||
|
var entry = directoryEntry;
|
||||||
|
|
||||||
|
using (DirectorySearcher dSearch = new DirectorySearcher(entry))
|
||||||
|
{
|
||||||
|
dSearch.Filter = string.IsNullOrEmpty(rawLDAPFilter) ? "(&(" + groupFilter + ")(objectClass=group))" : rawLDAPFilter;
|
||||||
|
dSearch.PageSize = 100000;
|
||||||
|
|
||||||
|
SearchResultCollection sr = dSearch.FindAll();
|
||||||
|
if (sr.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (SearchResult k in sr)
|
||||||
|
{
|
||||||
|
var sid = new SecurityIdentifier(k.Properties["objectSid"][0] as byte[], 0).Value;
|
||||||
|
var dn = k.Properties["distinguishedname"][0].ToString();
|
||||||
|
|
||||||
|
// Initialisieren Sie die managedBy-SID als null
|
||||||
|
string managedBySid = null;
|
||||||
|
|
||||||
|
// Prüfen, ob das managedBy-Attribut existiert und nicht null ist
|
||||||
|
if (k.Properties.Contains("managedBy") && k.Properties["managedBy"].Count > 0)
|
||||||
|
{
|
||||||
|
// managedBy-DN erhalten
|
||||||
|
string managedByDn = k.Properties["managedBy"][0].ToString();
|
||||||
|
|
||||||
|
// Erstellen eines DirectoryEntry-Objekts für den managedBy-DN
|
||||||
|
using (DirectoryEntry managedByEntry = new DirectoryEntry($"LDAP://{managedByDn}"))
|
||||||
|
{
|
||||||
|
if (managedByEntry.Properties.Contains("objectSid") && managedByEntry.Properties["objectSid"].Count > 0)
|
||||||
|
{
|
||||||
|
// SID des managedBy-Objekts erhalten
|
||||||
|
managedBySid = new SecurityIdentifier(managedByEntry.Properties["objectSid"][0] as byte[], 0).Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Neues SecurityGroup-Objekt erstellen
|
||||||
|
cSecurityGroupResult group = new cSecurityGroupResult()
|
||||||
|
{
|
||||||
|
ID = sid,
|
||||||
|
Path = dn,
|
||||||
|
DisplayName = k.Properties["Name"][0].ToString(),
|
||||||
|
Description = k.Properties.Contains("Description") ? k.Properties["Description"][0].ToString() : string.Empty,
|
||||||
|
Scope = (GroupScope)GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, sid).GroupScope,
|
||||||
|
ManagedBySID = managedBySid
|
||||||
|
};
|
||||||
|
|
||||||
|
securityGroups.Add(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
cLogManager.LogException(e);
|
||||||
|
return new List<cSecurityGroupResult>(securityGroups);
|
||||||
|
}
|
||||||
|
|
||||||
|
return securityGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cADCollectionBase : SortedList<string, cADResultBase>
|
||||||
|
{
|
||||||
|
public cADCollectionBase() { }
|
||||||
|
public cADCollectionBase(int n) : base(n) { }
|
||||||
|
|
||||||
|
public void Add(cADResultBase adr)
|
||||||
|
{
|
||||||
|
if (!this.ContainsKey(adr.ID))
|
||||||
|
this.Add(adr.ID, adr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cSecurityGroupResult : cADResultBase
|
||||||
|
{
|
||||||
|
public cSecurityGroupResult() { }
|
||||||
|
public cSecurityGroupResult(cADResultBase b) : base(b)
|
||||||
|
{
|
||||||
|
this.ManagedBySID = (b as cSecurityGroupResult)?.ManagedBySID;
|
||||||
|
}
|
||||||
|
public GroupScope Scope { get; internal set; }
|
||||||
|
public string ManagedBySID { get; internal set; }
|
||||||
|
}
|
||||||
|
public class cADUserResult : cADResultBase
|
||||||
|
{
|
||||||
|
public string GivenName { get; internal set; }
|
||||||
|
public string SurName { get; internal set; }
|
||||||
|
public string UserPrincipalName { get; internal set; }
|
||||||
|
public string Email { get; internal set; }
|
||||||
|
public cADUserResult() { }
|
||||||
|
public cADUserResult(cADResultBase b) : base(b)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public cADUserResult(Principal Result) : base(Result)
|
||||||
|
{
|
||||||
|
UserPrincipalName = Result.UserPrincipalName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroupScope Scope { get; internal set; }
|
||||||
|
}
|
||||||
|
public class cADResultBase
|
||||||
|
{
|
||||||
|
public string ID { get; set; } = null;
|
||||||
|
public string DisplayName { get; set; } = null;
|
||||||
|
public string Path { get; set; } = null;
|
||||||
|
public DateTime CreatedDate { get; set; } = DateTime.MinValue;
|
||||||
|
public string Description { get; set; } = null;
|
||||||
|
|
||||||
|
public cADResultBase()
|
||||||
|
{ }
|
||||||
|
public cADResultBase(cADResultBase Result)
|
||||||
|
{
|
||||||
|
if (Result == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ID = Result.ID;
|
||||||
|
DisplayName = Result.DisplayName;
|
||||||
|
Description = Result.Description;
|
||||||
|
Path = Result.Path;
|
||||||
|
}
|
||||||
|
public cADResultBase(Principal Result)
|
||||||
|
{
|
||||||
|
if (Result == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ID = Result.Sid.ToString();
|
||||||
|
DisplayName = Result.DisplayName;
|
||||||
|
Path = Result.DistinguishedName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchrones Abrufen des managedBy-Attributs einer AD-Gruppe anhand ihrer SID.
|
||||||
|
/// Gibt den Distinguished Name (DN) des Managers zurück.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="groupSid">Die SID der AD-Gruppe.</param>
|
||||||
|
/// <returns>Der DN des Managers oder null, falls nicht gefunden.</returns>
|
||||||
|
public async Task<string> GetManagedByDnAsync(string dn)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Simuliert einen asynchronen Aufruf
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
using (var group = GroupPrincipal.FindByIdentity(adContext, IdentityType.DistinguishedName, dn))
|
||||||
|
{
|
||||||
|
if (group == null)
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"Gruppe mit dn {dn} nicht gefunden.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zugriff auf das underlying DirectoryEntry, um das managedBy-Attribut zu lesen
|
||||||
|
var directoryEntry = group.GetUnderlyingObject() as DirectoryEntry;
|
||||||
|
if (directoryEntry != null && directoryEntry.Properties.Contains("managedBy"))
|
||||||
|
{
|
||||||
|
var managedByValue = directoryEntry.Properties["managedBy"].Value as string;
|
||||||
|
if (!string.IsNullOrEmpty(managedByValue))
|
||||||
|
{
|
||||||
|
return managedByValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"managedBy-Attribut für Gruppe mit dn {dn} ist leer.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"Gruppe mit dn {dn} hat kein managedBy-Attribut.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
cLogManager.LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchrones Abrufen der Mitglieder des Managers einer AD-Gruppe anhand des groupSid.
|
||||||
|
/// Verwendet den DN des Managers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="groupSid">Die SID der AD-Gruppe.</param>
|
||||||
|
/// <returns>Eine cADCollectionBase mit den Mitgliedern oder null.</returns>
|
||||||
|
public async Task<cADCollectionBase> GetManagedByMembersAsync(string groupSid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var managedByDn = await GetManagedByDnAsync(groupSid);
|
||||||
|
if (!string.IsNullOrEmpty(managedByDn))
|
||||||
|
{
|
||||||
|
return await GetMembersByDnAsync(managedByDn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"Keine gültige managedBy DN für Gruppe mit SID {groupSid} gefunden.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
cLogManager.LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchrones Abrufen der Mitglieder einer AD-Gruppe anhand des Distinguished Name (DN).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dn">Der Distinguished Name der AD-Gruppe.</param>
|
||||||
|
/// <returns>Eine cADCollectionBase mit den Mitgliedern oder null.</returns>
|
||||||
|
public async Task<cADCollectionBase> GetMembersByDnAsync(string dn)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Simuliert einen asynchronen Aufruf
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
var result = privGetMembersByDnAsync(dn).ToList();
|
||||||
|
if (result != null && result.Any())
|
||||||
|
{
|
||||||
|
var retVal = new cADCollectionBase(result.Count);
|
||||||
|
foreach (var entry in result)
|
||||||
|
{
|
||||||
|
var res = new cADUserResult(entry);
|
||||||
|
if (!string.IsNullOrEmpty(res.Path))
|
||||||
|
retVal.Add(res);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"Keine Mitglieder für Gruppe mit DN {dn} gefunden.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
cLogManager.LogException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interne Methode zum Abrufen der Mitglieder einer AD-Gruppe anhand des Distinguished Name (DN).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dn">Der Distinguished Name der AD-Gruppe.</param>
|
||||||
|
/// <returns>Eine PrincipalSearchResult mit den Mitgliedern oder null.</returns>
|
||||||
|
private PrincipalSearchResult<Principal> privGetMembersByDnAsync(string dn)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var group = GroupPrincipal.FindByIdentity(adContext, IdentityType.DistinguishedName, dn))
|
||||||
|
{
|
||||||
|
if (group == null)
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"Gruppe mit DN {dn} nicht gefunden.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return group.GetMembers(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
cLogManager.LogException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchrones Abrufen der Mitglieder einer AD-Gruppe anhand ihrer SID.
|
||||||
|
/// Diese Methode bleibt unverändert und kann weiterhin verwendet werden.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sid">Die SID der AD-Gruppe.</param>
|
||||||
|
/// <returns>Eine cADCollectionBase mit den Mitgliedern oder null.</returns>
|
||||||
|
internal async Task<cADCollectionBase> GetMembersAsync(string sid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Simuliert einen asynchronen Aufruf
|
||||||
|
await Task.Yield();
|
||||||
|
|
||||||
|
var result = privGetMembersAsync(sid).ToList();
|
||||||
|
if (result != null && result.Any())
|
||||||
|
{
|
||||||
|
var retVal = new cADCollectionBase(result.Count);
|
||||||
|
foreach (var entry in result)
|
||||||
|
{
|
||||||
|
var res = new cADUserResult(entry);
|
||||||
|
if (!string.IsNullOrEmpty(res.Path))
|
||||||
|
retVal.Add(res);
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"Keine Mitglieder für Gruppe mit SID {sid} gefunden.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
cLogManager.LogException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interne Methode zum Abrufen der Mitglieder einer AD-Gruppe anhand ihrer SID.
|
||||||
|
/// Diese Methode bleibt unverändert und kann weiterhin verwendet werden.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sid">Die SID der AD-Gruppe.</param>
|
||||||
|
/// <returns>Eine PrincipalSearchResult mit den Mitgliedern oder null.</returns>
|
||||||
|
private PrincipalSearchResult<Principal> privGetMembersAsync(string sid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var group = GroupPrincipal.FindByIdentity(adContext, IdentityType.Sid, sid))
|
||||||
|
{
|
||||||
|
if (group == null)
|
||||||
|
{
|
||||||
|
cLogManager.LogEntry($"Gruppe mit SID {sid} nicht gefunden.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return group.GetMembers(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
cLogManager.LogException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// <autogenerated />
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// <autogenerated />
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,14 @@
|
|||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamActiveDirectory.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamActiveDirectory.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamBaseClasses.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamHelper.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\Newtonsoft.Json.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamBaseClasses.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\LiamHelper.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.csproj.AssemblyReference.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.csproj.CoreCompileInputs.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActi.8091FDFC.Up2Date
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Debug\LiamActiveDirectory.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\System.ValueTuple.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Debug\System.ValueTuple.xml
|
||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
88ca960765b758a5c4edcddedf6dc811f2a49d840cd7ade015d7644911a99c77
|
||||||
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/obj/Debug/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
|||||||
|
// <autogenerated />
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||||
Binary file not shown.
@@ -0,0 +1,14 @@
|
|||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LIAMActiveDirectory.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LIAMActiveDirectory.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamBaseClasses.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamHelper.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\Newtonsoft.Json.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamBaseClasses.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\LiamHelper.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.csproj.AssemblyReference.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.csproj.CoreCompileInputs.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LIAMActiveDirectory.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\obj\Release\LiamActi.8091FDFC.Up2Date
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\System.ValueTuple.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LIAMActiveDirectory\bin\Release\System.ValueTuple.xml
|
||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
ab9bb136583040c5ab0b8fc2b80edba3f154caa1532f30973b39973f0def47e6
|
||||||
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.dll
Normal file
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.dll
Normal file
Binary file not shown.
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.pdb
Normal file
BIN
LIAMActiveDirectory/obj/Release/LiamActiveDirectory.pdb
Normal file
Binary file not shown.
4
LIAMActiveDirectory/packages.config
Normal file
4
LIAMActiveDirectory/packages.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="System.ValueTuple" version="4.6.1" targetFramework="net462" />
|
||||||
|
</packages>
|
||||||
399
LiamBaseClasses/C4IT.LIAM.Base.cs
Normal file
399
LiamBaseClasses/C4IT.LIAM.Base.cs
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using C4IT.Logging;
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
|
||||||
|
|
||||||
|
namespace C4IT.LIAM
|
||||||
|
{
|
||||||
|
public enum eLiamAccessRoles
|
||||||
|
{
|
||||||
|
Owner = 1, Write = 2, Read = 3, Traverse = 4,
|
||||||
|
ADOwner = 110, // "AD Owner Group"
|
||||||
|
ADMember = 100, // "AD Member Group"
|
||||||
|
ExchangeMLMember = 200, // "Mailing List Member"
|
||||||
|
ExchangeMLOwner = 210, // "Mailing List Owner"
|
||||||
|
ExchangeSMBFullAccess = 250, // "Shared Mailbox Full Access"
|
||||||
|
ExchangeSMBSendAs = 260, // "Shared Mailbox Send as"
|
||||||
|
ExchangeSMBOwner = 270 // "Shared Mailbox Owner"
|
||||||
|
};
|
||||||
|
public enum eLiamAccessRoleScopes { Unknown = 0, Universal = 1, Global = 2, DomainLocal = 3 };
|
||||||
|
|
||||||
|
public enum eLiamProviderTypes { Unknown = 0, Ntfs = 1, Sharepoint = 2, Matrix42 = 3, MsTeams = 4, ActiveDirectory = 5, Exchange = 6 };
|
||||||
|
|
||||||
|
public enum eLiamDataAreaTypes
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
NtfsShare = 101,
|
||||||
|
NtfsFolder = 102,
|
||||||
|
MsTeamsTeam = 401,
|
||||||
|
MsTeamsChannel = 402,
|
||||||
|
MsTeamsFolder = 403,
|
||||||
|
ActiveDirectoryGroup = 501,
|
||||||
|
ExchangeSharedMailbox = 601,
|
||||||
|
ExchangeDistributionGroup = 602
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum eLiamGroupStrategies { None = 0, Ntfs_AGP = 0, Ntfs_AGDLP = 1 };
|
||||||
|
|
||||||
|
public class cLiamConfiguration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamProviderData : ICloneable
|
||||||
|
{
|
||||||
|
|
||||||
|
public eLiamProviderTypes ProviderType { get; set; } = eLiamProviderTypes.Unknown;
|
||||||
|
|
||||||
|
public string Domain { get; set; } = "";
|
||||||
|
|
||||||
|
public string RootPath { get; set; } = "";
|
||||||
|
|
||||||
|
public cLiamCredential Credential { get; set; } = null;
|
||||||
|
|
||||||
|
public int MaxDepth { get; set; } = 1;
|
||||||
|
|
||||||
|
public eLiamGroupStrategies GroupStrategy { get; set; } = eLiamGroupStrategies.None;
|
||||||
|
|
||||||
|
public string DataAreaFilter { get; set; } = "";
|
||||||
|
|
||||||
|
public string DataAreaRegEx { get; set; } = "";
|
||||||
|
|
||||||
|
public string GroupFilter { get; set; } = "";
|
||||||
|
|
||||||
|
public string GroupRegEx { get; set; } = "";
|
||||||
|
|
||||||
|
public string GroupPath { get; set; } = "";
|
||||||
|
|
||||||
|
public string OwnerGroupGlobal { get; set; } = "";
|
||||||
|
public string OwnerGroupLocal { get; set; } = "";
|
||||||
|
public string WriteGroupGlobal { get; set; } = "";
|
||||||
|
public string WriteGroupLocal { get; set; } = "";
|
||||||
|
public string ReadGroupGlobal { get; set; } = "";
|
||||||
|
public string ReadGroupLocal { get; set; } = "";
|
||||||
|
public string TraverseGroup { get; set; } = "";
|
||||||
|
|
||||||
|
public List<cLiamNamingConvention> NamingConventions { get; set; } = new List<cLiamNamingConvention>();
|
||||||
|
public Dictionary<string, string> CustomTags { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
public Dictionary<string, string> AdditionalConfiguration { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public static void Copy(cLiamProviderData From, cLiamProviderData To)
|
||||||
|
{
|
||||||
|
To.ProviderType = From.ProviderType;
|
||||||
|
To.Domain = From.Domain;
|
||||||
|
To.RootPath = From.RootPath;
|
||||||
|
To.Credential = From.Credential;
|
||||||
|
To.MaxDepth = From.MaxDepth;
|
||||||
|
To.GroupStrategy = From.GroupStrategy;
|
||||||
|
To.DataAreaFilter = From.DataAreaFilter;
|
||||||
|
To.DataAreaRegEx = From.DataAreaRegEx;
|
||||||
|
To.GroupFilter = From.GroupFilter;
|
||||||
|
To.GroupRegEx = From.GroupRegEx;
|
||||||
|
To.GroupPath = From.GroupPath;
|
||||||
|
To.CustomTags = From.CustomTags;
|
||||||
|
To.AdditionalConfiguration = From.AdditionalConfiguration;
|
||||||
|
To.CustomTags = From.CustomTags;
|
||||||
|
To.NamingConventions = From.NamingConventions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public cLiamProviderData()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public cLiamProviderData(cLiamProviderData PD)
|
||||||
|
{
|
||||||
|
Copy(PD, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
return new cLiamProviderData(this);
|
||||||
|
}
|
||||||
|
public void ReplaceCustomTags()
|
||||||
|
{
|
||||||
|
foreach (var customTag in this.CustomTags)
|
||||||
|
{
|
||||||
|
var Key = customTag.Key;
|
||||||
|
|
||||||
|
foreach (var namingConvention in NamingConventions)
|
||||||
|
{
|
||||||
|
if (customTag.Key == "Filesystem_GroupDomainLocalTag" && namingConvention.Scope == eLiamAccessRoleScopes.DomainLocal || customTag.Key == "Filesystem_GroupGlobalTag" && namingConvention.Scope == eLiamAccessRoleScopes.Global)
|
||||||
|
Key = "SCOPETAG";
|
||||||
|
else
|
||||||
|
Key = customTag.Key;
|
||||||
|
namingConvention.DescriptionTemplate = namingConvention.DescriptionTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
namingConvention.NamingTemplate = namingConvention.NamingTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
namingConvention.Wildcard = namingConvention.Wildcard.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
}
|
||||||
|
GroupFilter = GroupFilter.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class cLiamProviderBase : cLiamProviderData
|
||||||
|
{
|
||||||
|
public cLiamConfiguration LiamConfiguration { get; private set; }
|
||||||
|
|
||||||
|
public cLiamProviderBase(cLiamConfiguration Configuration, cLiamProviderData ProviderData) :
|
||||||
|
base(ProviderData)
|
||||||
|
{
|
||||||
|
LiamConfiguration = Configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<List<cLiamDataAreaBase>> getDataAreasAsync(int MaxDepth = -1);
|
||||||
|
|
||||||
|
public abstract Task<bool> LogonAsync();
|
||||||
|
public abstract string GetLastErrorMessage();
|
||||||
|
|
||||||
|
public abstract Task<cLiamDataAreaBase> LoadDataArea(string UID);
|
||||||
|
|
||||||
|
public static cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||||
|
{
|
||||||
|
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var MyPath = Assembly.GetExecutingAssembly()?.Location;
|
||||||
|
if (MyPath == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
MyPath = Path.GetDirectoryName(MyPath);
|
||||||
|
var DllPath = Path.Combine(MyPath, $"Liam{ProviderData.ProviderType}.dll");
|
||||||
|
if (!File.Exists(DllPath))
|
||||||
|
{
|
||||||
|
LogEntry($"Couldn not found Data Provider library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var assLocal = Assembly.LoadFrom(DllPath);
|
||||||
|
if (assLocal == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not load Data Provider library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var TP = assLocal.GetTypes();
|
||||||
|
var type = assLocal.GetType("C4IT.LIAM.LiamInitializer");
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not found class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var MI = type.GetMethod("CreateInstance");
|
||||||
|
if (MI == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not found method 'CreateInstance' in class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var objDll = MI.Invoke(null, new object[] { LiamConfiguration, ProviderData });
|
||||||
|
var RetVal = objDll as cLiamProviderBase;
|
||||||
|
ProviderData.ReplaceCustomTags();
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamCredential
|
||||||
|
{
|
||||||
|
public string Domain { get; set; } = "";
|
||||||
|
public string Identification { get; set; } = "";
|
||||||
|
public string Secret { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamNamingConvention
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public string NamingTemplate { get; set; } = "";
|
||||||
|
public string DescriptionTemplate { get; set; } = "";
|
||||||
|
public string Wildcard { get; set; } = "";
|
||||||
|
public eLiamAccessRoles AccessRole { get; set; } = eLiamAccessRoles.Read;
|
||||||
|
public eLiamAccessRoleScopes Scope { get; set; } = eLiamAccessRoleScopes.Unknown;
|
||||||
|
public eLiamProviderTypes? ProviderType { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamDataAreaInfo
|
||||||
|
{
|
||||||
|
public string DisplayName { get; protected set; } = null;
|
||||||
|
public string Description { get; protected set; } = null;
|
||||||
|
public string OwnerRef { get; set; } = null;
|
||||||
|
public string UID { get; protected set; } = null;
|
||||||
|
public string CreatedDate { get; protected set; } = null;
|
||||||
|
|
||||||
|
public string TechnicalName { get; protected set; } = "";
|
||||||
|
|
||||||
|
public int Level { get; set; } = -1;
|
||||||
|
|
||||||
|
public string ParentUID { get; protected set; } = null;
|
||||||
|
|
||||||
|
public eLiamDataAreaTypes DataType { get; protected set; } = eLiamDataAreaTypes.Unknown;
|
||||||
|
|
||||||
|
public bool SupportsPermissions { get; protected set; } = false;
|
||||||
|
|
||||||
|
public bool SupportsOwners { get; protected set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class cLiamDataAreaBase : cLiamDataAreaInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
public readonly cLiamProviderBase Provider = null;
|
||||||
|
|
||||||
|
public cLiamDataAreaBase(cLiamProviderBase Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1);
|
||||||
|
|
||||||
|
public static async Task<List<cLiamDataAreaBase>> getChildrenFromListAsync(List<cLiamDataAreaBase> Items, int Depth = -1)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
var RetVal = new List<cLiamDataAreaBase>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Items == null)
|
||||||
|
return RetVal;
|
||||||
|
|
||||||
|
if (Depth <= 0)
|
||||||
|
return RetVal;
|
||||||
|
|
||||||
|
foreach (var Entry in Items)
|
||||||
|
{
|
||||||
|
var Childs = await Entry.getChildrenAsync(Depth + 1);
|
||||||
|
if (Childs != null)
|
||||||
|
RetVal.AddRange(Childs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<List<cLiamPermissionInfo>> GetPermissionsAsync(bool force)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamUserInfo
|
||||||
|
{
|
||||||
|
public string DisplayName { get; set; } = null;
|
||||||
|
public string GivenName { get; set; } = null;
|
||||||
|
public string SurName { get; set; } = null;
|
||||||
|
public string UserPrincipalName { get; set; } = null;
|
||||||
|
public string EMail { get; set; } = null;
|
||||||
|
public string SID { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamPermissionResult
|
||||||
|
{
|
||||||
|
public bool Valid { get; set; } = false;
|
||||||
|
public string UserReference { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamPermissionInfo
|
||||||
|
{
|
||||||
|
public cLiamUserInfo User;
|
||||||
|
public eLiamAccessRoles AccessRole = eLiamAccessRoles.Read;
|
||||||
|
public bool OnlyEffective = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class DataAreaEntryBase
|
||||||
|
{
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
public string TechnicalName { get; set; }
|
||||||
|
public string UID { get; set; }
|
||||||
|
public string TargetType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SecurityGroupEntry : DataAreaEntryBase
|
||||||
|
{
|
||||||
|
public string Scope { get; set; }
|
||||||
|
}
|
||||||
|
public class DataAreaEntry : DataAreaEntryBase
|
||||||
|
{
|
||||||
|
public string Parent { get; set; }
|
||||||
|
public string ParentUID { get; set; }
|
||||||
|
public string Owner { get; set; }
|
||||||
|
public string Write { get; set; }
|
||||||
|
public string Read { get; set; }
|
||||||
|
public string Traverse { get; set; }
|
||||||
|
public string CreatedDate { get; set; }
|
||||||
|
public string Level { get; set; }
|
||||||
|
public string ConfigurationId { get; set; }
|
||||||
|
public string BaseFolder { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string UniqueId { get; set; }
|
||||||
|
public string DataAreaType { get; set; }
|
||||||
|
}
|
||||||
|
public class LiamApiVersionInfo
|
||||||
|
{
|
||||||
|
public string ProductName { get; set; } = "- unknown -";
|
||||||
|
public string ProductVersion { get; set; } = "";
|
||||||
|
public string AssemblyName { get; set; } = "- unknown -";
|
||||||
|
public string AssemblyVersion { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderCacheEntry
|
||||||
|
{
|
||||||
|
public Guid ID;
|
||||||
|
public Guid ObjectID;
|
||||||
|
public DateTime ValidUntil;
|
||||||
|
public cLiamProviderBase Provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LiamDataAreaEntry
|
||||||
|
{
|
||||||
|
public string DisplayName { get; set; } = "";
|
||||||
|
|
||||||
|
public string UID { get; set; } = "";
|
||||||
|
|
||||||
|
public bool SupportsPermissions { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
399
LiamBaseClasses/C4IT.LIAM.Base.cs.txt
Normal file
399
LiamBaseClasses/C4IT.LIAM.Base.cs.txt
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
using C4IT.Logging;
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
|
||||||
|
|
||||||
|
namespace C4IT.LIAM
|
||||||
|
{
|
||||||
|
public enum eLiamAccessRoles
|
||||||
|
{
|
||||||
|
Owner = 1, Write = 2, Read = 3, Traverse = 4,
|
||||||
|
ADOwner = 100, // "AD Owner Group"
|
||||||
|
ADMember = 110, // "AD Member Group"
|
||||||
|
ExchangeMLMember = 200, // "Mailing List Member"
|
||||||
|
ExchangeMLOwner = 210, // "Mailing List Owner"
|
||||||
|
ExchangeSMBFullAccess = 250, // "Shared Mailbox Full Access"
|
||||||
|
ExchangeSMBSendAs = 260, // "Shared Mailbox Send as"
|
||||||
|
ExchangeSMBOwner = 270 // "Shared Mailbox Owner"
|
||||||
|
};
|
||||||
|
public enum eLiamAccessRoleScopes { Unknown = 0, Universal = 1, Global = 2, DomainLocal = 3 };
|
||||||
|
|
||||||
|
public enum eLiamProviderTypes { Unknown = 0, Ntfs = 1, Sharepoint = 2, Matrix42 = 3, MsTeams = 4, ActiveDirectory = 5, Exchange = 6 };
|
||||||
|
|
||||||
|
public enum eLiamDataAreaTypes
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
NtfsShare = 101,
|
||||||
|
NtfsFolder = 102,
|
||||||
|
MsTeamsTeam = 401,
|
||||||
|
MsTeamsChannel = 402,
|
||||||
|
MsTeamsFolder = 403,
|
||||||
|
ActiveDirectoryGroup = 501,
|
||||||
|
ExchangeSharedMailbox = 601,
|
||||||
|
ExchangeDistributionGroup = 602
|
||||||
|
};
|
||||||
|
|
||||||
|
public enum eLiamGroupStrategies { None = 0, Ntfs_AGP = 0, Ntfs_AGDLP = 1 };
|
||||||
|
|
||||||
|
public class cLiamConfiguration
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamProviderData : ICloneable
|
||||||
|
{
|
||||||
|
|
||||||
|
public eLiamProviderTypes ProviderType { get; set; } = eLiamProviderTypes.Unknown;
|
||||||
|
|
||||||
|
public string Domain { get; set; } = "";
|
||||||
|
|
||||||
|
public string RootPath { get; set; } = "";
|
||||||
|
|
||||||
|
public cLiamCredential Credential { get; set; } = null;
|
||||||
|
|
||||||
|
public int MaxDepth { get; set; } = 1;
|
||||||
|
|
||||||
|
public eLiamGroupStrategies GroupStrategy { get; set; } = eLiamGroupStrategies.None;
|
||||||
|
|
||||||
|
public string DataAreaFilter { get; set; } = "";
|
||||||
|
|
||||||
|
public string DataAreaRegEx { get; set; } = "";
|
||||||
|
|
||||||
|
public string GroupFilter { get; set; } = "";
|
||||||
|
|
||||||
|
public string GroupRegEx { get; set; } = "";
|
||||||
|
|
||||||
|
public string GroupPath { get; set; } = "";
|
||||||
|
|
||||||
|
public string OwnerGroupGlobal { get; set; } = "";
|
||||||
|
public string OwnerGroupLocal { get; set; } = "";
|
||||||
|
public string WriteGroupGlobal { get; set; } = "";
|
||||||
|
public string WriteGroupLocal { get; set; } = "";
|
||||||
|
public string ReadGroupGlobal { get; set; } = "";
|
||||||
|
public string ReadGroupLocal { get; set; } = "";
|
||||||
|
public string TraverseGroup { get; set; } = "";
|
||||||
|
|
||||||
|
public List<cLiamNamingConvention> NamingConventions { get; set; } = new List<cLiamNamingConvention>();
|
||||||
|
public Dictionary<string, string> CustomTags { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
public Dictionary<string, string> AdditionalConfiguration { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public static void Copy(cLiamProviderData From, cLiamProviderData To)
|
||||||
|
{
|
||||||
|
To.ProviderType = From.ProviderType;
|
||||||
|
To.Domain = From.Domain;
|
||||||
|
To.RootPath = From.RootPath;
|
||||||
|
To.Credential = From.Credential;
|
||||||
|
To.MaxDepth = From.MaxDepth;
|
||||||
|
To.GroupStrategy = From.GroupStrategy;
|
||||||
|
To.DataAreaFilter = From.DataAreaFilter;
|
||||||
|
To.DataAreaRegEx = From.DataAreaRegEx;
|
||||||
|
To.GroupFilter = From.GroupFilter;
|
||||||
|
To.GroupRegEx = From.GroupRegEx;
|
||||||
|
To.GroupPath = From.GroupPath;
|
||||||
|
To.CustomTags = From.CustomTags;
|
||||||
|
To.AdditionalConfiguration = From.AdditionalConfiguration;
|
||||||
|
To.CustomTags = From.CustomTags;
|
||||||
|
To.NamingConventions = From.NamingConventions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public cLiamProviderData()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public cLiamProviderData(cLiamProviderData PD)
|
||||||
|
{
|
||||||
|
Copy(PD, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
return new cLiamProviderData(this);
|
||||||
|
}
|
||||||
|
public void ReplaceCustomTags()
|
||||||
|
{
|
||||||
|
foreach (var customTag in this.CustomTags)
|
||||||
|
{
|
||||||
|
var Key = customTag.Key;
|
||||||
|
|
||||||
|
foreach (var namingConvention in NamingConventions)
|
||||||
|
{
|
||||||
|
if (customTag.Key == "Filesystem_GroupDomainLocalTag" && namingConvention.Scope == eLiamAccessRoleScopes.DomainLocal || customTag.Key == "Filesystem_GroupGlobalTag" && namingConvention.Scope == eLiamAccessRoleScopes.Global)
|
||||||
|
Key = "SCOPETAG";
|
||||||
|
else
|
||||||
|
Key = customTag.Key;
|
||||||
|
namingConvention.DescriptionTemplate = namingConvention.DescriptionTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
namingConvention.NamingTemplate = namingConvention.NamingTemplate.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
namingConvention.Wildcard = namingConvention.Wildcard.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
}
|
||||||
|
GroupFilter = GroupFilter.Replace($"{{{{{Key}}}}}", customTag.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class cLiamProviderBase : cLiamProviderData
|
||||||
|
{
|
||||||
|
public cLiamConfiguration LiamConfiguration { get; private set; }
|
||||||
|
|
||||||
|
public cLiamProviderBase(cLiamConfiguration Configuration, cLiamProviderData ProviderData) :
|
||||||
|
base(ProviderData)
|
||||||
|
{
|
||||||
|
LiamConfiguration = Configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<List<cLiamDataAreaBase>> getDataAreasAsync(int MaxDepth = -1);
|
||||||
|
|
||||||
|
public abstract Task<bool> LogonAsync();
|
||||||
|
public abstract string GetLastErrorMessage();
|
||||||
|
|
||||||
|
public abstract Task<cLiamDataAreaBase> LoadDataArea(string UID);
|
||||||
|
|
||||||
|
public static cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||||
|
{
|
||||||
|
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var MyPath = Assembly.GetExecutingAssembly()?.Location;
|
||||||
|
if (MyPath == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
MyPath = Path.GetDirectoryName(MyPath);
|
||||||
|
var DllPath = Path.Combine(MyPath, $"Liam{ProviderData.ProviderType}.dll");
|
||||||
|
if (!File.Exists(DllPath))
|
||||||
|
{
|
||||||
|
LogEntry($"Couldn not found Data Provider library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var assLocal = Assembly.LoadFrom(DllPath);
|
||||||
|
if (assLocal == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not load Data Provider library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var TP = assLocal.GetTypes();
|
||||||
|
var type = assLocal.GetType("C4IT.LIAM.LiamInitializer");
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not found class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var MI = type.GetMethod("CreateInstance");
|
||||||
|
if (MI == null)
|
||||||
|
{
|
||||||
|
LogEntry($"Could not found method 'CreateInstance' in class 'C4IT.LIAM.LiamInitializer' in library '{DllPath}'", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
var objDll = MI.Invoke(null, new object[] { LiamConfiguration, ProviderData });
|
||||||
|
var RetVal = objDll as cLiamProviderBase;
|
||||||
|
ProviderData.ReplaceCustomTags();
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamCredential
|
||||||
|
{
|
||||||
|
public string Domain { get; set; } = "";
|
||||||
|
public string Identification { get; set; } = "";
|
||||||
|
public string Secret { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamNamingConvention
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public string NamingTemplate { get; set; } = "";
|
||||||
|
public string DescriptionTemplate { get; set; } = "";
|
||||||
|
public string Wildcard { get; set; } = "";
|
||||||
|
public eLiamAccessRoles AccessRole { get; set; } = eLiamAccessRoles.Read;
|
||||||
|
public eLiamAccessRoleScopes Scope { get; set; } = eLiamAccessRoleScopes.Unknown;
|
||||||
|
public eLiamProviderTypes? ProviderType { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamDataAreaInfo
|
||||||
|
{
|
||||||
|
public string DisplayName { get; protected set; } = null;
|
||||||
|
public string Description { get; protected set; } = null;
|
||||||
|
public string OwnerRef { get; set; } = null;
|
||||||
|
public string UID { get; protected set; } = null;
|
||||||
|
public string CreatedDate { get; protected set; } = null;
|
||||||
|
|
||||||
|
public string TechnicalName { get; protected set; } = "";
|
||||||
|
|
||||||
|
public int Level { get; set; } = -1;
|
||||||
|
|
||||||
|
public string ParentUID { get; protected set; } = null;
|
||||||
|
|
||||||
|
public eLiamDataAreaTypes DataType { get; protected set; } = eLiamDataAreaTypes.Unknown;
|
||||||
|
|
||||||
|
public bool SupportsPermissions { get; protected set; } = false;
|
||||||
|
|
||||||
|
public bool SupportsOwners { get; protected set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class cLiamDataAreaBase : cLiamDataAreaInfo
|
||||||
|
{
|
||||||
|
|
||||||
|
public readonly cLiamProviderBase Provider = null;
|
||||||
|
|
||||||
|
public cLiamDataAreaBase(cLiamProviderBase Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1);
|
||||||
|
|
||||||
|
public static async Task<List<cLiamDataAreaBase>> getChildrenFromListAsync(List<cLiamDataAreaBase> Items, int Depth = -1)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
var RetVal = new List<cLiamDataAreaBase>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Items == null)
|
||||||
|
return RetVal;
|
||||||
|
|
||||||
|
if (Depth <= 0)
|
||||||
|
return RetVal;
|
||||||
|
|
||||||
|
foreach (var Entry in Items)
|
||||||
|
{
|
||||||
|
var Childs = await Entry.getChildrenAsync(Depth + 1);
|
||||||
|
if (Childs != null)
|
||||||
|
RetVal.AddRange(Childs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
return RetVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<List<cLiamPermissionInfo>> GetPermissionsAsync(bool force)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamUserInfo
|
||||||
|
{
|
||||||
|
public string DisplayName { get; set; } = null;
|
||||||
|
public string GivenName { get; set; } = null;
|
||||||
|
public string SurName { get; set; } = null;
|
||||||
|
public string UserPrincipalName { get; set; } = null;
|
||||||
|
public string EMail { get; set; } = null;
|
||||||
|
public string SID { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamPermissionResult
|
||||||
|
{
|
||||||
|
public bool Valid { get; set; } = false;
|
||||||
|
public string UserReference { get; set; } = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamPermissionInfo
|
||||||
|
{
|
||||||
|
public cLiamUserInfo User;
|
||||||
|
public eLiamAccessRoles AccessRole = eLiamAccessRoles.Read;
|
||||||
|
public bool OnlyEffective = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class DataAreaEntryBase
|
||||||
|
{
|
||||||
|
public string DisplayName { get; set; }
|
||||||
|
public string TechnicalName { get; set; }
|
||||||
|
public string UID { get; set; }
|
||||||
|
public string TargetType { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SecurityGroupEntry : DataAreaEntryBase
|
||||||
|
{
|
||||||
|
public string Scope { get; set; }
|
||||||
|
}
|
||||||
|
public class DataAreaEntry : DataAreaEntryBase
|
||||||
|
{
|
||||||
|
public string Parent { get; set; }
|
||||||
|
public string ParentUID { get; set; }
|
||||||
|
public string Owner { get; set; }
|
||||||
|
public string Write { get; set; }
|
||||||
|
public string Read { get; set; }
|
||||||
|
public string Traverse { get; set; }
|
||||||
|
public string CreatedDate { get; set; }
|
||||||
|
public string Level { get; set; }
|
||||||
|
public string ConfigurationId { get; set; }
|
||||||
|
public string BaseFolder { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string UniqueId { get; set; }
|
||||||
|
public string DataAreaType { get; set; }
|
||||||
|
}
|
||||||
|
public class LiamApiVersionInfo
|
||||||
|
{
|
||||||
|
public string ProductName { get; set; } = "- unknown -";
|
||||||
|
public string ProductVersion { get; set; } = "";
|
||||||
|
public string AssemblyName { get; set; } = "- unknown -";
|
||||||
|
public string AssemblyVersion { get; set; } = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProviderCacheEntry
|
||||||
|
{
|
||||||
|
public Guid ID;
|
||||||
|
public Guid ObjectID;
|
||||||
|
public DateTime ValidUntil;
|
||||||
|
public cLiamProviderBase Provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LiamDataAreaEntry
|
||||||
|
{
|
||||||
|
public string DisplayName { get; set; } = "";
|
||||||
|
|
||||||
|
public string UID { get; set; } = "";
|
||||||
|
|
||||||
|
public bool SupportsPermissions { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
61
LiamBaseClasses/LiamBaseClasses.csproj
Normal file
61
LiamBaseClasses/LiamBaseClasses.csproj
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{3531C9E6-CF6E-458E-B604-4A5A8D1C7AB0}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>LiamBaseClasses</RootNamespace>
|
||||||
|
<AssemblyName>LiamBaseClasses</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>false</Deterministic>
|
||||||
|
<SccProjectName>SAK</SccProjectName>
|
||||||
|
<SccLocalPath>SAK</SccLocalPath>
|
||||||
|
<SccAuxPath>SAK</SccAuxPath>
|
||||||
|
<SccProvider>SAK</SccProvider>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||||
|
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="C4IT.LIAM.Base.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiamHelper\LiamHelper.csproj">
|
||||||
|
<Project>{6b0e73a6-f918-42d5-9525-d59d4d16283d}</Project>
|
||||||
|
<Name>LiamHelper</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
10
LiamBaseClasses/LiamBaseClasses.csproj.vspscc
Normal file
10
LiamBaseClasses/LiamBaseClasses.csproj.vspscc
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
""
|
||||||
|
{
|
||||||
|
"FILE_VERSION" = "9237"
|
||||||
|
"ENLISTMENT_CHOICE" = "NEVER"
|
||||||
|
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||||
|
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||||
|
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||||
|
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||||
|
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||||
|
}
|
||||||
11
LiamBaseClasses/Properties/AssemblyInfo.cs
Normal file
11
LiamBaseClasses/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("LIAM support library for basic classes & interfaces")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
[assembly: Guid("3531c9e6-cf6e-458e-b604-4a5a8d1c7ab0")]
|
||||||
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/LiamHelper.dll
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/LiamHelper.pdb
Normal file
BIN
LiamBaseClasses/bin/Debug/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Debug/Newtonsoft.Json.dll
Normal file
BIN
LiamBaseClasses/bin/Debug/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/bin/Release/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamHelper.dll
Normal file
BIN
LiamBaseClasses/bin/Release/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/LiamHelper.pdb
Normal file
BIN
LiamBaseClasses/bin/Release/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LiamBaseClasses/bin/Release/Newtonsoft.Json.dll
Normal file
BIN
LiamBaseClasses/bin/Release/Newtonsoft.Json.dll
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
|||||||
|
// <autogenerated />
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||||
Binary file not shown.
0
LiamBaseClasses/obj/Debug/LiamBase.24B0A51E.Up2Date
Normal file
0
LiamBaseClasses/obj/Debug/LiamBase.24B0A51E.Up2Date
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
3908855f9633bf09d020c2efbd1fa153a9ad8a91b6e76b39255ee0403b9907f8
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamBaseClasses.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamBaseClasses.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamHelper.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\Newtonsoft.Json.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Debug\LiamHelper.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.csproj.AssemblyReference.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.csproj.CoreCompileInputs.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBase.24B0A51E.Up2Date
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Debug\LiamBaseClasses.pdb
|
||||||
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/obj/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
|||||||
|
// <autogenerated />
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
77f86ea35cc63f1fe117fbff3ddf1a527617a8ddb75413eb5ef7f6b4cf6c8399
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamBaseClasses.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamBaseClasses.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamHelper.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\Newtonsoft.Json.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\bin\Release\LiamHelper.pdb
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.csproj.AssemblyReference.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.csproj.CoreCompileInputs.cache
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBase.24B0A51E.Up2Date
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.dll
|
||||||
|
C:\Workspace\C4IT DEV LIAM WEB Service\LiamBaseClasses\obj\Release\LiamBaseClasses.pdb
|
||||||
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.dll
Normal file
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.pdb
Normal file
BIN
LiamBaseClasses/obj/Release/LiamBaseClasses.pdb
Normal file
Binary file not shown.
898
LiamExchange/C4IT.LIAM.Exchange.cs
Normal file
898
LiamExchange/C4IT.LIAM.Exchange.cs
Normal file
@@ -0,0 +1,898 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Management.Automation.Runspaces;
|
||||||
|
using C4IT.Logging;
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
using C4IT.Matrix42.ServerInfo;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using LiamNtfs;
|
||||||
|
using System.DirectoryServices;
|
||||||
|
using System.Security.Principal;
|
||||||
|
|
||||||
|
namespace C4IT.LIAM
|
||||||
|
{
|
||||||
|
public class cLiamProviderExchange : cLiamProviderBase
|
||||||
|
{
|
||||||
|
public static Guid exchangeModuleId = new Guid("A1E213C3-6517-EA11-4881-000C2980FD95");
|
||||||
|
public readonly ExchangeManager exchangeManager;
|
||||||
|
internal readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||||||
|
|
||||||
|
private string exchangeUri;
|
||||||
|
private PSCredential credential;
|
||||||
|
private string organizationalUnit;
|
||||||
|
private string lastErrorMessage;
|
||||||
|
private bool isLoggedOn = false;
|
||||||
|
|
||||||
|
public cLiamProviderExchange(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) :
|
||||||
|
base(LiamConfiguration, ProviderData)
|
||||||
|
{
|
||||||
|
exchangeUri = ProviderData.RootPath;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(ProviderData.GroupPath))
|
||||||
|
organizationalUnit = ProviderData.GroupPath;
|
||||||
|
else
|
||||||
|
organizationalUnit = ProviderData.Domain;
|
||||||
|
|
||||||
|
// Credential erstellen
|
||||||
|
var securePassword = new SecureString();
|
||||||
|
foreach (char c in ProviderData.Credential.Secret)
|
||||||
|
{
|
||||||
|
securePassword.AppendChar(c);
|
||||||
|
}
|
||||||
|
credential = new PSCredential(ProviderData.Credential.Identification, securePassword);
|
||||||
|
// ExchangeManager initialisieren
|
||||||
|
exchangeManager = new ExchangeManager(this, exchangeUri, credential, ProviderData.Domain, organizationalUnit);
|
||||||
|
// AD-Zugriff initialisieren
|
||||||
|
var LI = new cNtfsLogonInfo()
|
||||||
|
{
|
||||||
|
Domain = Domain,
|
||||||
|
User = Credential?.Identification,
|
||||||
|
UserSecret = Credential?.Secret,
|
||||||
|
TargetGroupPath = this.GroupPath
|
||||||
|
};
|
||||||
|
|
||||||
|
// Asynchrone Initialisierung starten
|
||||||
|
_ = activeDirectoryBase.LogonAsync(LI).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extrahiert den GUID-Wert aus den Properties.
|
||||||
|
/// Zunächst wird versucht, "objectGUID" zu lesen – ist dieser leer, wird "GUID" verwendet.
|
||||||
|
/// </summary>
|
||||||
|
internal static string ExtractObjectGuid(dynamic properties)
|
||||||
|
{
|
||||||
|
// Erstversuch: objectGUID (wie in AD)
|
||||||
|
var value = properties["objectGUID"]?.Value;
|
||||||
|
if (value == null || string.IsNullOrEmpty(value.ToString()))
|
||||||
|
{
|
||||||
|
// Alternative: GUID (wie von den Exchange-Cmdlets zurückgegeben)
|
||||||
|
value = properties["GUID"]?.Value;
|
||||||
|
}
|
||||||
|
if (value is byte[] guidBytes)
|
||||||
|
return new Guid(guidBytes).ToString();
|
||||||
|
if (value is Guid guid)
|
||||||
|
return guid.ToString();
|
||||||
|
return value?.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> LogonAsync()
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||||||
|
{
|
||||||
|
LogEntry("Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||||
|
lastErrorMessage = "License not valid or Exchange module not licensed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var testMailboxes = exchangeManager.GetSharedMailboxes("Name -like '*'");
|
||||||
|
if (testMailboxes != null)
|
||||||
|
{
|
||||||
|
LogEntry("Successfully connected to Exchange", LogLevels.Info);
|
||||||
|
isLoggedOn = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Failed to connect to Exchange: {ex.Message}";
|
||||||
|
isLoggedOn = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastErrorMessage = "Unknown error connecting to Exchange";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
lastErrorMessage = $"Exception during Exchange logon: {E.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetLastErrorMessage()
|
||||||
|
{
|
||||||
|
return lastErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getDataAreasAsync(int MaxDepth = -1)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||||||
|
{
|
||||||
|
LogEntry("Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoggedOn && !await LogonAsync())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var DataAreas = new List<cLiamDataAreaBase>();
|
||||||
|
|
||||||
|
// Shared Mailboxes
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sharedMailboxes = exchangeManager.GetSharedMailboxes();
|
||||||
|
foreach (var mailbox in sharedMailboxes)
|
||||||
|
{
|
||||||
|
var displayName = mailbox.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = mailbox.Properties["Alias"]?.Value?.ToString();
|
||||||
|
var primarySmtpAddress = mailbox.Properties["PrimarySmtpAddress"]?.Value?.ToString();
|
||||||
|
var objectGuid = ExtractObjectGuid(mailbox.Properties);
|
||||||
|
|
||||||
|
// Filterung via Regex
|
||||||
|
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||||||
|
!Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exchangeMailbox = new cLiamExchangeSharedMailbox(this, displayName, primarySmtpAddress, alias, objectGuid);
|
||||||
|
DataAreas.Add(exchangeMailbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distribution Groups
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var distributionGroups = exchangeManager.GetDistributionGroups();
|
||||||
|
foreach (var group in distributionGroups)
|
||||||
|
{
|
||||||
|
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = group.Properties["Alias"]?.Value?.ToString();
|
||||||
|
var primarySmtpAddress = group.Properties["PrimarySmtpAddress"]?.Value?.ToString();
|
||||||
|
var objectGuid = ExtractObjectGuid(group.Properties);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||||||
|
!Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exchangeGroup = new cLiamExchangeDistributionGroup(this, displayName, primarySmtpAddress, alias, objectGuid);
|
||||||
|
DataAreas.Add(exchangeGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataAreas;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dataType = cLIAMHelper.getUidItem(ref UID);
|
||||||
|
if (string.IsNullOrEmpty(dataType))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!int.TryParse(dataType, out int dataTypeInt))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var primarySmtpAddress = cLIAMHelper.getUidItem(ref UID);
|
||||||
|
if (string.IsNullOrEmpty(primarySmtpAddress))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!isLoggedOn && !await LogonAsync())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch ((eLiamDataAreaTypes)dataTypeInt)
|
||||||
|
{
|
||||||
|
case eLiamDataAreaTypes.ExchangeSharedMailbox:
|
||||||
|
return await cLiamExchangeSharedMailbox.Load(this, primarySmtpAddress);
|
||||||
|
case eLiamDataAreaTypes.ExchangeDistributionGroup:
|
||||||
|
return await cLiamExchangeDistributionGroup.Load(this, primarySmtpAddress);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid)
|
||||||
|
{
|
||||||
|
LogEntry("Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoggedOn && !await LogonAsync())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var securityGroups = new List<cLiamDataAreaBase>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var groups = exchangeManager.GetSecurityGroups(groupFilter);
|
||||||
|
foreach (var group in groups)
|
||||||
|
{
|
||||||
|
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var sid = group.Properties["Sid"]?.Value?.ToString();
|
||||||
|
var dn = group.Properties["DistinguishedName"]?.Value?.ToString();
|
||||||
|
var objectGuid = ExtractObjectGuid(group.Properties);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(this.GroupRegEx) &&
|
||||||
|
!Regex.Match(displayName, this.GroupRegEx).Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var securityGroup = new cLiamExchangeSecurityGroup(this, displayName, sid, dn, objectGuid);
|
||||||
|
securityGroups.Add(securityGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
return securityGroups;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hilfsmethoden zur Interaktion mit Exchange
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
internal async Task<bool> AddMemberToGroup(string groupName, string member, bool isSharedMailbox)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isSharedMailbox)
|
||||||
|
exchangeManager.AddMailboxPermission(groupName, member);
|
||||||
|
else
|
||||||
|
exchangeManager.AddMemberToDistributionGroup(groupName, member);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Error adding member to group: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> RemoveMemberFromGroup(string groupName, string member, bool isSharedMailbox)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isSharedMailbox)
|
||||||
|
exchangeManager.RemoveMailboxPermission(groupName, member);
|
||||||
|
else
|
||||||
|
exchangeManager.RemoveMemberFromDistributionGroup(groupName, member);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Error removing member from group: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<cLiamExchangeSecurityGroup> GetManagedByGroup(string groupDn)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (activeDirectoryBase.adContext == null)
|
||||||
|
{
|
||||||
|
LogEntry("Active Directory context not initialized", LogLevels.Error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
string ldapPath = $"LDAP://{groupDn}";
|
||||||
|
DirectoryEntry groupEntry = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
groupEntry = new DirectoryEntry(
|
||||||
|
ldapPath,
|
||||||
|
this.Credential?.Identification,
|
||||||
|
this.Credential?.Secret,
|
||||||
|
AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
|
||||||
|
|
||||||
|
if (groupEntry.Properties.Contains("managedBy") && groupEntry.Properties["managedBy"].Value != null)
|
||||||
|
{
|
||||||
|
string managedByDn = groupEntry.Properties["managedBy"].Value.ToString();
|
||||||
|
string managedByLdapPath = $"LDAP://{managedByDn}";
|
||||||
|
using (DirectoryEntry managedByEntry = new DirectoryEntry(
|
||||||
|
managedByLdapPath,
|
||||||
|
this.Credential?.Identification,
|
||||||
|
this.Credential?.Secret,
|
||||||
|
AuthenticationTypes.Secure | AuthenticationTypes.Sealing))
|
||||||
|
{
|
||||||
|
if (managedByEntry.SchemaClassName == "group")
|
||||||
|
{
|
||||||
|
byte[] sidBytes = (byte[])managedByEntry.Properties["objectSid"].Value;
|
||||||
|
SecurityIdentifier sid = new SecurityIdentifier(sidBytes, 0);
|
||||||
|
string displayName = managedByEntry.Properties["displayName"]?.Value?.ToString()
|
||||||
|
?? managedByEntry.Properties["name"]?.Value?.ToString();
|
||||||
|
return new cLiamExchangeSecurityGroup(this, displayName, sid.Value, managedByDn, sid.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
groupEntry?.Dispose();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamExchangeSecurityGroup : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderExchange Provider = null;
|
||||||
|
public readonly string sid = null;
|
||||||
|
public readonly string dn = null;
|
||||||
|
|
||||||
|
// objectGuid wird nun als TechnicalName genutzt
|
||||||
|
public cLiamExchangeSecurityGroup(cLiamProviderExchange Provider, string displayName, string sid, string dn, string objectGuid) : base(Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.TechnicalName = displayName;
|
||||||
|
this.DisplayName = displayName;
|
||||||
|
this.UID = sid;
|
||||||
|
this.sid = sid;
|
||||||
|
this.dn = dn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
return Task.FromResult(new List<cLiamDataAreaBase>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamExchangeSharedMailbox : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderExchange Provider = null;
|
||||||
|
public readonly string PrimarySmtpAddress = null;
|
||||||
|
public readonly string Alias = null;
|
||||||
|
public string OwnerGroupIdentifier = "S-1-0-0";
|
||||||
|
public string FullAccessGroupSid = "S-1-0-0";
|
||||||
|
public string SendAsGroupSid = "S-1-0-0";
|
||||||
|
|
||||||
|
// objectGuid wird für TechnicalName genutzt
|
||||||
|
public cLiamExchangeSharedMailbox(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias, string objectGuid) : base(Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.TechnicalName = objectGuid;
|
||||||
|
this.DisplayName = displayName;
|
||||||
|
this.PrimarySmtpAddress = primarySmtpAddress;
|
||||||
|
this.Alias = alias;
|
||||||
|
this.UID = getUID(primarySmtpAddress);
|
||||||
|
this.Level = 0;
|
||||||
|
this.DataType = eLiamDataAreaTypes.ExchangeSharedMailbox;
|
||||||
|
this.SupportsOwners = true;
|
||||||
|
this.SupportsPermissions = true;
|
||||||
|
_ = assignPermissionGroups(Provider).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string getUID(string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
return $"{(int)eLiamDataAreaTypes.ExchangeSharedMailbox}|{primarySmtpAddress}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<cLiamExchangeSharedMailbox> Load(cLiamProviderExchange Provider, string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var mailbox = Provider.exchangeManager.GetSharedMailboxByAddress(primarySmtpAddress);
|
||||||
|
if (mailbox == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var displayName = mailbox.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = mailbox.Properties["Alias"]?.Value?.ToString();
|
||||||
|
var objectGuid = cLiamProviderExchange.ExtractObjectGuid(mailbox.Properties);
|
||||||
|
|
||||||
|
return new cLiamExchangeSharedMailbox(Provider, displayName, primarySmtpAddress, alias, objectGuid);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var members = Provider.exchangeManager.GetMailboxPermissionMembers(this.TechnicalName);
|
||||||
|
if (members == null)
|
||||||
|
return new List<cLiamUserInfo>();
|
||||||
|
|
||||||
|
var ownersList = new List<cLiamUserInfo>();
|
||||||
|
foreach (var member in members)
|
||||||
|
{
|
||||||
|
var userInfo = new cLiamUserInfo
|
||||||
|
{
|
||||||
|
DisplayName = member.Properties["DisplayName"]?.Value?.ToString(),
|
||||||
|
UserPrincipalName = member.Properties["UserPrincipalName"]?.Value?.ToString(),
|
||||||
|
EMail = member.Properties["PrimarySmtpAddress"]?.Value?.ToString(),
|
||||||
|
SID = member.Properties["Sid"]?.Value?.ToString()
|
||||||
|
};
|
||||||
|
ownersList.Add(userInfo);
|
||||||
|
}
|
||||||
|
return ownersList;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
switch (Role)
|
||||||
|
{
|
||||||
|
case eLiamAccessRoles.Owner:
|
||||||
|
success = await Provider.AddMemberToGroup(this.DisplayName, User.UserPrincipalName, true);
|
||||||
|
break;
|
||||||
|
case eLiamAccessRoles.Write:
|
||||||
|
success = await Provider.exchangeManager.AddSendAsPermission(this.DisplayName, User.UserPrincipalName);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogEntry($"Unsupported permission role for Exchange mailbox: {Role}", LogLevels.Warning);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
return new cLiamPermissionResult
|
||||||
|
{
|
||||||
|
Valid = success,
|
||||||
|
UserReference = User.UserPrincipalName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
switch (Role)
|
||||||
|
{
|
||||||
|
case eLiamAccessRoles.Owner:
|
||||||
|
success = await Provider.RemoveMemberFromGroup(this.DisplayName, User.UserPrincipalName, true);
|
||||||
|
break;
|
||||||
|
case eLiamAccessRoles.Write:
|
||||||
|
success = await Provider.exchangeManager.RemoveSendAsPermission(this.DisplayName, User.UserPrincipalName);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogEntry($"Unsupported permission role for Exchange mailbox: {Role}", LogLevels.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task assignPermissionGroups(cLiamProviderExchange Provider)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fullAccessNamingConvention = Provider.NamingConventions.FirstOrDefault(i =>
|
||||||
|
i.AccessRole == eLiamAccessRoles.ExchangeSMBFullAccess);
|
||||||
|
|
||||||
|
var sendAsNamingConvention = Provider.NamingConventions.FirstOrDefault(i =>
|
||||||
|
i.AccessRole == eLiamAccessRoles.ExchangeSMBSendAs);
|
||||||
|
|
||||||
|
if (fullAccessNamingConvention == null || sendAsNamingConvention == null)
|
||||||
|
{
|
||||||
|
LogEntry("Naming conventions for Exchange mailbox permissions not found", LogLevels.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fullAccessPermissions = Provider.exchangeManager.GetFullAccessPermissionGroups(this.TechnicalName);
|
||||||
|
if (fullAccessPermissions != null)
|
||||||
|
{
|
||||||
|
foreach (var permission in fullAccessPermissions)
|
||||||
|
{
|
||||||
|
string samAccountName = permission.Properties["SamAccountName"]?.Value?.ToString();
|
||||||
|
string sid = permission.Properties["Sid"]?.Value?.ToString();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(samAccountName) && !string.IsNullOrEmpty(sid))
|
||||||
|
{
|
||||||
|
//if (Regex.IsMatch(samAccountName, fullAccessNamingConvention.Wildcard, RegexOptions.IgnoreCase))
|
||||||
|
{
|
||||||
|
this.FullAccessGroupSid = sid;
|
||||||
|
LogEntry($"Found FullAccess group {samAccountName} (SID: {sid}) for mailbox {this.DisplayName}", LogLevels.Debug);
|
||||||
|
string dn = permission.Properties["DistinguishedName"]?.Value?.ToString();
|
||||||
|
if (!string.IsNullOrEmpty(dn))
|
||||||
|
{
|
||||||
|
var managedByGroup = await Provider.GetManagedByGroup(dn);
|
||||||
|
if (managedByGroup != null)
|
||||||
|
{
|
||||||
|
this.OwnerGroupIdentifier = managedByGroup.sid;
|
||||||
|
LogEntry($"Found owner group {managedByGroup.TechnicalName} (SID: {managedByGroup.sid}) for mailbox {this.DisplayName}", LogLevels.Debug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendAsPermissions = Provider.exchangeManager.GetSendAsPermissionGroups(this.TechnicalName);
|
||||||
|
if (sendAsPermissions != null)
|
||||||
|
{
|
||||||
|
foreach (var permission in sendAsPermissions)
|
||||||
|
{
|
||||||
|
string recipientType = permission.Properties["RecipientType"]?.Value?.ToString();
|
||||||
|
string samAccountName = permission.Properties["SamAccountName"]?.Value?.ToString();
|
||||||
|
string sid = permission.Properties["Sid"]?.Value?.ToString();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(samAccountName) && !string.IsNullOrEmpty(sid))
|
||||||
|
{
|
||||||
|
//if (Regex.IsMatch(samAccountName, sendAsNamingConvention.Wildcard, RegexOptions.IgnoreCase))
|
||||||
|
{
|
||||||
|
this.SendAsGroupSid = sid;
|
||||||
|
LogEntry($"Found SendAs group {samAccountName} (SID: {sid}) for mailbox {this.DisplayName}", LogLevels.Debug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamExchangeDistributionGroup : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderExchange Provider = null;
|
||||||
|
public readonly string PrimarySmtpAddress = null;
|
||||||
|
public readonly string Alias = null;
|
||||||
|
public string OwnerGroupIdentifier = "S-1-0-0";
|
||||||
|
public string MemberGroupSid = "S-1-0-0";
|
||||||
|
|
||||||
|
// objectGuid wird als TechnicalName gesetzt
|
||||||
|
public cLiamExchangeDistributionGroup(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias, string objectGuid) : base(Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.TechnicalName = objectGuid;
|
||||||
|
this.DisplayName = displayName;
|
||||||
|
this.PrimarySmtpAddress = primarySmtpAddress;
|
||||||
|
this.Alias = alias;
|
||||||
|
this.UID = getUID(primarySmtpAddress);
|
||||||
|
this.Level = 0;
|
||||||
|
this.DataType = eLiamDataAreaTypes.ExchangeDistributionGroup;
|
||||||
|
this.SupportsOwners = true;
|
||||||
|
this.SupportsPermissions = true;
|
||||||
|
_ = assignPermissionGroups(Provider).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string getUID(string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
return $"{(int)eLiamDataAreaTypes.ExchangeDistributionGroup}|{primarySmtpAddress}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<cLiamExchangeDistributionGroup> Load(cLiamProviderExchange Provider, string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var group = Provider.exchangeManager.GetDistributionGroupByAddress(primarySmtpAddress);
|
||||||
|
if (group == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = group.Properties["Alias"]?.Value?.ToString();
|
||||||
|
var objectGuid = cLiamProviderExchange.ExtractObjectGuid(group.Properties);
|
||||||
|
|
||||||
|
return new cLiamExchangeDistributionGroup(Provider, displayName, primarySmtpAddress, alias, objectGuid);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var members = Provider.exchangeManager.GetDistributionGroupMembers(this.TechnicalName);
|
||||||
|
if (members == null)
|
||||||
|
return new List<cLiamUserInfo>();
|
||||||
|
|
||||||
|
var membersList = new List<cLiamUserInfo>();
|
||||||
|
foreach (var member in members)
|
||||||
|
{
|
||||||
|
var userInfo = new cLiamUserInfo
|
||||||
|
{
|
||||||
|
DisplayName = member.Properties["DisplayName"]?.Value?.ToString(),
|
||||||
|
UserPrincipalName = member.Properties["UserPrincipalName"]?.Value?.ToString(),
|
||||||
|
EMail = member.Properties["PrimarySmtpAddress"]?.Value?.ToString(),
|
||||||
|
SID = member.Properties["Sid"]?.Value?.ToString()
|
||||||
|
};
|
||||||
|
membersList.Add(userInfo);
|
||||||
|
}
|
||||||
|
return membersList;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Role != eLiamAccessRoles.Owner)
|
||||||
|
{
|
||||||
|
LogEntry($"Only Owner role is supported for distribution groups, requested: {Role}", LogLevels.Warning);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = await Provider.AddMemberToGroup(this.DisplayName, User.UserPrincipalName, false);
|
||||||
|
return new cLiamPermissionResult
|
||||||
|
{
|
||||||
|
Valid = success,
|
||||||
|
UserReference = User.UserPrincipalName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Role != eLiamAccessRoles.Owner)
|
||||||
|
{
|
||||||
|
LogEntry($"Only Owner role is supported for distribution groups, requested: {Role}", LogLevels.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Provider.RemoveMemberFromGroup(this.DisplayName, User.UserPrincipalName, false);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task assignPermissionGroups(cLiamProviderExchange Provider)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var namingConvention = Provider.NamingConventions
|
||||||
|
.FirstOrDefault(nc => nc.AccessRole == eLiamAccessRoles.ExchangeMLMember);
|
||||||
|
if (namingConvention == null)
|
||||||
|
{
|
||||||
|
LogEntry("Naming convention for DL-Member not found", LogLevels.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// ruft alle Gruppen auf dem DL ab
|
||||||
|
var memberGroups = Provider.exchangeManager
|
||||||
|
.GetDistributionGroupMembers(this.TechnicalName);
|
||||||
|
|
||||||
|
foreach (var group in memberGroups)
|
||||||
|
{
|
||||||
|
var sam = group.Properties["SamAccountName"]?.Value?.ToString();
|
||||||
|
var sid = group.Properties["Sid"]?.Value?.ToString();
|
||||||
|
if (string.IsNullOrEmpty(sam) || string.IsNullOrEmpty(sid))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// falls gewünscht: Filter nach Namenskonvention
|
||||||
|
// if (!Regex.IsMatch(sam, namingConvention.Wildcard, RegexOptions.IgnoreCase))
|
||||||
|
// continue;
|
||||||
|
|
||||||
|
// hier beispielsweise in eine List<string> MemberGroupSids aufnehmen
|
||||||
|
this.MemberGroupSid = sid;
|
||||||
|
LogEntry($"Found DL-member group {sam} (SID: {sid}) for distribution list {this.DisplayName}", LogLevels.Debug);
|
||||||
|
|
||||||
|
// optional: falls die Gruppe ein ManagedBy hat
|
||||||
|
var dn = group.Properties["DistinguishedName"]?.Value?.ToString();
|
||||||
|
if (!string.IsNullOrEmpty(dn))
|
||||||
|
{
|
||||||
|
var mgr = await Provider.GetManagedByGroup(dn);
|
||||||
|
if (mgr != null)
|
||||||
|
{
|
||||||
|
this.OwnerGroupIdentifier = mgr.sid;
|
||||||
|
LogEntry($"Found owner group {mgr.TechnicalName} (SID: {mgr.sid}) for distribution list {this.DisplayName}", LogLevels.Debug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
726
LiamExchange/C4IT.LIAM.Exchange.cs.txt
Normal file
726
LiamExchange/C4IT.LIAM.Exchange.cs.txt
Normal file
@@ -0,0 +1,726 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Management.Automation.Runspaces;
|
||||||
|
|
||||||
|
using C4IT.Logging;
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
using C4IT.Matrix42.ServerInfo;
|
||||||
|
|
||||||
|
namespace C4IT.LIAM
|
||||||
|
{
|
||||||
|
public static class LiamInitializer
|
||||||
|
{
|
||||||
|
static public cLiamProviderBase CreateInstance(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData)
|
||||||
|
{
|
||||||
|
return new cLiamProviderExchange(LiamConfiguration, ProviderData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamProviderExchange : cLiamProviderBase
|
||||||
|
{
|
||||||
|
public static Guid exchangeModuleId = new Guid("A1E213C3-6517-EA11-4881-000C2980FD95");
|
||||||
|
internal readonly ExchangeManager exchangeManager;
|
||||||
|
private string exchangeUri;
|
||||||
|
private PSCredential credential;
|
||||||
|
private string organizationalUnit;
|
||||||
|
private string lastErrorMessage;
|
||||||
|
private bool isLoggedOn = false;
|
||||||
|
|
||||||
|
public cLiamProviderExchange(cLiamConfiguration LiamConfiguration, cLiamProviderData ProviderData) :
|
||||||
|
base(LiamConfiguration, ProviderData)
|
||||||
|
{
|
||||||
|
exchangeUri = ProviderData.RootPath;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(ProviderData.GroupPath))
|
||||||
|
organizationalUnit = ProviderData.GroupPath;
|
||||||
|
else
|
||||||
|
organizationalUnit = ProviderData.Domain;
|
||||||
|
|
||||||
|
// Use the credential from the provider data
|
||||||
|
var securePassword = new SecureString();
|
||||||
|
foreach (char c in ProviderData.Credential.Secret)
|
||||||
|
{
|
||||||
|
securePassword.AppendChar(c);
|
||||||
|
}
|
||||||
|
credential = new PSCredential(ProviderData.Credential.Identification, securePassword);
|
||||||
|
|
||||||
|
// Create the Exchange manager
|
||||||
|
exchangeManager = new ExchangeManager(exchangeUri, credential, organizationalUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> LogonAsync()
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid /*|| !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(exchangeModuleId)*/)
|
||||||
|
{
|
||||||
|
LogEntry($"Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||||
|
lastErrorMessage = "License not valid or Exchange module not licensed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test connection by getting a simple list
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var testMailboxes = exchangeManager.GetSharedMailboxes("Name -like '*'");
|
||||||
|
if (testMailboxes != null)
|
||||||
|
{
|
||||||
|
LogEntry($"Successfully connected to Exchange", LogLevels.Info);
|
||||||
|
isLoggedOn = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Failed to connect to Exchange: {ex.Message}";
|
||||||
|
isLoggedOn = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastErrorMessage = "Unknown error connecting to Exchange";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
lastErrorMessage = $"Exception during Exchange logon: {E.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetLastErrorMessage()
|
||||||
|
{
|
||||||
|
return lastErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getDataAreasAsync(int MaxDepth = -1)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid /*|| !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(exchangeModuleId)*/)
|
||||||
|
{
|
||||||
|
LogEntry($"Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoggedOn && !await LogonAsync())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var DataAreas = new List<cLiamDataAreaBase>();
|
||||||
|
|
||||||
|
// Get Shared Mailboxes
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sharedMailboxes = exchangeManager.GetSharedMailboxes();
|
||||||
|
foreach (var mailbox in sharedMailboxes)
|
||||||
|
{
|
||||||
|
var displayName = mailbox.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = mailbox.Properties["Alias"]?.Value?.ToString();
|
||||||
|
var primarySmtpAddress = mailbox.Properties["PrimarySmtpAddress"]?.Value?.ToString();
|
||||||
|
|
||||||
|
// Skip if it doesn't match the regex filter (if provided)
|
||||||
|
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||||||
|
!System.Text.RegularExpressions.Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exchangeMailbox = new cLiamExchangeSharedMailbox(this, displayName, primarySmtpAddress, alias);
|
||||||
|
DataAreas.Add(exchangeMailbox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Distribution Groups
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var distributionGroups = exchangeManager.GetDistributionGroups();
|
||||||
|
foreach (var group in distributionGroups)
|
||||||
|
{
|
||||||
|
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = group.Properties["Alias"]?.Value?.ToString();
|
||||||
|
var primarySmtpAddress = group.Properties["PrimarySmtpAddress"]?.Value?.ToString();
|
||||||
|
|
||||||
|
// Skip if it doesn't match the regex filter (if provided)
|
||||||
|
if (!string.IsNullOrEmpty(this.DataAreaRegEx) &&
|
||||||
|
!System.Text.RegularExpressions.Regex.Match(displayName, this.DataAreaRegEx).Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var exchangeGroup = new cLiamExchangeDistributionGroup(this, displayName, primarySmtpAddress, alias);
|
||||||
|
DataAreas.Add(exchangeGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DataAreas;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cLiamDataAreaBase> LoadDataArea(string UID)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var dataType = cLIAMHelper.getUidItem(ref UID);
|
||||||
|
if (string.IsNullOrEmpty(dataType))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
int dataTypeInt;
|
||||||
|
if (!int.TryParse(dataType, out dataTypeInt))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var primarySmtpAddress = cLIAMHelper.getUidItem(ref UID);
|
||||||
|
if (string.IsNullOrEmpty(primarySmtpAddress))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (!isLoggedOn && !await LogonAsync())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch ((eLiamDataAreaTypes)dataTypeInt)
|
||||||
|
{
|
||||||
|
case eLiamDataAreaTypes.ExchangeSharedMailbox:
|
||||||
|
return await cLiamExchangeSharedMailbox.Load(this, primarySmtpAddress);
|
||||||
|
case eLiamDataAreaTypes.ExchangeDistributionGroup:
|
||||||
|
return await cLiamExchangeDistributionGroup.Load(this, primarySmtpAddress);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getSecurityGroupsAsync(string groupFilter)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!cC4ITLicenseM42ESM.Instance.IsValid /*|| !cC4ITLicenseM42ESM.Instance.Modules.ContainsKey(exchangeModuleId)*/)
|
||||||
|
{
|
||||||
|
LogEntry($"Error: License not valid or Exchange module not licensed", LogLevels.Error);
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isLoggedOn && !await LogonAsync())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// For Exchange, we need to use the same AD security groups as from the AD provider
|
||||||
|
// This is just a placeholder implementation to return some groups from the exchange environment
|
||||||
|
var securityGroups = new List<cLiamDataAreaBase>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Use the Exchange PowerShell to get AD groups
|
||||||
|
var groups = exchangeManager.GetSecurityGroups(groupFilter);
|
||||||
|
foreach (var group in groups)
|
||||||
|
{
|
||||||
|
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var sid = group.Properties["Sid"]?.Value?.ToString();
|
||||||
|
var dn = group.Properties["DistinguishedName"]?.Value?.ToString();
|
||||||
|
|
||||||
|
// Skip if it doesn't match the regex filter (if provided)
|
||||||
|
if (!string.IsNullOrEmpty(this.GroupRegEx) &&
|
||||||
|
!System.Text.RegularExpressions.Regex.Match(displayName, this.GroupRegEx).Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var securityGroup = new cLiamExchangeSecurityGroup(this, displayName, sid, dn);
|
||||||
|
securityGroups.Add(securityGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return securityGroups;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods to interact with Exchange
|
||||||
|
internal async Task<bool> CreateSharedMailbox(string displayName, string alias, string ownerGroupName, string writeGroupName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
exchangeManager.CreateSharedMailbox(displayName, alias, null);
|
||||||
|
|
||||||
|
// Create the owner (FullAccess) and write (SendAs) groups if they don't exist already
|
||||||
|
exchangeManager.CreateSecurityGroup(ownerGroupName, $"{displayName} Full Access");
|
||||||
|
exchangeManager.CreateSecurityGroup(writeGroupName, $"{displayName} Send As");
|
||||||
|
|
||||||
|
// Grant permissions to the groups
|
||||||
|
exchangeManager.AddMailboxPermission(displayName, ownerGroupName, "FullAccess");
|
||||||
|
exchangeManager.AddSendAsPermission(displayName, writeGroupName);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Error creating shared mailbox: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> CreateDistributionGroup(string displayName, string alias, List<string> initialMembers = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
exchangeManager.CreateDistributionGroup(displayName, alias, initialMembers);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Error creating distribution group: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> AddMemberToGroup(string groupName, string member, bool isSharedMailbox)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isSharedMailbox)
|
||||||
|
{
|
||||||
|
exchangeManager.AddMailboxPermission(groupName, member);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exchangeManager.AddMemberToDistributionGroup(groupName, member);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Error adding member to group: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<bool> RemoveMemberFromGroup(string groupName, string member, bool isSharedMailbox)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isSharedMailbox)
|
||||||
|
{
|
||||||
|
exchangeManager.RemoveMailboxPermission(groupName, member);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
exchangeManager.RemoveMemberFromDistributionGroup(groupName, member);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
lastErrorMessage = $"Error removing member from group: {ex.Message}";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamExchangeSecurityGroup : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderExchange Provider = null;
|
||||||
|
public readonly string sid = null;
|
||||||
|
public readonly string dn = null;
|
||||||
|
|
||||||
|
public cLiamExchangeSecurityGroup(cLiamProviderExchange Provider, string displayName, string sid, string dn) : base(Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.TechnicalName = displayName;
|
||||||
|
this.UID = sid;
|
||||||
|
this.sid = sid;
|
||||||
|
this.dn = dn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
// Security groups don't have children in this context
|
||||||
|
return Task.FromResult(new List<cLiamDataAreaBase>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamExchangeSharedMailbox : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderExchange Provider = null;
|
||||||
|
public readonly string PrimarySmtpAddress = null;
|
||||||
|
public readonly string Alias = null;
|
||||||
|
public string OwnerGroupIdentifier = null; // Full Access group
|
||||||
|
public string WriteGroupIdentifier = null; // Send As group
|
||||||
|
|
||||||
|
public cLiamExchangeSharedMailbox(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias) : base(Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.TechnicalName = displayName;
|
||||||
|
this.DisplayName = displayName;
|
||||||
|
this.PrimarySmtpAddress = primarySmtpAddress;
|
||||||
|
this.Alias = alias;
|
||||||
|
this.UID = getUID(primarySmtpAddress);
|
||||||
|
this.Level = 0;
|
||||||
|
this.DataType = eLiamDataAreaTypes.ExchangeSharedMailbox;
|
||||||
|
this.SupportsOwners = true;
|
||||||
|
this.SupportsPermissions = true;
|
||||||
|
|
||||||
|
// Set standard naming convention for access groups
|
||||||
|
// These will be resolved to actual groups later as needed
|
||||||
|
this.OwnerGroupIdentifier = $"EXCH_FA_{alias}"; // Full Access group
|
||||||
|
this.WriteGroupIdentifier = $"EXCH_SA_{alias}"; // Send As group
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string getUID(string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
return $"{(int)eLiamDataAreaTypes.ExchangeSharedMailbox}|{primarySmtpAddress}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<cLiamExchangeSharedMailbox> Load(cLiamProviderExchange Provider, string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the mailbox details from Exchange
|
||||||
|
var mailbox = Provider.exchangeManager.GetSharedMailboxByAddress(primarySmtpAddress);
|
||||||
|
if (mailbox == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var displayName = mailbox.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = mailbox.Properties["Alias"]?.Value?.ToString();
|
||||||
|
|
||||||
|
return new cLiamExchangeSharedMailbox(Provider, displayName, primarySmtpAddress, alias);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get members of the Full Access group
|
||||||
|
var members = Provider.exchangeManager.GetMailboxPermissionMembers(this.DisplayName);
|
||||||
|
if (members == null)
|
||||||
|
return new List<cLiamUserInfo>();
|
||||||
|
|
||||||
|
var ownersList = new List<cLiamUserInfo>();
|
||||||
|
foreach (var member in members)
|
||||||
|
{
|
||||||
|
var userInfo = new cLiamUserInfo
|
||||||
|
{
|
||||||
|
DisplayName = member.Properties["DisplayName"]?.Value?.ToString(),
|
||||||
|
UserPrincipalName = member.Properties["UserPrincipalName"]?.Value?.ToString(),
|
||||||
|
EMail = member.Properties["PrimarySmtpAddress"]?.Value?.ToString(),
|
||||||
|
SID = member.Properties["Sid"]?.Value?.ToString()
|
||||||
|
};
|
||||||
|
ownersList.Add(userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ownersList;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
switch (Role)
|
||||||
|
{
|
||||||
|
case eLiamAccessRoles.Owner:
|
||||||
|
// Add to Full Access group
|
||||||
|
success = await Provider.AddMemberToGroup(this.DisplayName, User.UserPrincipalName, true);
|
||||||
|
break;
|
||||||
|
case eLiamAccessRoles.Write:
|
||||||
|
// Add Send As permission
|
||||||
|
success = await Provider.exchangeManager.AddSendAsPermission(this.DisplayName, User.UserPrincipalName);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogEntry($"Unsupported permission role for Exchange mailbox: {Role}", LogLevels.Warning);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
return new cLiamPermissionResult
|
||||||
|
{
|
||||||
|
Valid = success,
|
||||||
|
UserReference = User.UserPrincipalName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
switch (Role)
|
||||||
|
{
|
||||||
|
case eLiamAccessRoles.Owner:
|
||||||
|
// Remove from Full Access group
|
||||||
|
success = await Provider.RemoveMemberFromGroup(this.DisplayName, User.UserPrincipalName, true);
|
||||||
|
break;
|
||||||
|
case eLiamAccessRoles.Write:
|
||||||
|
// Remove Send As permission
|
||||||
|
success = await Provider.exchangeManager.RemoveSendAsPermission(this.DisplayName, User.UserPrincipalName);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogEntry($"Unsupported permission role for Exchange mailbox: {Role}", LogLevels.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
// Shared mailboxes don't have children in this context
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cLiamExchangeDistributionGroup : cLiamDataAreaBase
|
||||||
|
{
|
||||||
|
public new readonly cLiamProviderExchange Provider = null;
|
||||||
|
public readonly string PrimarySmtpAddress = null;
|
||||||
|
public readonly string Alias = null;
|
||||||
|
|
||||||
|
public cLiamExchangeDistributionGroup(cLiamProviderExchange Provider, string displayName, string primarySmtpAddress, string alias) : base(Provider)
|
||||||
|
{
|
||||||
|
this.Provider = Provider;
|
||||||
|
this.TechnicalName = displayName;
|
||||||
|
this.DisplayName = displayName;
|
||||||
|
this.PrimarySmtpAddress = primarySmtpAddress;
|
||||||
|
this.Alias = alias;
|
||||||
|
this.UID = getUID(primarySmtpAddress);
|
||||||
|
this.Level = 0;
|
||||||
|
this.DataType = eLiamDataAreaTypes.ExchangeDistributionGroup;
|
||||||
|
this.SupportsOwners = true;
|
||||||
|
this.SupportsPermissions = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string getUID(string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
return $"{(int)eLiamDataAreaTypes.ExchangeDistributionGroup}|{primarySmtpAddress}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<cLiamExchangeDistributionGroup> Load(cLiamProviderExchange Provider, string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get the group details from Exchange
|
||||||
|
var group = Provider.exchangeManager.GetDistributionGroupByAddress(primarySmtpAddress);
|
||||||
|
if (group == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var displayName = group.Properties["DisplayName"]?.Value?.ToString();
|
||||||
|
var alias = group.Properties["Alias"]?.Value?.ToString();
|
||||||
|
|
||||||
|
return new cLiamExchangeDistributionGroup(Provider, displayName, primarySmtpAddress, alias);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamUserInfo>> GetOwnersAsync()
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Get members of the distribution group
|
||||||
|
var members = Provider.exchangeManager.GetDistributionGroupMembers(this.DisplayName);
|
||||||
|
if (members == null)
|
||||||
|
return new List<cLiamUserInfo>();
|
||||||
|
|
||||||
|
var membersList = new List<cLiamUserInfo>();
|
||||||
|
foreach (var member in members)
|
||||||
|
{
|
||||||
|
var userInfo = new cLiamUserInfo
|
||||||
|
{
|
||||||
|
DisplayName = member.Properties["DisplayName"]?.Value?.ToString(),
|
||||||
|
UserPrincipalName = member.Properties["UserPrincipalName"]?.Value?.ToString(),
|
||||||
|
EMail = member.Properties["PrimarySmtpAddress"]?.Value?.ToString(),
|
||||||
|
SID = member.Properties["Sid"]?.Value?.ToString()
|
||||||
|
};
|
||||||
|
membersList.Add(userInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return membersList;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<cLiamPermissionResult> GrantPermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// For distribution groups, we only support adding members (which is essentially Owner role)
|
||||||
|
if (Role != eLiamAccessRoles.Owner)
|
||||||
|
{
|
||||||
|
LogEntry($"Only Owner role is supported for distribution groups, requested: {Role}", LogLevels.Warning);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = await Provider.AddMemberToGroup(this.DisplayName, User.UserPrincipalName, false);
|
||||||
|
|
||||||
|
return new cLiamPermissionResult
|
||||||
|
{
|
||||||
|
Valid = success,
|
||||||
|
UserReference = User.UserPrincipalName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return new cLiamPermissionResult { Valid = false };
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<bool> RevokePermissionAsync(cLiamUserInfo User, eLiamAccessRoles Role)
|
||||||
|
{
|
||||||
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(CM);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// For distribution groups, we only support removing members (which is essentially Owner role)
|
||||||
|
if (Role != eLiamAccessRoles.Owner)
|
||||||
|
{
|
||||||
|
LogEntry($"Only Owner role is supported for distribution groups, requested: {Role}", LogLevels.Warning);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Provider.RemoveMemberFromGroup(this.DisplayName, User.UserPrincipalName, false);
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(CM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<List<cLiamDataAreaBase>> getChildrenAsync(int Depth = -1)
|
||||||
|
{
|
||||||
|
// Distribution groups don't have children in this context
|
||||||
|
return new List<cLiamDataAreaBase>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1026
LiamExchange/C4IT.LIAM.ExchangeManager.cs
Normal file
1026
LiamExchange/C4IT.LIAM.ExchangeManager.cs
Normal file
File diff suppressed because it is too large
Load Diff
671
LiamExchange/C4IT.LIAM.ExchangeManager.cs.txt
Normal file
671
LiamExchange/C4IT.LIAM.ExchangeManager.cs.txt
Normal file
@@ -0,0 +1,671 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Management.Automation.Runspaces;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using C4IT.Logging;
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace C4IT.LIAM
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages Exchange operations using PowerShell remoting
|
||||||
|
/// </summary>
|
||||||
|
public class ExchangeManager
|
||||||
|
{
|
||||||
|
private readonly string _exchangeUri;
|
||||||
|
private readonly PSCredential _credential;
|
||||||
|
private readonly string _organizationalUnit;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor with explicit credentials, Exchange URI and OU path
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="exchangeUri">URL of the Exchange PowerShell endpoint (e.g. "http://exchangeserver/PowerShell")</param>
|
||||||
|
/// <param name="credential">Explicit credentials</param>
|
||||||
|
/// <param name="organizationalUnit">OU path where objects should be created</param>
|
||||||
|
public ExchangeManager(string exchangeUri, PSCredential credential, string organizationalUnit)
|
||||||
|
{
|
||||||
|
_exchangeUri = exchangeUri;
|
||||||
|
_credential = credential;
|
||||||
|
_organizationalUnit = organizationalUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a runspace connected to the Exchange PowerShell endpoint
|
||||||
|
/// </summary>
|
||||||
|
private Runspace CreateRunspace()
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var connectionInfo = new WSManConnectionInfo(
|
||||||
|
new Uri(_exchangeUri),
|
||||||
|
"http://schemas.microsoft.com/powershell/Microsoft.Exchange",
|
||||||
|
_credential);
|
||||||
|
|
||||||
|
// Set authentication mechanism to Kerberos by default
|
||||||
|
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
|
||||||
|
|
||||||
|
var runspace = RunspaceFactory.CreateRunspace(connectionInfo);
|
||||||
|
runspace.Open();
|
||||||
|
return runspace;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a distribution group (mailing list). Optionally members can be added initially.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Name of the group</param>
|
||||||
|
/// <param name="alias">Alias of the group</param>
|
||||||
|
/// <param name="initialMembers">List of members to be added to the group (optional)</param>
|
||||||
|
public void CreateDistributionGroup(string name, string alias, List<string> initialMembers = null)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
|
||||||
|
// Create the distribution group
|
||||||
|
ps.AddCommand("New-DistributionGroup")
|
||||||
|
.AddParameter("Name", name)
|
||||||
|
.AddParameter("Alias", alias)
|
||||||
|
.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||||
|
ps.Invoke();
|
||||||
|
|
||||||
|
// Add initial members if specified
|
||||||
|
if (initialMembers != null)
|
||||||
|
{
|
||||||
|
foreach (var member in initialMembers)
|
||||||
|
{
|
||||||
|
ps.Commands.Clear();
|
||||||
|
ps.AddCommand("Add-DistributionGroupMember")
|
||||||
|
.AddParameter("Identity", name)
|
||||||
|
.AddParameter("Member", member);
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a security group in Active Directory that can be used for Exchange permissions
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Name of the security group</param>
|
||||||
|
/// <param name="description">Description of the security group</param>
|
||||||
|
/// <returns>True if successful</returns>
|
||||||
|
public bool CreateSecurityGroup(string name, string description)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
|
||||||
|
// Create the security group using New-ADGroup cmdlet
|
||||||
|
ps.AddCommand("New-ADGroup")
|
||||||
|
.AddParameter("Name", name)
|
||||||
|
.AddParameter("GroupScope", "Universal")
|
||||||
|
.AddParameter("GroupCategory", "Security")
|
||||||
|
.AddParameter("DisplayName", name)
|
||||||
|
.AddParameter("Path", _organizationalUnit)
|
||||||
|
.AddParameter("Description", description);
|
||||||
|
|
||||||
|
var result = ps.Invoke();
|
||||||
|
return result.Count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all shared mailboxes matching an optional filter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">Optional filter string</param>
|
||||||
|
/// <returns>Collection of shared mailboxes as PSObjects</returns>
|
||||||
|
public IEnumerable<PSObject> GetSharedMailboxes(string filter = null)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Get-Mailbox")
|
||||||
|
.AddParameter("RecipientTypeDetails", "SharedMailbox");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(filter))
|
||||||
|
{
|
||||||
|
ps.AddParameter("Filter", filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return Enumerable.Empty<PSObject>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a shared mailbox by primary SMTP address
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="primarySmtpAddress">The primary SMTP address of the mailbox</param>
|
||||||
|
/// <returns>The mailbox as a PSObject, or null if not found</returns>
|
||||||
|
public PSObject GetSharedMailboxByAddress(string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Get-Mailbox")
|
||||||
|
.AddParameter("RecipientTypeDetails", "SharedMailbox")
|
||||||
|
.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||||
|
|
||||||
|
var results = ps.Invoke();
|
||||||
|
return results.Count > 0 ? results[0] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all distribution groups matching an optional filter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">Optional filter string</param>
|
||||||
|
/// <returns>Collection of distribution groups as PSObjects</returns>
|
||||||
|
public IEnumerable<PSObject> GetDistributionGroups(string filter = null)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Get-DistributionGroup");
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(filter))
|
||||||
|
{
|
||||||
|
ps.AddParameter("Filter", filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return Enumerable.Empty<PSObject>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a distribution group by primary SMTP address
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="primarySmtpAddress">The primary SMTP address of the group</param>
|
||||||
|
/// <returns>The distribution group as a PSObject, or null if not found</returns>
|
||||||
|
public PSObject GetDistributionGroupByAddress(string primarySmtpAddress)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Get-DistributionGroup")
|
||||||
|
.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||||
|
|
||||||
|
var results = ps.Invoke();
|
||||||
|
return results.Count > 0 ? results[0] : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets members of a distribution group
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="groupName">The name of the distribution group</param>
|
||||||
|
/// <returns>Collection of members as PSObjects</returns>
|
||||||
|
public IEnumerable<PSObject> GetDistributionGroupMembers(string groupName)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Get-DistributionGroupMember")
|
||||||
|
.AddParameter("Identity", groupName);
|
||||||
|
|
||||||
|
return ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return Enumerable.Empty<PSObject>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets users who have permissions on a mailbox
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mailboxName">The name of the mailbox</param>
|
||||||
|
/// <returns>Collection of users as PSObjects</returns>
|
||||||
|
public IEnumerable<PSObject> GetMailboxPermissionMembers(string mailboxName)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Get-MailboxPermission")
|
||||||
|
.AddParameter("Identity", mailboxName)
|
||||||
|
.AddParameter("AccessRights", "FullAccess");
|
||||||
|
|
||||||
|
// Filter out default permissions like NT AUTHORITY\SELF
|
||||||
|
var results = ps.Invoke().Where(p =>
|
||||||
|
!p.Properties["User"].Value.ToString().Contains("NT AUTHORITY") &&
|
||||||
|
!p.Properties["User"].Value.ToString().Contains("Administrator"));
|
||||||
|
|
||||||
|
// Now, get the full user objects for each permission
|
||||||
|
var userList = new List<PSObject>();
|
||||||
|
using (var ps2 = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps2.Runspace = runspace;
|
||||||
|
foreach (var perm in results)
|
||||||
|
{
|
||||||
|
ps2.Commands.Clear();
|
||||||
|
ps2.AddCommand("Get-User")
|
||||||
|
.AddParameter("Identity", perm.Properties["User"].Value.ToString());
|
||||||
|
|
||||||
|
var users = ps2.Invoke();
|
||||||
|
if (users.Count > 0)
|
||||||
|
{
|
||||||
|
userList.Add(users[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return userList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return Enumerable.Empty<PSObject>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets security groups matching a filter
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filter">LDAP filter to match groups</param>
|
||||||
|
/// <returns>Collection of security groups as PSObjects</returns>
|
||||||
|
public IEnumerable<PSObject> GetSecurityGroups(string filter)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Get-ADGroup")
|
||||||
|
.AddParameter("Filter", filter)
|
||||||
|
.AddParameter("Properties", new string[] { "DisplayName", "DistinguishedName", "Sid" });
|
||||||
|
|
||||||
|
return ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return Enumerable.Empty<PSObject>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a member to a distribution group
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="groupName">Name of the distribution group</param>
|
||||||
|
/// <param name="member">User to be added as a member</param>
|
||||||
|
public void AddMemberToDistributionGroup(string groupName, string member)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Add-DistributionGroupMember")
|
||||||
|
.AddParameter("Identity", groupName)
|
||||||
|
.AddParameter("Member", member);
|
||||||
|
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a member from a distribution group
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="groupName">Name of the distribution group</param>
|
||||||
|
/// <param name="member">User to be removed</param>
|
||||||
|
public void RemoveMemberFromDistributionGroup(string groupName, string member)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Remove-DistributionGroupMember")
|
||||||
|
.AddParameter("Identity", groupName)
|
||||||
|
.AddParameter("Member", member)
|
||||||
|
.AddParameter("Confirm", false);
|
||||||
|
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds mailbox permission for a user
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mailboxName">Name of the mailbox</param>
|
||||||
|
/// <param name="user">User or group to be granted permission</param>
|
||||||
|
/// <param name="accessRight">Access right (default: FullAccess)</param>
|
||||||
|
public void AddMailboxPermission(string mailboxName, string user, string accessRight = "FullAccess")
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Add-MailboxPermission")
|
||||||
|
.AddParameter("Identity", mailboxName)
|
||||||
|
.AddParameter("User", user)
|
||||||
|
.AddParameter("AccessRights", accessRight)
|
||||||
|
.AddParameter("InheritanceType", "All");
|
||||||
|
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes mailbox permission for a user
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mailboxName">Name of the mailbox</param>
|
||||||
|
/// <param name="user">User or group to have permission removed</param>
|
||||||
|
/// <param name="accessRight">Access right (default: FullAccess)</param>
|
||||||
|
public void RemoveMailboxPermission(string mailboxName, string user, string accessRight = "FullAccess")
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Remove-MailboxPermission")
|
||||||
|
.AddParameter("Identity", mailboxName)
|
||||||
|
.AddParameter("User", user)
|
||||||
|
.AddParameter("AccessRights", accessRight)
|
||||||
|
.AddParameter("InheritanceType", "All")
|
||||||
|
.AddParameter("Confirm", false);
|
||||||
|
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds Send As permission for a mailbox
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mailboxName">Name of the mailbox</param>
|
||||||
|
/// <param name="user">User or group to be granted permission</param>
|
||||||
|
/// <returns>True if successful</returns>
|
||||||
|
public async Task<bool> AddSendAsPermission(string mailboxName, string user)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Add-ADPermission")
|
||||||
|
.AddParameter("Identity", mailboxName)
|
||||||
|
.AddParameter("User", user)
|
||||||
|
.AddParameter("ExtendedRights", "Send-As")
|
||||||
|
.AddParameter("AccessRights", "ExtendedRight");
|
||||||
|
|
||||||
|
var results = ps.Invoke();
|
||||||
|
return results.Count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes Send As permission for a mailbox
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mailboxName">Name of the mailbox</param>
|
||||||
|
/// <param name="user">User or group to have permission removed</param>
|
||||||
|
/// <returns>True if successful</returns>
|
||||||
|
public async Task<bool> RemoveSendAsPermission(string mailboxName, string user)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Remove-ADPermission")
|
||||||
|
.AddParameter("Identity", mailboxName)
|
||||||
|
.AddParameter("User", user)
|
||||||
|
.AddParameter("ExtendedRights", "Send-As")
|
||||||
|
.AddParameter("AccessRights", "ExtendedRight")
|
||||||
|
.AddParameter("Confirm", false);
|
||||||
|
|
||||||
|
var results = ps.Invoke();
|
||||||
|
return results.Count > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a shared mailbox. Optionally initial permissions (e.g. FullAccess) can be set for members.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Name of the mailbox</param>
|
||||||
|
/// <param name="alias">Alias of the mailbox</param>
|
||||||
|
/// <param name="initialMembers">List of users to be added as access rights (optional)</param>
|
||||||
|
public void CreateSharedMailbox(string name, string alias, List<string> initialMembers = null)
|
||||||
|
{
|
||||||
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
|
||||||
|
// Create new shared mailbox
|
||||||
|
ps.AddCommand("New-Mailbox")
|
||||||
|
.AddParameter("Name", name)
|
||||||
|
.AddParameter("Alias", alias)
|
||||||
|
.AddParameter("Shared", true)
|
||||||
|
.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||||
|
ps.Invoke();
|
||||||
|
|
||||||
|
// Add initial members if specified
|
||||||
|
if (initialMembers != null)
|
||||||
|
{
|
||||||
|
foreach (var member in initialMembers)
|
||||||
|
{
|
||||||
|
ps.Commands.Clear();
|
||||||
|
ps.AddCommand("Add-MailboxPermission")
|
||||||
|
.AddParameter("Identity", name)
|
||||||
|
.AddParameter("User", member)
|
||||||
|
.AddParameter("AccessRights", "FullAccess")
|
||||||
|
.AddParameter("InheritanceType", "All");
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogException(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(MethodBase.GetCurrentMethod());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
380
LiamExchange/ExchangeManager.Extensions.cs
Normal file
380
LiamExchange/ExchangeManager.Extensions.cs
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Management.Automation;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security;
|
||||||
|
using System.DirectoryServices;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Management.Automation.Runspaces;
|
||||||
|
using System.Security.Principal;
|
||||||
|
|
||||||
|
namespace C4IT.LIAM
|
||||||
|
{
|
||||||
|
public partial class ExchangeManager
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Stellt sicher, dass eine AD-Sicherheitsgruppe für den angegebenen AccessRole existiert (erstellt sie falls nicht)
|
||||||
|
/// und wartet optional, bis die Replikation abgeschlossen ist.
|
||||||
|
/// Liefert den tatsächlichen Gruppennamen zurück.
|
||||||
|
/// </summary>
|
||||||
|
private string EnsureSecurityGroup(eLiamAccessRoles accessRole, string baseName)
|
||||||
|
{
|
||||||
|
const int MaxLoop = 50; // Abbruchbedingung: nach 50 Versuchen abbrechen
|
||||||
|
|
||||||
|
// 1. Namenskonvention für diese Rolle finden
|
||||||
|
var namingConvention = _provider.NamingConventions
|
||||||
|
.FirstOrDefault(nc => nc.AccessRole == accessRole);
|
||||||
|
if (namingConvention == null)
|
||||||
|
throw new InvalidOperationException($"Keine Namenskonvention für Rolle '{accessRole}' gefunden.");
|
||||||
|
|
||||||
|
// 2. Benötigte CustomTags aus dem Provider ziehen
|
||||||
|
// - Prefix (z.B. "ACL")
|
||||||
|
// - GROUPTYPEPOSTFIX (z.B. "ExchangeMLMember")
|
||||||
|
_provider.CustomTags.TryGetValue("ADGroupPrefix", out var prefix);
|
||||||
|
_provider.CustomTags.TryGetValue(accessRole.ToString(), out var typePostfix);
|
||||||
|
|
||||||
|
// 3. Schleife für _LOOP hochzählen, bis ein einzigartiger Name gefunden ist
|
||||||
|
string groupName = null;
|
||||||
|
string description = null;
|
||||||
|
|
||||||
|
for (int loop = 0; loop <= MaxLoop; loop++)
|
||||||
|
{
|
||||||
|
// nur einfügen, wenn loop > 0
|
||||||
|
var loopPart = loop > 0 ? $"_{loop}" : string.Empty;
|
||||||
|
|
||||||
|
// Platzhalter im Template ersetzen
|
||||||
|
groupName = namingConvention.NamingTemplate
|
||||||
|
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||||
|
.Replace("{{NAME}}", baseName)
|
||||||
|
.Replace("{{_LOOP}}", loopPart)
|
||||||
|
.Replace("{{GROUPTYPEPOSTFIX}}", typePostfix ?? string.Empty);
|
||||||
|
|
||||||
|
description = namingConvention.DescriptionTemplate
|
||||||
|
.Replace("{{ADGroupPrefix}}", prefix ?? string.Empty)
|
||||||
|
.Replace("{{NAME}}", baseName)
|
||||||
|
.Replace("{{_LOOP}}", loopPart)
|
||||||
|
.Replace("{{GROUPTYPEPOSTFIX}}", typePostfix ?? string.Empty);
|
||||||
|
|
||||||
|
// Existenz prüfen
|
||||||
|
bool exists = GetSecurityGroups(groupName)
|
||||||
|
.Any(g => string.Equals(
|
||||||
|
g.Properties["sAMAccountName"]?.Value?.ToString(),
|
||||||
|
groupName,
|
||||||
|
StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (!exists)
|
||||||
|
break; // Name ist frei – raus aus der Schleife
|
||||||
|
|
||||||
|
if (loop == MaxLoop)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Konnte nach {MaxLoop} Versuchen keinen eindeutigen Gruppennamen für '{baseName}' erzeugen.");
|
||||||
|
}
|
||||||
|
// 4. Gruppen-Scope-Bit setzen
|
||||||
|
int scopeBit;
|
||||||
|
switch (namingConvention.Scope)
|
||||||
|
{
|
||||||
|
case eLiamAccessRoleScopes.Global:
|
||||||
|
scopeBit = 0x2;
|
||||||
|
break;
|
||||||
|
case eLiamAccessRoleScopes.DomainLocal:
|
||||||
|
scopeBit = 0x4;
|
||||||
|
break;
|
||||||
|
case eLiamAccessRoleScopes.Universal:
|
||||||
|
scopeBit = 0x8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
scopeBit = 0x8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int groupType = unchecked((int)(0x80000000 | scopeBit));
|
||||||
|
|
||||||
|
// 5. Gruppe im AD anlegen
|
||||||
|
string ldapPath = $"LDAP://{_organizationalUnit}";
|
||||||
|
string password = new System.Net.NetworkCredential(string.Empty, _credential.Password).Password;
|
||||||
|
using (var root = new DirectoryEntry(
|
||||||
|
ldapPath,
|
||||||
|
_credential.UserName,
|
||||||
|
password,
|
||||||
|
AuthenticationTypes.Secure))
|
||||||
|
{
|
||||||
|
var newGroup = root.Children.Add($"CN={groupName}", "group");
|
||||||
|
newGroup.Properties["sAMAccountName"].Value = groupName;
|
||||||
|
newGroup.Properties["displayName"].Value = groupName;
|
||||||
|
newGroup.Properties["groupType"].Value = groupType;
|
||||||
|
if(!string.IsNullOrEmpty(description))
|
||||||
|
{
|
||||||
|
newGroup.Properties["description"].Value = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
newGroup.CommitChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Auf Replikation warten (optional)
|
||||||
|
const int replicationTimeoutMinutes = 2;
|
||||||
|
if (!WaitForGroupReplication(groupName, TimeSpan.FromMinutes(replicationTimeoutMinutes)))
|
||||||
|
{
|
||||||
|
throw new TimeoutException(
|
||||||
|
$"Die AD-Gruppe '{groupName}' konnte innerhalb von {replicationTimeoutMinutes} Minuten nicht repliziert werden.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return groupName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Wartet darauf, dass die Gruppe nach der Erstellung im AD repliziert ist.
|
||||||
|
/// </summary>
|
||||||
|
private bool WaitForGroupReplication(string groupName, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
var pollInterval = TimeSpan.FromSeconds(5);
|
||||||
|
|
||||||
|
while (sw.Elapsed < timeout)
|
||||||
|
{
|
||||||
|
var found = GetSecurityGroups(groupName)
|
||||||
|
.Any(g => string.Equals(
|
||||||
|
g.Properties["sAMAccountName"]?.Value?.ToString(),
|
||||||
|
groupName,
|
||||||
|
StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (found) return true;
|
||||||
|
Thread.Sleep(pollInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setzt das ManagedBy-Attribut einer AD-Gruppe auf eine andere Gruppe
|
||||||
|
/// – mit den im Konstruktor übergebenen Credentials und Domain.
|
||||||
|
/// </summary>
|
||||||
|
private void SetManagedBy(string groupName, string managerGroup)
|
||||||
|
{
|
||||||
|
string ldapPath = $"LDAP://{_organizationalUnit}";
|
||||||
|
|
||||||
|
// SecureString -> Klartext
|
||||||
|
string password = SecureStringToString(_credential.Password);
|
||||||
|
|
||||||
|
using (var root = new DirectoryEntry(ldapPath,
|
||||||
|
_credential.UserName,
|
||||||
|
password,
|
||||||
|
AuthenticationTypes.Secure))
|
||||||
|
using (var ds = new DirectorySearcher(root))
|
||||||
|
{
|
||||||
|
// Gruppe holen
|
||||||
|
ds.Filter = $"(&(objectClass=group)(sAMAccountName={groupName}))";
|
||||||
|
var result = ds.FindOne();
|
||||||
|
if (result == null)
|
||||||
|
throw new InvalidOperationException($"Gruppe '{groupName}' nicht gefunden in {ldapPath}");
|
||||||
|
|
||||||
|
var groupEntry = result.GetDirectoryEntry();
|
||||||
|
|
||||||
|
// DistinguishedName der Manager-Gruppe ermitteln
|
||||||
|
using (var mgrSearch = new DirectorySearcher(root))
|
||||||
|
{
|
||||||
|
mgrSearch.Filter = $"(&(objectClass=group)(sAMAccountName={managerGroup}))";
|
||||||
|
var mgrResult = mgrSearch.FindOne();
|
||||||
|
if (mgrResult == null)
|
||||||
|
throw new InvalidOperationException($"Manager-Gruppe '{managerGroup}' nicht gefunden in {ldapPath}");
|
||||||
|
|
||||||
|
string managerDn = mgrResult.GetDirectoryEntry()
|
||||||
|
.Properties["distinguishedName"]
|
||||||
|
.Value
|
||||||
|
.ToString();
|
||||||
|
|
||||||
|
// Attribut setzen und speichern
|
||||||
|
groupEntry.Properties["managedBy"].Value = managerDn;
|
||||||
|
groupEntry.CommitChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Erstellt eine Shared Mailbox samt zugehöriger AD-Gruppen (FullAccess, SendAs, Owner) und setzt die nötigen Berechtigungen.
|
||||||
|
/// </summary>
|
||||||
|
public Tuple<Guid, List<Tuple<string, string, string, string>>> CreateSharedMailboxWithOwnershipGroups(
|
||||||
|
string name,
|
||||||
|
string alias,
|
||||||
|
string displayName = null,
|
||||||
|
string primarySmtpAddress = null)
|
||||||
|
{
|
||||||
|
CreationResult result = new CreationResult();
|
||||||
|
|
||||||
|
// Ensure AD groups
|
||||||
|
string fullAccessGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeSMBFullAccess, name);
|
||||||
|
string sendAsGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeSMBSendAs, name);
|
||||||
|
string ownerGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeSMBOwner, name);
|
||||||
|
|
||||||
|
SetManagedBy(fullAccessGroup, ownerGroup);
|
||||||
|
SetManagedBy(sendAsGroup, ownerGroup);
|
||||||
|
|
||||||
|
// Create mailbox
|
||||||
|
using (Runspace rs = CreateRunspace())
|
||||||
|
{
|
||||||
|
using (PowerShell ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = rs;
|
||||||
|
ps.AddCommand("New-Mailbox");
|
||||||
|
ps.AddParameter("Name", name);
|
||||||
|
ps.AddParameter("Alias", alias);
|
||||||
|
ps.AddParameter("Shared", true);
|
||||||
|
ps.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||||
|
if (!string.IsNullOrEmpty(displayName))
|
||||||
|
ps.AddParameter("DisplayName", displayName);
|
||||||
|
if (!string.IsNullOrEmpty(primarySmtpAddress))
|
||||||
|
ps.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||||
|
ps.Invoke();
|
||||||
|
AddMailboxPermission(name, fullAccessGroup, "FullAccess");
|
||||||
|
AddSendAsPermission(name, sendAsGroup).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve mailbox GUID
|
||||||
|
DirectoryEntry mbEntry = FindAdObject("(&(objectClass=user)(mailNickname=" + alias + "))");
|
||||||
|
if (mbEntry != null && mbEntry.Properties.Contains("objectGUID") && mbEntry.Properties["objectGUID"].Count > 0)
|
||||||
|
{
|
||||||
|
byte[] bytes = (byte[])mbEntry.Properties["objectGUID"][0];
|
||||||
|
result.ObjectGuid = new Guid(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect group details
|
||||||
|
string[] roles = new string[] {
|
||||||
|
eLiamAccessRoles.ExchangeSMBFullAccess.ToString(),
|
||||||
|
eLiamAccessRoles.ExchangeSMBSendAs.ToString(),
|
||||||
|
eLiamAccessRoles.ExchangeSMBOwner.ToString()
|
||||||
|
};
|
||||||
|
string[] names = new string[] {
|
||||||
|
fullAccessGroup,
|
||||||
|
sendAsGroup,
|
||||||
|
ownerGroup
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < roles.Length; i++)
|
||||||
|
{
|
||||||
|
DirectoryEntry grpEntry = FindAdObject("(&(objectCategory=group)(sAMAccountName=" + names[i] + "))");
|
||||||
|
if (grpEntry != null && grpEntry.Properties.Contains("objectSid") && grpEntry.Properties["objectSid"].Count > 0)
|
||||||
|
{
|
||||||
|
byte[] sidBytes = (byte[])grpEntry.Properties["objectSid"][0];
|
||||||
|
string sid = new SecurityIdentifier(sidBytes, 0).Value;
|
||||||
|
string distinguishedName = grpEntry.Properties["distinguishedName"][0].ToString();
|
||||||
|
result.Groups.Add(Tuple.Create(roles[i], sid, names[i], distinguishedName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Tuple.Create(result.ObjectGuid, result.Groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Erstellt eine Distribution Group samt zugehöriger AD-Gruppen (Member, Owner) und setzt die nötigen Berechtigungen.
|
||||||
|
/// </summary>
|
||||||
|
public Tuple<Guid, List<Tuple<string, string, string, string>>> CreateDistributionGroupWithOwnershipGroups(
|
||||||
|
string name,
|
||||||
|
string alias,
|
||||||
|
string displayName = null,
|
||||||
|
string primarySmtpAddress = null)
|
||||||
|
{
|
||||||
|
CreationResult result = new CreationResult();
|
||||||
|
|
||||||
|
// Ensure AD groups
|
||||||
|
string memberGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeMLMember, name);
|
||||||
|
string ownerGroup = EnsureSecurityGroup(eLiamAccessRoles.ExchangeMLOwner, name);
|
||||||
|
|
||||||
|
SetManagedBy(memberGroup, ownerGroup);
|
||||||
|
|
||||||
|
// Create distribution group
|
||||||
|
using (Runspace rs = CreateRunspace())
|
||||||
|
{
|
||||||
|
using (PowerShell ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = rs;
|
||||||
|
ps.AddCommand("New-DistributionGroup");
|
||||||
|
ps.AddParameter("Name", name);
|
||||||
|
ps.AddParameter("Alias", alias);
|
||||||
|
ps.AddParameter("OrganizationalUnit", _organizationalUnit);
|
||||||
|
if (!string.IsNullOrEmpty(displayName))
|
||||||
|
ps.AddParameter("DisplayName", displayName);
|
||||||
|
if (!string.IsNullOrEmpty(primarySmtpAddress))
|
||||||
|
ps.AddParameter("PrimarySmtpAddress", primarySmtpAddress);
|
||||||
|
ps.Invoke();
|
||||||
|
|
||||||
|
// b) GUID holen
|
||||||
|
ps.Commands.Clear();
|
||||||
|
ps.AddCommand("Get-DistributionGroup")
|
||||||
|
.AddParameter("Identity", name);
|
||||||
|
var dg = ps.Invoke().FirstOrDefault();
|
||||||
|
if (dg != null && dg.Properties["Guid"] != null)
|
||||||
|
{
|
||||||
|
var guidVal = dg.Properties["Guid"].Value;
|
||||||
|
if (guidVal is Guid g) result.ObjectGuid = g;
|
||||||
|
else if (guidVal is string s && Guid.TryParse(s, out Guid parsed)) result.ObjectGuid = parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddMemberToDistributionGroup(name, memberGroup);
|
||||||
|
SetDistributionGroupManagedBy(name, ownerGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Collect group details
|
||||||
|
string[] dRoles = new string[] {
|
||||||
|
eLiamAccessRoles.ExchangeMLMember.ToString(),
|
||||||
|
eLiamAccessRoles.ExchangeMLOwner.ToString()
|
||||||
|
};
|
||||||
|
string[] dNames = new string[] {
|
||||||
|
memberGroup,
|
||||||
|
ownerGroup
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < dRoles.Length; i++)
|
||||||
|
{
|
||||||
|
DirectoryEntry grpEntry = FindAdObject("(&(objectCategory=group)(sAMAccountName=" + dNames[i] + "))");
|
||||||
|
if (grpEntry != null && grpEntry.Properties.Contains("objectSid") && grpEntry.Properties["objectSid"].Count > 0)
|
||||||
|
{
|
||||||
|
byte[] sidBytes = (byte[])grpEntry.Properties["objectSid"][0];
|
||||||
|
string sid = new SecurityIdentifier(sidBytes, 0).Value;
|
||||||
|
string distinguishedName = grpEntry.Properties["distinguishedName"][0].ToString();
|
||||||
|
result.Groups.Add(Tuple.Create(dRoles[i], sid, dNames[i], distinguishedName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Tuple.Create(result.ObjectGuid, result.Groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setzt das ManagedBy-Attribut einer Distribution Group.
|
||||||
|
/// </summary>
|
||||||
|
private void SetDistributionGroupManagedBy(string groupName, string managerGroup)
|
||||||
|
{
|
||||||
|
using (var runspace = CreateRunspace())
|
||||||
|
using (var ps = PowerShell.Create())
|
||||||
|
{
|
||||||
|
ps.Runspace = runspace;
|
||||||
|
ps.AddCommand("Set-DistributionGroup")
|
||||||
|
.AddParameter("Identity", groupName)
|
||||||
|
.AddParameter("ManagedBy", managerGroup)
|
||||||
|
.AddParameter("ErrorAction", "SilentlyContinue");
|
||||||
|
ps.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hilfsmethode: SecureString in Klartext wandeln.
|
||||||
|
/// </summary>
|
||||||
|
private static string SecureStringToString(SecureString ss)
|
||||||
|
{
|
||||||
|
if (ss == null) return string.Empty;
|
||||||
|
IntPtr ptr = Marshal.SecureStringToBSTR(ss);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Marshal.PtrToStringBSTR(ptr) ?? string.Empty;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.ZeroFreeBSTR(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
102
LiamExchange/LiamExchange.csproj
Normal file
102
LiamExchange/LiamExchange.csproj
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{12586A29-BB1E-49B4-B971-88E520D6A77C}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>LiamExchange</RootNamespace>
|
||||||
|
<AssemblyName>LiamExchange</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
<SccProjectName>SAK</SccProjectName>
|
||||||
|
<SccLocalPath>SAK</SccLocalPath>
|
||||||
|
<SccAuxPath>SAK</SccAuxPath>
|
||||||
|
<SccProvider>SAK</SccProvider>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Microsoft.Bcl.Cryptography, Version=9.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.Bcl.Cryptography.9.0.4\lib\net462\Microsoft.Bcl.Cryptography.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.DirectoryServices" />
|
||||||
|
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||||
|
<Reference Include="System.Formats.Asn1, Version=9.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Formats.Asn1.9.0.4\lib\net462\System.Formats.Asn1.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Microsoft.PowerShell.5.ReferenceAssemblies.1.1.0\lib\net4\System.Management.Automation.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="C4IT.LIAM.Exchange.cs" />
|
||||||
|
<Compile Include="ExchangeManager.Extensions.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LiamBaseClasses\LiamBaseClasses.csproj">
|
||||||
|
<Project>{3531c9e6-cf6e-458e-b604-4a5a8d1c7ab0}</Project>
|
||||||
|
<Name>LiamBaseClasses</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\LiamHelper\LiamHelper.csproj">
|
||||||
|
<Project>{6b0e73a6-f918-42d5-9525-d59d4d16283d}</Project>
|
||||||
|
<Name>LiamHelper</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\LiamNtfs\LiamNtfs.csproj">
|
||||||
|
<Project>{7F3085F7-1B7A-4DB2-B66F-1B69CCB0002F}</Project>
|
||||||
|
<Name>LiamNtfs</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="C4IT.LIAM.ExchangeManager.cs" />
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
10
LiamExchange/LiamExchange.csproj.vspscc
Normal file
10
LiamExchange/LiamExchange.csproj.vspscc
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
""
|
||||||
|
{
|
||||||
|
"FILE_VERSION" = "9237"
|
||||||
|
"ENLISTMENT_CHOICE" = "NEVER"
|
||||||
|
"PROJECT_FILE_RELATIVE_PATH" = ""
|
||||||
|
"NUMBER_OF_EXCLUDED_FILES" = "0"
|
||||||
|
"ORIGINAL_PROJECT_FILE_PATH" = ""
|
||||||
|
"NUMBER_OF_NESTED_PROJECTS" = "0"
|
||||||
|
"SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
|
||||||
|
}
|
||||||
33
LiamExchange/Properties/AssemblyInfo.cs
Normal file
33
LiamExchange/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("LiamExchange")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("LiamExchange")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2025")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("12586a29-bb1e-49b4-b971-88e520d6a77c")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
11
LiamExchange/app.config
Normal file
11
LiamExchange/app.config
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
||||||
BIN
LiamExchange/bin/Debug/LiamBaseClasses.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamBaseClasses.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamBaseClasses.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamBaseClasses.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamExchange.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamExchange.dll
Normal file
Binary file not shown.
11
LiamExchange/bin/Debug/LiamExchange.dll.config
Normal file
11
LiamExchange/bin/Debug/LiamExchange.dll.config
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
||||||
BIN
LiamExchange/bin/Debug/LiamExchange.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamExchange.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamHelper.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamHelper.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamHelper.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamHelper.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamNtfs.dll
Normal file
BIN
LiamExchange/bin/Debug/LiamNtfs.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/LiamNtfs.pdb
Normal file
BIN
LiamExchange/bin/Debug/LiamNtfs.pdb
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.dll
Normal file
BIN
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.dll
Normal file
Binary file not shown.
1576
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.xml
Normal file
1576
LiamExchange/bin/Debug/Microsoft.Bcl.Cryptography.xml
Normal file
File diff suppressed because it is too large
Load Diff
BIN
LiamExchange/bin/Debug/Microsoft.Management.Infrastructure.dll
Normal file
BIN
LiamExchange/bin/Debug/Microsoft.Management.Infrastructure.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/Newtonsoft.Json.dll
Normal file
BIN
LiamExchange/bin/Debug/Newtonsoft.Json.dll
Normal file
Binary file not shown.
BIN
LiamExchange/bin/Debug/System.Buffers.dll
Normal file
BIN
LiamExchange/bin/Debug/System.Buffers.dll
Normal file
Binary file not shown.
38
LiamExchange/bin/Debug/System.Buffers.xml
Normal file
38
LiamExchange/bin/Debug/System.Buffers.xml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><doc>
|
||||||
|
<assembly>
|
||||||
|
<name>System.Buffers</name>
|
||||||
|
</assembly>
|
||||||
|
<members>
|
||||||
|
<member name="T:System.Buffers.ArrayPool`1">
|
||||||
|
<summary>Provides a resource pool that enables reusing instances of type <see cref="T[]"></see>.</summary>
|
||||||
|
<typeparam name="T">The type of the objects that are in the resource pool.</typeparam>
|
||||||
|
</member>
|
||||||
|
<member name="M:System.Buffers.ArrayPool`1.#ctor">
|
||||||
|
<summary>Initializes a new instance of the <see cref="T:System.Buffers.ArrayPool`1"></see> class.</summary>
|
||||||
|
</member>
|
||||||
|
<member name="M:System.Buffers.ArrayPool`1.Create">
|
||||||
|
<summary>Creates a new instance of the <see cref="T:System.Buffers.ArrayPool`1"></see> class.</summary>
|
||||||
|
<returns>A new instance of the <see cref="System.Buffers.ArrayPool`1"></see> class.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:System.Buffers.ArrayPool`1.Create(System.Int32,System.Int32)">
|
||||||
|
<summary>Creates a new instance of the <see cref="T:System.Buffers.ArrayPool`1"></see> class using the specifed configuration.</summary>
|
||||||
|
<param name="maxArrayLength">The maximum length of an array instance that may be stored in the pool.</param>
|
||||||
|
<param name="maxArraysPerBucket">The maximum number of array instances that may be stored in each bucket in the pool. The pool groups arrays of similar lengths into buckets for faster access.</param>
|
||||||
|
<returns>A new instance of the <see cref="System.Buffers.ArrayPool`1"></see> class with the specified configuration.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:System.Buffers.ArrayPool`1.Rent(System.Int32)">
|
||||||
|
<summary>Retrieves a buffer that is at least the requested length.</summary>
|
||||||
|
<param name="minimumLength">The minimum length of the array.</param>
|
||||||
|
<returns>An array of type <see cref="T[]"></see> that is at least <paramref name="minimumLength">minimumLength</paramref> in length.</returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:System.Buffers.ArrayPool`1.Return(`0[],System.Boolean)">
|
||||||
|
<summary>Returns an array to the pool that was previously obtained using the <see cref="M:System.Buffers.ArrayPool`1.Rent(System.Int32)"></see> method on the same <see cref="T:System.Buffers.ArrayPool`1"></see> instance.</summary>
|
||||||
|
<param name="array">A buffer to return to the pool that was previously obtained using the <see cref="M:System.Buffers.ArrayPool`1.Rent(System.Int32)"></see> method.</param>
|
||||||
|
<param name="clearArray">Indicates whether the contents of the buffer should be cleared before reuse. If <paramref name="clearArray">clearArray</paramref> is set to true, and if the pool will store the buffer to enable subsequent reuse, the <see cref="M:System.Buffers.ArrayPool`1.Return(`0[],System.Boolean)"></see> method will clear the <paramref name="array">array</paramref> of its contents so that a subsequent caller using the <see cref="M:System.Buffers.ArrayPool`1.Rent(System.Int32)"></see> method will not see the content of the previous caller. If <paramref name="clearArray">clearArray</paramref> is set to false or if the pool will release the buffer, the array&#39;s contents are left unchanged.</param>
|
||||||
|
</member>
|
||||||
|
<member name="P:System.Buffers.ArrayPool`1.Shared">
|
||||||
|
<summary>Gets a shared <see cref="T:System.Buffers.ArrayPool`1"></see> instance.</summary>
|
||||||
|
<returns>A shared <see cref="System.Buffers.ArrayPool`1"></see> instance.</returns>
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
|
</doc>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user