diff --git a/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj b/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj
index 6fa295a..0c6f115 100644
--- a/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj
+++ b/C4IT_DataHistoryProvider_Base/F4SD-Cockpit-Server.csproj
@@ -149,6 +149,9 @@
+
+ Common\C4IT.F4SD.Base.Ticket.cs
+
Common\C4IT.F4SD.GlobalConfig.cs
@@ -254,9 +257,6 @@
DataHistoryCollectorActiveDirectory.cs
-
- DataHistoryCollectorCitrix.cs
-
DataHistoryCollectorClientAgent.cs
@@ -275,9 +275,6 @@
DataHistoryConfigActiveDirectory.cs
-
- DataHistoryConfigCitrix.cs
-
DataHistoryConfigClientAgent.cs
@@ -302,6 +299,9 @@
DataHistorySqlHelper.cs
+
+ DataSources\IRemoteDesktopManager.cs
+
DataSources\ISearchResultRelationProvider.cs
@@ -314,6 +314,27 @@
IisConfigHelper.cs
+
+ Modules\Agent\AgentApiHandler.cs
+
+
+ Modules\Agent\AgentRemoteClientInfo.cs
+
+
+ Modules\Agent\AgentRemoteConnectionInfo.cs
+
+
+ Modules\Agent\AgentRemoteDesktopManager.cs
+
+
+ Modules\Agent\DTOs\AgentLogonResultDto.cs
+
+
+ Modules\Citrix\DataHistoryCollectorCitrix.cs
+
+
+ Modules\Citrix\DataHistoryConfigCitrix.cs
+
Services\IStagedRelationService.cs
diff --git a/C4IT_DataHistoryProvider_Base/Publish/F4SD-Cockpit-Server.dll b/C4IT_DataHistoryProvider_Base/Publish/F4SD-Cockpit-Server.dll
index 7948232..3578b7d 100644
Binary files a/C4IT_DataHistoryProvider_Base/Publish/F4SD-Cockpit-Server.dll and b/C4IT_DataHistoryProvider_Base/Publish/F4SD-Cockpit-Server.dll differ
diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml
index d4cbfcd..abd254e 100644
--- a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml
+++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xml
@@ -14,9 +14,13 @@
-
+
+
+
+
+
@@ -24,4 +28,9 @@
+
+
+
+
+
diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd
index 03b1e75..07e37ef 100644
--- a/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd
+++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-Global-Configuration.xsd
@@ -18,11 +18,29 @@
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
@@ -76,6 +94,14 @@
+
+
+
+
+
+
+
+
@@ -131,6 +157,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -145,6 +187,7 @@
+
@@ -166,5 +209,29 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-HealthCard-Configuration.xml b/C4IT_DataHistoryProvider_Test/Config/F4SD-HealthCard-Configuration.xml
index 5e3bcc1..817c258 100644
--- a/C4IT_DataHistoryProvider_Test/Config/F4SD-HealthCard-Configuration.xml
+++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-HealthCard-Configuration.xml
@@ -252,6 +252,9 @@
IntuneDeviceId
+
+ EmpirumDeviceId
+
BshRegistryKeyExists
@@ -891,6 +894,21 @@
+
+
+ Empirum Informationen
+
+
+ Empirum Id
+
+
+ Letzte Inventory
+
+
+ IsPxe
+
+
+
@@ -1372,7 +1390,7 @@
-
+
Session
diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml b/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml
index ea81c56..3bb761d 100644
--- a/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml
+++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xml
@@ -7,7 +7,8 @@
R0ICvoG+yjJFGXGgagNQbzAwcBacJr47wRHOIwYhBl/YGDmxpoRWrI1GZ9x1C7ofSqeE1UeZNHX/oqMo/04h+jfUrqk1QHo/6e43Lns1z7UVhWrzOlPSxYwCjv7e4+6wqTWTx6UNGR5jCeD/eHAXHW24dGu7mph9xhcB3VC1kRY=
ZLAAU+jFXU/+x9FVjx4EAZRnK/D+G/OpZGkn4ek56vhDUeoR5QnSAsNu/cMa1yM3Zxa3CgmSjUmpBy+X2gr1Vo8yAeLVhqI8k9hzev+/LhrinTZIqVZZ4CaA5TEiBuNAy2uB8WEkned6uh3hRyIVNavlfoO9sToZn8f+xn8NKrM=
gdZccNCwzFrAdA+qGOA9I9ChD8hJQq/4Xuc5iC2i2I+Rtp6KCRrlgqPU0Wn6zwQ8SKitRLUSeNCJcspzkpewfv0Lnb2VIDMhdDeA5zyxVss0dZqDrMgYRhZcT+odtFTX8GlWUTyqBSQpUh8YQYdggvFZkE5ZOTaFU6kqUoKAgcs=
- a2btKvTS6UnTiD3vTaLX4JjQe3YB8iOpgqwDD3Imy9QzfIZwOBkKuI+jZDtea9VPpFsO6P7pVPmL5y3eZQpVe9oBlw74Ve0hMvX+RrNjAO5DINbBNG8JxZ4gPIMQsUnYVVkHH3pvoiJIJ8AlctQuMEQ2v2slnOvEhTMWiJF2vzQWPgY7vCu6hp92AJvalKIOmK6qT3u7gf45L06R16hpzxD73DbmYwEnMs1ZuF9e1NrLdXRBr+/m4/K8RneZf/hLnW70JJm1IfA/PEVYUEk5HG0fWZFTnsBI3xNXuxXg4OdiR/7Bcrmpj36ATEU6XfWnJBP5qZwhvNzIdMMcDLOnk52b56Szjr5wEOSJIvG93knmZJAFPDIqnRY9BLYtZb6rZ6sCpLMD7R97HKhUy0CFgNNY43CniAtIiARpnGFpdxPISSWeVFsqrckEDeya4hUpZQRUf7T53nTnOBFMuygDgWxfJnMxEl0tg6m5kfAhkguyFDRueA/XkSs0bXQ8xuERBZpKCWA7TJZnMbljK9G22VMYPFCJbB8hHkBjW49wsM8rF0MAS2KvweJdvFjclhqRNSH6sXHKTh4r870YYhYXNnrqobikmP81ZCoq6avKH10/1UPJJAQjBT4MwM488M7TfPv4q9l0ezi7v91fnl2MORRlZljoQ57ao6flIf/KCgQhxl20PtYPz4TcRU/onZ5OKRDXEgaWpkJZkt4ZZX2NgjIvEI8wTEATY3Eu2dBOKeWKD7jwhkPJtnRka8+miNSFanhwJ78WjIx1B/s9jMJ2njCMAzsabjVDMZPwedXigz67zcSl3NnCg4ycCukPnk/Vs2r90XjYKOCuvlU6CsTCeQLLX28Y2AaABY+7vQIEV3XPZVc4kimy6EEShfNZkkLNHQjoZqVXkFp8AKxWCZLzJOFyGFTAX0UqsN9O6soJ/rzAF68ByjYT2y9iggA8GDYUAHZxe0fX/b01+8D+I14c9qPctBaEPhJ2DjYOfJhKRglP1nkIX6U/wd0A19brME7fr50k/ndYpavzGOhVFHrcnxufn6CDJ9/8XeeQ3XdqHwCnYT4G0dUBDEQXcCGWJa0KVkefl4vW25A8Uz5aa4yQoOj7wsnJdLVoijClWEj4a7AWP1AaH9l+dQels1ek7nJ5M8BgjGK5QSSbSrgdNLVRTRZ8PxsSdSjs1tXpSZB6SfSIWW0l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
@@ -81,7 +82,7 @@
-
+
M42 Demo Server (Imagoverum)
diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xsd b/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xsd
index 3387100..089e8c8 100644
--- a/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xsd
+++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-Infrastructure-Configuration.xsd
@@ -391,12 +391,18 @@
+
+
+
+
+
-
+
+
@@ -405,14 +411,17 @@
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
@@ -420,6 +429,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xml b/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xml
index 787f4fb..08f025d 100644
--- a/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xml
+++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xml
@@ -1,6 +1,10 @@
+
+ Remote Verbindung starten
+
+
AD Computer Objekt bearbeiten
Opens Active Directory to edit the current selected computer.
@@ -933,14 +937,14 @@
-
+
Intune Komformitätsstatus erzwingen
Enforce Intune compliance state
Komformitätsstatus aktualisieren
Update compliance state
-
+
Bitlocker Schlüssel anzeigen
Show Bitlocker recoverykey
@@ -956,14 +960,29 @@
Laufwerkstyp
-
+
Erstellungsdatum
+
-
+
+ TAP Passwort anzeigen
+ Show TAP Password
+ TAP Passwort anzeigen
+ Show TAP Password
+
+
+
+ Passwort
+
+
+ Startdatum
+
+
+
-
+
Verwaltete Anwendungen anzeigen
Show managed applications
@@ -996,7 +1015,7 @@
-
-
+
Test:Bitlocker Schlüssel anzeigen
Test:Show Bitlocker recoverykey
@@ -1035,13 +1054,13 @@
Laufwerkstyp
-
+
Erstellungsdatum
-
+
Test:LAPS Passwort anzeigen
Test:Show LAPS Password
@@ -1057,14 +1076,14 @@
Passwort
-
+
Sicherungsdatum
-
-
-
+
Session abmelden
Session logoff
Session Abmelden
@@ -1140,7 +1159,7 @@
-
+
Session verstecken
Session hidden
Session verstecken
@@ -1151,7 +1170,7 @@
-
+
Nachricht senden zu Session
Send Message to Session
@@ -1162,5 +1181,24 @@
5
+
+
+ Empirum Inventur öffnen
+ This Quick Action requires information about the "Inventory of Device".
+ Um diese Quick Action verwenden zu können werden Informationen über das "Gerät" benötigt.
+
+ https://intune.microsoft.com/#view/Microsoft_Intune_Devices/DeviceSettingsMenuBlade/~/overview/mdmDeviceId/PARAM_EmpirumDeviceId
+
+
+
+
+ Nachricht senden zu Session
+ Send Message to Session
+
+ Nachricht senden zu Session
+ Send Message to Session
+
+
+
\ No newline at end of file
diff --git a/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xsd b/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xsd
index 7c45ca3..e0b615a 100644
--- a/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xsd
+++ b/C4IT_DataHistoryProvider_Test/Config/F4SD-QuickAction-Configuration.xsd
@@ -27,7 +27,7 @@
-
+
@@ -197,6 +197,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -249,7 +259,7 @@
-
+
diff --git a/C4IT_DataHistoryProvider_Test/DataHistorySql.xml b/C4IT_DataHistoryProvider_Test/DataHistorySql.xml
index e970b21..b244523 100644
--- a/C4IT_DataHistoryProvider_Test/DataHistorySql.xml
+++ b/C4IT_DataHistoryProvider_Test/DataHistorySql.xml
@@ -723,6 +723,22 @@
SELECT @cnt
+
+
+ DECLARE @cnt INT
+ SET @cnt = 0
+
+ IF EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[main-user-tokens]') AND type in (N'U'))
+ AND NOT EXISTS (SELECT * FROM Information_Schema.Columns WHERE Table_Name = 'main-user-tokens' AND Column_Name = 'id_remote')
+ BEGIN
+ PRINT N'Start adding column [id_remote] to table [main-user-tokens] ...';
+ ALTER Table [main-user-tokens] ADD [id_remote] NVARCHAR(64) NULL;
+ SET @cnt = @cnt + 1;
+ PRINT N'... done.'
+ END
+
+ SELECT @cnt
+
IF NOT EXISTS (SELECT 1 FROM [main-db-version] WHERE [db_version] = @version AND [db_revision] = @revision)
INSERT INTO [main-db-version] ([db_version], [db_revision]) VALUES (@version,@revision);
@@ -931,10 +947,24 @@
UPDATE [main-computer] SET [id_intune]=@id WHERE [deviceId_azure]=@deviceId
-
+
UPDATE [main-computer] SET [id_intune]=@id, [deviceid_azure]=@deviceid, tenant_azure = @tenant WHERE upn_internal = @upn_internal and [domainNB] is null
-
+
+ DECLARE @ID UNIQUEIDENTIFIER
+ SET @ID = (SELECT id FROM [main-user] WHERE [sid_bin] = @SID)
+ IF (@ID is null) SET @ID = (SELECT id FROM [main-user] WHERE [upn_external] = @UPN)
+ SELECT @ID
+
+
+ SELECT [id],[origin],[instance],[id_foreign] FROM [main-user-foreign-ids] WHERE [ID] = @ID
+
+
+ UPDATE [main-user-foreign-ids] SET [id] = @ID WHERE [origin] = @origin and [instance] = @instance and [id_foreign] = @id_foreign
+ IF @@ROWCOUNT = 0
+ INSERT INTO [main-user-foreign-ids] ([id], [origin], [instance], [id_foreign]) VALUES (@id, @origin, @instance, @id_foreign)
+
+
UPDATE [main-user] SET [id_citrix]=@id WHERE [sid_bin]=@sid_bin
@@ -2526,14 +2556,14 @@
SELECT [Key],[Value] FROM [main-config]
- SELECT [id],[type],[name],[name2],[secret],[validUntil],[renewUntil] FROM [main-user-tokens]
+ SELECT [id],[type],[name],[name2],[secret],[validUntil],[renewUntil],[id_remote] FROM [main-user-tokens]
DELETE FROM [main-user-tokens] WHERE [validUntil] < @ValidUntil
- UPDATE [main-user-tokens] SET [name]=@Name, [name2]=@Name2, [secret]=@Secret, [validUntil]=@ValidUntil, [renewUntil]=@RenewUntil WHERE [id]=@Id AND [type]=@Type
- IF @@ROWCOUNT = 0 INSERT INTO [main-user-tokens] ([id], [type], [name], [name2], [secret], [validUntil], [renewUntil]) VALUES (@Id, @Type, @Name, @Name2, @Secret, @ValidUntil, @RenewUntil)
+ UPDATE [main-user-tokens] SET [name]=@Name, [name2]=@Name2, [secret]=@Secret, [validUntil]=@ValidUntil, [renewUntil]=@RenewUntil, [id_remote]=@IdRemote WHERE [id]=@Id AND [type]=@Type
+ IF @@ROWCOUNT = 0 INSERT INTO [main-user-tokens] ([id], [type], [name], [name2], [secret], [validUntil], [renewUntil], [id_remote]) VALUES (@Id, @Type, @Name, @Name2, @Secret, @ValidUntil, @RenewUntil, @IdRemote)
SELECT @@ROWCOUNT
diff --git a/C4IT_DataHistoryProvider_Test/License/F4SD_License.xml b/C4IT_DataHistoryProvider_Test/License/F4SD_License.xml
index 750e156..5da51c1 100644
--- a/C4IT_DataHistoryProvider_Test/License/F4SD_License.xml
+++ b/C4IT_DataHistoryProvider_Test/License/F4SD_License.xml
@@ -1,12 +1,13 @@
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/C4IT_DataHistoryProvider_Test/ctrlCitrix.cs b/C4IT_DataHistoryProvider_Test/ctrlCitrix.cs
index cc407f1..75838a3 100644
--- a/C4IT_DataHistoryProvider_Test/ctrlCitrix.cs
+++ b/C4IT_DataHistoryProvider_Test/ctrlCitrix.cs
@@ -1,19 +1,15 @@
using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Data;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows.Forms;
-using C4IT.DataHistoryProvider;
-using System.Reflection;
-using C4IT.Logging;
+using System.Threading;
+using System.Reflection;
+
+using C4IT.Logging;
+using C4IT.DataHistoryProvider;
+using C4IT.DataHistoryProvider.Base.Modules.Citrix;
using static C4IT.Logging.cLogManager;
-using System.Threading;
+
namespace C4IT_DataHistoryProvider_Test
{
public partial class ctrlCitrix: UserControl
@@ -39,12 +35,22 @@ namespace C4IT_DataHistoryProvider_Test
Program.Collector.CleanupUiMessageHandler();
Program.Collector.ProcessUiMessage += ctrlProtocolBox1.ProcessMessage;
var _requestInfo = new cF4sdWebRequestInfo("btnConnectCitrix_Click", null);
- var tenants = Program.Collector.InfrastructureConfig.CitrixTenants?.Values;
+ var systems = Program.Collector.InfrastructureConfig.Citrix.Systems;
+ ctrlProtocolBox1.ProcessMessage($"Validating Citrix connections...");
- foreach (var Tenant in tenants)
+ await Program.Collector.CitrixCollector.ValidateConnectionsAsync(CancellationToken.None);
+
+ ctrlProtocolBox1.ProcessMessage($"Validating Citrix connections finished.");
+
+ return;
+
+ foreach (var _system in systems)
{
- var result = await Program.Collector.CitrixCollector.GetCitrixCommunicationForTenantAsync(Tenant.TenantID, false);
+ if (!(_system is cDataHistoryCitrixCloudTenant Tenant))
+ continue;
+
+ var result = await Program.Collector.CitrixCollector.GetCitrixCommunicationForSystemAsync(Tenant.TenantID, false);
if (result != null)
{
ctrlProtocolBox1.ProcessMessage($"Citrix connection for tenant {Tenant.TenantID} successful");
@@ -84,13 +90,17 @@ namespace C4IT_DataHistoryProvider_Test
Program.Collector.CleanupUiMessageHandler();
Program.Collector.ProcessUiMessage += ctrlProtocolBox1.ProcessMessage;
var _requestInfo = new cF4sdWebRequestInfo("btnConnectCitrix_Click", null);
- var tenants = Program.Collector.InfrastructureConfig.CitrixTenants?.Values;
+
+ var systems = Program.Collector.InfrastructureConfig.Citrix.Systems;
- foreach (var Tenant in tenants)
+ foreach (var _system in systems)
{
+ if (!(_system is cDataHistoryCitrixCloudTenant Tenant))
+ continue;
+
var result = await Program.Collector.CitrixCollector.GetCitrixUsersAsync();
- if (result != null)
+ if (result)
{
ctrlProtocolBox1.ProcessMessage($"Citrix connection for tenant {Tenant.TenantID} successful");
}
@@ -129,13 +139,16 @@ namespace C4IT_DataHistoryProvider_Test
Program.Collector.CleanupUiMessageHandler();
Program.Collector.ProcessUiMessage += ctrlProtocolBox1.ProcessMessage;
var _requestInfo = new cF4sdWebRequestInfo("btnGetSessions_Click", null);
- var tenants = Program.Collector.InfrastructureConfig.CitrixTenants?.Values;
+ var systems = Program.Collector.InfrastructureConfig.Citrix.Systems;
- foreach (var Tenant in tenants)
+ foreach (var _system in systems)
{
+ if (!(_system is cDataHistoryCitrixCloudTenant Tenant))
+ continue;
+
var result = await Program.Collector.CitrixCollector.GetCitrixSessionsAsync();
- if (result != null)
+ if (result)
{
ctrlProtocolBox1.ProcessMessage($"Citrix connection for tenant {Tenant.TenantID} successful");
}
@@ -170,8 +183,6 @@ namespace C4IT_DataHistoryProvider_Test
{
Cursor = Cursors.WaitCursor;
-
-
if (Program.Collector == null)
return;
@@ -179,23 +190,16 @@ namespace C4IT_DataHistoryProvider_Test
Program.Collector.CleanupUiMessageHandler();
Program.Collector.ProcessUiMessage += ctrlProtocolBox1.ProcessMessage;
var _requestInfo = new cF4sdWebRequestInfo("btnScanUsers_Click", null);
- var tenants = Program.Collector.InfrastructureConfig.CitrixTenants?.Values;
+ ctrlProtocolBox1.ProcessMessage($"Starting Citrix user scans...");
- foreach (var Tenant in tenants)
- {
- var result = await Program.Collector.CitrixCollector.DoScanAsync(true, true, _requestInfo, 1, CancellationToken.None);
- if (result)
- {
- ctrlProtocolBox1.ProcessMessage($"Citrix connection for tenant {Tenant.TenantID} successful");
- }
- else
- {
- ctrlProtocolBox1.ProcessMessage($"Citrix connection for tenant {Tenant.TenantID} failed");
-
- }
- }
+ Program.Collector.CitrixCollector.DoScanSequential = true;
+ var result = await Program.Collector.CitrixCollector.DoScanAsync(true, true, _requestInfo, 0, CancellationToken.None);
+ if (result)
+ ctrlProtocolBox1.ProcessMessage($"All Citrix user scans finished successfully.");
+ else
+ ctrlProtocolBox1.ProcessMessage($"At least one Citrix user scan finished with errors.");
}
catch (Exception E)
{
diff --git a/C4IT_DataHistoryProvider_Test/ctrlMainFunction.cs b/C4IT_DataHistoryProvider_Test/ctrlMainFunction.cs
index 2a49cec..8edbcaf 100644
--- a/C4IT_DataHistoryProvider_Test/ctrlMainFunction.cs
+++ b/C4IT_DataHistoryProvider_Test/ctrlMainFunction.cs
@@ -231,7 +231,7 @@ namespace C4IT_DataHistoryProvider_Test
if (Program.Collector.InfrastructureConfig.F4SDAnalyticsDB != null)
Program.mainForm.tabControlMain.TabPages.Add(Program.mainForm.tabPageF4SDAnalytics);
- if (Program.Collector.CitrixCollector != null && Program.Collector.InfrastructureConfig.CitrixTenants?.Values != null)
+ if (Program.Collector.CitrixCollector != null && Program.Collector.InfrastructureConfig.Citrix.Systems != null)
Program.mainForm.tabControlMain.TabPages.Add(Program.mainForm.tabPageCitrix);
if (Program.Collector.NxqlCollector != null && !Program.mainForm.tabControlMain.TabPages.Contains(Program.mainForm.tabPageNexthink))
diff --git a/CommonAssemblyInfo.cs b/CommonAssemblyInfo.cs
index e0f59d2..b2dc583 100644
--- a/CommonAssemblyInfo.cs
+++ b/CommonAssemblyInfo.cs
@@ -15,8 +15,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
-[assembly: AssemblyInformationalVersion("2.6.1.1")]
-[assembly: AssemblyVersion("2.6.*")]
+[assembly: AssemblyInformationalVersion("2.7.1.0")]
+[assembly: AssemblyVersion("2.7.*")]
[assembly: AssemblyMinClientVersion("2.6.0.0")]
diff --git a/F4SD-Cockpit-ConfigLoader/F4SD-Cockpit-ConfigLoader.csproj b/F4SD-Cockpit-ConfigLoader/F4SD-Cockpit-ConfigLoader.csproj
index 8a4e9e6..6d27e8d 100644
--- a/F4SD-Cockpit-ConfigLoader/F4SD-Cockpit-ConfigLoader.csproj
+++ b/F4SD-Cockpit-ConfigLoader/F4SD-Cockpit-ConfigLoader.csproj
@@ -111,6 +111,9 @@
MSBuild:Compile
Designer
+
+ Common\C4IT.F4SD.Base.Ticket.cs
+
Common\C4IT.F4SD.GlobalConfig.cs
diff --git a/F4SD-Cockpit-ServerCore/Common/C4IT.FASD.Communication.Citrix.cs b/F4SD-Cockpit-ServerCore/Common/C4IT.FASD.Communication.Citrix.cs
index 1d659e6..2c472f1 100644
--- a/F4SD-Cockpit-ServerCore/Common/C4IT.FASD.Communication.Citrix.cs
+++ b/F4SD-Cockpit-ServerCore/Common/C4IT.FASD.Communication.Citrix.cs
@@ -1,66 +1,579 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.Design;
using System.Linq;
using System.Net;
+using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
+
using C4IT.HTTP;
-using C4IT.MsGraph;
-using Newtonsoft.Json.Linq;
using C4IT.Logging;
+
+using Newtonsoft.Json.Linq;
+
using static C4IT.Logging.cLogManager;
-using C4IT.DataHistoryProvider;
namespace C4IT.FASD.Communication.Citrix
{
- public class cCitrixCommunication : cHttpApiBase
+ public class cCitrixApiResultList : List
+ {
+ public string NextResultUrl { get; private set; } = null;
+ public bool retryForbidden { get; private set; } = false;
+
+ public cCitrixApiResultList(bool retryForbidden)
+ {
+ this.retryForbidden = retryForbidden;
+ }
+
+ public bool hasRemaining
+ {
+ get
+ {
+ return !string.IsNullOrEmpty(NextResultUrl);
+ }
+ }
+
+ public void AddResult(dynamic Result)
+ {
+ try
+ {
+ NextResultUrl = null;
+
+ if (Result.TryGetValue("@odata.nextLink", out JToken JT))
+ {
+ var JO = (JValue)JT;
+
+ NextResultUrl = Result["@odata.nextLink"];
+ }
+
+ if (Result.TryGetValue("value", out JToken JT2))
+ {
+ foreach (dynamic Entry in Result.value)
+ try
+ {
+ var val = new cCitrixApiResultBase(Entry);
+ this.Add(val);
+ }
+ catch (Exception E)
+ {
+ cLogManager.DefaultLogger.LogException(E);
+ }
+ }
+ }
+ catch (Exception E)
+ {
+ cLogManager.DefaultLogger.LogException(E);
+ }
+ }
+
+ }
+
+ public class cCitrixApiResultBase
+ {
+ public string ID { get; private set; } = null;
+ public string ODataId { get; private set; } = null;
+ public string DisplayName { get; private set; } = null;
+
+ public string Context { get; private set; } = null;
+
+ public dynamic Result { get; private set; } = null;
+
+ public cCitrixApiResultBase(dynamic Result, string namePropery = null)
+ {
+ this.Result = Result;
+
+ try { ID = Result.Id; } catch { }
+ ;
+ try
+ {
+ if (namePropery == null)
+ namePropery = "displayName";
+ if (Result.TryGetValue(namePropery, out JToken JT1))
+ {
+ var _ty = JT1.GetType().ToString();
+ if (JT1 is JValue _jVal)
+ DisplayName = _jVal.Value?.ToString();
+ }
+ else if (Result.TryGetValue("name", out JToken JT2))
+ DisplayName = Result.name;
+ }
+ catch { }
+ try { Context = Result["@odata.context"]; } catch { }
+ ODataId = GetStringFromDynamic(Result, "@odata.id");
+ if (string.IsNullOrEmpty(ODataId))
+ ODataId = @"https://api.cloud.com/" + ID;
+ }
+
+ public cCitrixApiResultBase(cCitrixApiResultBase Result)
+ {
+ if (Result == null)
+ return;
+
+ this.Result = Result.Result;
+ ID = Result.ID;
+ ODataId = Result.ODataId;
+ DisplayName = Result.DisplayName;
+ Context = Result.Context;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static string GetStringFromDynamic(dynamic O, string ProperyName)
+ {
+ try
+ {
+ return (string)O[ProperyName];
+ }
+ catch { }
+ return null;
+ }
+ }
+
+ public class cCitrixCustomerInfo
+ {
+ public string Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+
+ public cCitrixSiteInfo PrimarySite { get; set; }
+
+ public Dictionary Sites { get; private set; } = new Dictionary();
+ }
+
+ public class cCitrixSiteInfo
+ {
+ public Guid Id { get; set; }
+ public string Name { get; set; } = string.Empty;
+
+ public bool? IsValid { get; set; } = null;
+ public bool IsPrimarySite { get; set; } = false;
+ }
+
+ public class cCitrixCommunicationSystem
+ {
+ public const string constCitrixCloudMonitorUrl = "monitorodata/";
+
+ public const string constCitrixOnPremMonitorUrl = "Citrix/Monitor/OData/v4/Data/";
+
+ public cCitrixCommunicationMonitor Monitor { get; private set; }
+ public cCitrixCommunicationCvad CVAD { get; private set; }
+
+ public bool IsCloud { get; private set; }
+
+ public string Name { get; private set; } = string.Empty;
+
+ public cCitrixCommunicationSystem(cCitrixCommunicationCloudBase CitrixCloud, string Name)
+ {
+ IsCloud = true;
+ this.Name = Name;
+ this.Monitor = new cCitrixCommunicationMonitor(CitrixCloud);
+ this.CVAD = new cCitrixCommunicationCvad(CitrixCloud);
+ }
+
+ public cCitrixCommunicationSystem(cCitrixCommunicationOnPremCvad Cvad, cCitrixCommunicationOnPremMonitor Monitor, string Name)
+ {
+ IsCloud = false;
+ this.Name = Name;
+ this.Monitor = new cCitrixCommunicationMonitor(Monitor);
+ this.CVAD = new cCitrixCommunicationCvad(Cvad);
+ }
+
+ public async Task ScanCustomerInfosAsync(CancellationToken token)
+ {
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
+
+ try
+ {
+ var _retVal = new cCitrixCustomerInfo();
+ var CustomerInfo = await CVAD.GetCustomerInfoAsync(token);
+ if (token.IsCancellationRequested)
+ return null;
+
+ if (CustomerInfo == null)
+ return _retVal;
+
+ _retVal.Id = CustomerInfo.Id;
+ _retVal.Name = CustomerInfo.Name;
+
+ cCitrixSiteInfo PrimarySite = null;
+ int maxConsitency = 0;
+ int countC0 = 0;
+ int countC1 = 0;
+ int countC2 = 0;
+ foreach (var site in CustomerInfo.Sites.Values)
+ {
+ var _newSite = new cCitrixSiteInfo()
+ {
+ Name = site.Name,
+ Id = site.Id,
+ IsValid = false
+ };
+
+ // validate the site consitency
+ var _resultConsitency = await CheckSiteConsitencyAsync(site.Id.ToString("D"), token);
+ if (token.IsCancellationRequested)
+ return null;
+ switch (_resultConsitency)
+ {
+ case 0: _newSite.IsValid = null; countC0++; break;
+ case 1: _newSite.IsValid = true; countC1++; break;
+ case 2: _newSite.IsValid = true; countC2++; break;
+ }
+
+ if (maxConsitency < _resultConsitency)
+ PrimarySite = _newSite;
+
+ maxConsitency = Math.Max(maxConsitency, _resultConsitency);
+
+ _retVal.Sites.Add(_newSite.Id, _newSite);
+ }
+
+ if (PrimarySite != null)
+ {
+ if (countC2 == 1)
+ PrimarySite.IsPrimarySite = true;
+ else if (countC1 == 1 && countC2 == 0)
+ PrimarySite.IsPrimarySite = true;
+ }
+
+ if (PrimarySite?.IsPrimarySite == true)
+ _retVal.PrimarySite = PrimarySite;
+
+ return _retVal;
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ finally
+ {
+ if (CM != null) LogMethodEnd(CM);
+ }
+
+
+ return null;
+ }
+
+ public async Task CheckSiteConsitencyAsync(string SiteId, CancellationToken token)
+ {
+ // check if the machines queried from the monitor component could be found in the cvad component
+ // return values:
+ // 2: all machines could be found
+ // 1: al least one machine could be found
+ // 0: no machines in monitor component
+ // -1: none of the machines could be found
+ // -2: internal error occured
+
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
+
+ var _lastSiteId = CVAD.CitrixInfo.SiteId;
+ try
+ {
+ CVAD.CitrixInfo.SiteId = SiteId;
+
+ // get the machine list from cvad
+ var _machinesCvad = await CVAD.GetMachineNamesAsync(token);
+ if (token.IsCancellationRequested)
+ return -2;
+
+ // get the machine list from monitor
+ var _machinesMonitor = await Monitor.GetMachineNamesAsync(token);
+ if (token.IsCancellationRequested)
+ return -2;
+
+ if (_machinesMonitor == null || _machinesMonitor.Count == 0)
+ return 0;
+
+ var atLeastOne = false;
+ var all = true;
+ foreach ( var machineName in _machinesMonitor )
+ {
+ if (_machinesCvad.Contains(machineName))
+ atLeastOne = true;
+ else
+ all = false;
+ }
+
+ if (atLeastOne && all)
+ return 2;
+ if (atLeastOne)
+ return 1;
+
+ return -1;
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ finally
+ {
+ CVAD.CitrixInfo.SiteId = _lastSiteId;
+ if (CM != null) LogMethodEnd(CM);
+ }
+
+ return -2;
+ }
+ }
+
+ public interface iCitrixCvadInfo
+ {
+ string CustomerId { get; }
+
+ string SiteId { get; set; }
+
+ }
+
+ public class cCitrixCommunicationCloudBase : cHttpApiBase, iCitrixCvadInfo
{
public const int constMaxPageSize = 1000;
- public const string constCitrixBaseUrl = "https://api.cloud.com/{Request}";
- public const string constCitrixUserList = "monitorodata/Users?$top={top}&$skip={skip}&$select=Id,Sid,Upn,Domain&$filter=Domain ne ''";
- public const string constCitrixUserSessions = "monitorodata/Sessions?$filter=UserId eq {UserId} and (EndDate eq null or StartDate ge {MinStartDate})&$expand=Machine($select=Id,DnsName,Name)&$select=SessionKey,StartDate,EndDate,ConnectionState";
- public cCitrixCommunication() : base("Citrix ID tenant", "https://api.cloud.com/cctrustoauth2/{Tenant}/tokens/clients", "Citrix Comunication")
+ private string InstanceId = null;
+
+ public cCitrixCommunicationCloudBase(string baseUrlCloud) : base("Citrix customer tenant", $"{baseUrlCloud}/cctrustoauth2/{{Tenant}}/tokens/clients", "Citrix API", baseUrlCloud)
{
- KnownAutoRetryErrors.Add(HttpStatusCode.Forbidden);
- autoRetryCount = 2;
- autoRetryDelay = 100;
+ MaxConcurrentRequests = 1;
+ KnownAutoRetryErrors.Add((HttpStatusCode)429);
+ autoRetryCount = 50;
+ autoRetryDelay = 200;
+ autoRetryOnKnownErrors = true;
}
private protected override List> GetRequestHeaders(cOAuthLogonInfo privLogonInfo)
{
-
+
return new List>()
{
new KeyValuePair("Authorization", $"CwsAuth Bearer={AccessToken}"),
new KeyValuePair("Citrix-CustomerId", privLogonInfo.Tenant),
- new KeyValuePair("Citrix-InstanceId", privLogonInfo.InstanceId)
+ new KeyValuePair("Citrix-InstanceId", InstanceId)
};
}
- public async Task RequestAsync(string Request, eHttpMethod httpMethod = eHttpMethod.get, object JsonData = null, bool retryForbidden = false, string nameProperty = null, bool noAutoRelogon = false)
+
+ public string CustomerId { get {
+ return this.privLogonInfo?.Tenant;
+ } }
+
+ public string SiteId
+ {
+ get { return InstanceId; }
+ set { InstanceId = value; }
+ }
+ }
+
+ public class cCitrixCommunicationOnPremCvad : cHttpApiBase, iCitrixCvadInfo
+ {
+ private const string constLogonUrl = "manage/Tokens";
+ private string privCustomerId = null;
+ private string InstanceId = null;
+
+ public cCitrixCommunicationOnPremCvad(string baseUrl) : base("Citrix on-prem system", baseUrl, "Citrix API", baseUrl + "/cvad/")
+ {
+ // MaxConcurrentRequests = 1;
+ //KnownAutoRetryErrors.Add((HttpStatusCode)429);
+ //autoRetryCount = 50;
+ //autoRetryDelay = 200;
+ //autoRetryOnKnownErrors = true;
+ }
+
+ public string CustomerId { get { return privCustomerId; } }
+
+ public string SiteId
+ {
+ get { return InstanceId; }
+ set { InstanceId = value; }
+ }
+
+ private protected override async Task privLogonWithCredentialsAsync(NetworkCredential credentials)
+ {
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
+
+ try
+ {
+ var _usr = credentials.UserName;
+ if (!string.IsNullOrEmpty(credentials.Domain))
+ _usr = $"{credentials.Domain}\\{_usr}";
+ var _auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_usr}:{credentials.Password}"));
+ using (var httpClient = new HttpClient())
+ {
+ httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", _auth);
+ httpClient.BaseAddress = new Uri(RequestBaseUrl);
+ var _result = await httpClient.PostAsync(constLogonUrl, null);
+ if (_result != null)
+ {
+ var content = await _result.Content.ReadAsStringAsync();
+ if (_result.IsSuccessStatusCode)
+ {
+ var JO = JObject.Parse(content);
+ var token = JO["Token"]?.ToString();
+ var CustomerId = JO["CustomerId"]?.ToString();
+ var strExpires = JO["ExpiresAt"]?.ToString();
+ if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(CustomerId) || string.IsNullOrEmpty(strExpires))
+ {
+ LastErrorMessage = $"CVAD Logon failed because no valid token information could be found in the logon result.";
+ return new cCredentialLoginInfo();
+ }
+
+
+ if (!DateTime.TryParse(strExpires, out var expires))
+ {
+ LastErrorMessage = $"CVAD Logon failed because no valid expiration information could be found in the logon result.";
+ return new cCredentialLoginInfo();
+ }
+
+ expires = DateTime.SpecifyKind(expires, DateTimeKind.Utc);
+ var _now = DateTime.UtcNow;
+
+ var _expieresInteral = expires - _now;
+ var _delta = _expieresInteral.TotalSeconds * RelogonFactor;
+ var expires2 = _now + TimeSpan.FromSeconds(_delta);
+
+ this.privCustomerId = CustomerId;
+
+ return new cCredentialLoginInfo() { IsValid = true, Token = token, TokenExpiresIn = expires2 };
+ }
+ else
+ {
+ LastErrorMessage = $"CVAD Logon failed with status code {(int)_result.StatusCode}: {_result.ReasonPhrase}";
+ }
+ }
+ else
+ LastErrorMessage = $"CVAD Logon failed due to unknown reason.";
+ }
+
+ }
+ catch (Exception E)
+ {
+ LastErrorMessage = $"CVAD Logon failed with exception: {E.Message}";
+ LogException(E);
+ }
+ finally
+ {
+ if (CM != null) LogMethodEnd(CM);
+ }
+
+
+ return new cCredentialLoginInfo();
+ }
+
+ private protected override List> GetRequestHeaders(cOAuthLogonInfo privLogonInfo)
+ {
+ var _retVal = new List>()
+ {
+ new KeyValuePair("Authorization", $"CwsAuth Bearer={AccessToken}")
+ };
+
+ if (privCustomerId != null)
+ _retVal.Add(new KeyValuePair("Citrix-CustomerId", privCustomerId));
+
+ if (InstanceId != null)
+ _retVal.Add(new KeyValuePair("Citrix-InstanceId", InstanceId));
+
+ return _retVal;
+ }
+
+ }
+
+ public class cCitrixCommunicationOnPremMonitor : cHttpApiBase
+ {
+ private const string constLogonUrl = "Users?$top=1&$select=Id";
+
+ public cCitrixCommunicationOnPremMonitor(string baseUrl) : base("Citrix on-prem system", baseUrl, "Citrix API", baseUrl + string.Format("/Citrix/Monitor/OData/v4/Data/"))
+ {
+ }
+
+ private protected override async Task privLogonWithCredentialsAsync(NetworkCredential credentials)
+ {
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
+
+ try
+ {
+ var _auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{credentials.Domain}\\{credentials.UserName}:{credentials.Password}"));
+
+ using (var _handler = new HttpClientHandler())
+ {
+ _handler.Credentials = credentials;
+ _handler.PreAuthenticate = true;
+ using (var httpClient = new HttpClient(_handler))
+ {
+ httpClient.BaseAddress = new Uri(RequestBaseUrl);
+ httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
+ var _result = await httpClient.GetAsync(constLogonUrl);
+ if (_result != null)
+ {
+ var content = await _result.Content.ReadAsStringAsync();
+ if (_result.IsSuccessStatusCode)
+ return new cCredentialLoginInfo() { IsValid = true, Token = null, TokenExpiresIn = DateTime.MaxValue, useAlwaysCredentials = true };
+ else
+ LastErrorMessage = $"Monitor Logon failed with status code {(int)_result.StatusCode}: {_result.ReasonPhrase}";
+ }
+ else
+ LastErrorMessage = $"Monitor Logon failed due to unknown reason.";
+
+ }
+ }
+ }
+ catch (Exception E)
+ {
+ LastErrorMessage = $"Monitor Logon failed with exception: {E.Message}";
+ LogException(E);
+ }
+ finally
+ {
+ if (CM != null) LogMethodEnd(CM);
+ }
+
+
+ return new cCredentialLoginInfo();
+ }
+
+ private protected override List> GetRequestHeaders(cOAuthLogonInfo privLogonInfo)
+ {
+ var _retVal = new List>();
+ {
+ new KeyValuePair("Accept", "application/json");
+ }
+ ;
+
+ return _retVal;
+ }
+ }
+
+ public class cCitrixCommunicationBase
+ {
+ private cHttpApiBase HttpApi;
+
+ public Uri baseUri { get; private set; }
+
+ public string LastErrorMessage { get { return HttpApi.LastErrorMessage; } }
+
+ public cCitrixCommunicationBase(cHttpApiBase HttpApi, string baseUrl)
+ {
+ this.HttpApi = HttpApi;
+ this.baseUri = new Uri(new Uri(HttpApi.RequestBaseUrl), baseUrl);
+ }
+
+ public async Task RequestAsync(string Request, eHttpMethod httpMethod, object JsonData, string nameProperty = null, bool retryForbidden = false, bool noAutoRelogon = false, CancellationToken token = default)
{
MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
try
{
+ var uriRequest = new Uri(baseUri, Request);
- var strUrl = constCitrixBaseUrl;
- strUrl = strUrl.Replace("{Request}", Request);
-
- var data = await privRequestAsync(strUrl, httpMethod, JsonData, retryForbidden, noAutoRelogon: noAutoRelogon);
+ var data = await HttpApi.privRequestAsync(uriRequest.OriginalString, httpMethod, JsonData, retryForbidden, noAutoRelogon: noAutoRelogon, token: token);
if (data == null)
return null;
if (data is bool isValid)
{
if (isValid)
- return new cCitrixResultBase(null);
+ return new cCitrixApiResultBase(null);
else
return null;
}
- var RetVal = new cCitrixResultBase(data, nameProperty);
+ var RetVal = new cCitrixApiResultBase(data, nameProperty);
return RetVal;
}
catch (Exception E)
@@ -74,19 +587,15 @@ namespace C4IT.FASD.Communication.Citrix
return null;
}
- public async Task RequestListAsync(string Request, bool loadPaged = false, bool retryForbidden = false)
+ public async Task RequestListAsync(string Request, bool loadPaged, bool retryForbidden, CancellationToken token = default)
{
try
{
- // get the request url
-
- var strUrl = constCitrixBaseUrl;
- strUrl = strUrl.Replace("{Request}", Request);
-
- var res = await privRequestAsync(strUrl, autoRetry: retryForbidden);
+ var uriRequest = new Uri(baseUri, Request);
+ var res = await HttpApi.privRequestAsync(uriRequest.OriginalString, autoRetry: retryForbidden, token: token);
if (res != null)
{
- var RetVal = new cCitrixResultList(retryForbidden);
+ var RetVal = new cCitrixApiResultList(retryForbidden);
RetVal.AddResult(res);
if (!RetVal.hasRemaining || loadPaged)
return RetVal;
@@ -105,11 +614,11 @@ namespace C4IT.FASD.Communication.Citrix
return null;
}
- public async Task RequestNextAsync(cCitrixResultList List)
+ public async Task RequestNextAsync(cCitrixApiResultList List, CancellationToken token = default)
{
try
{
- var res = await privRequestAsync(List.NextResultUrl, autoRetry: List.retryForbidden);
+ var res = await HttpApi.privRequestAsync(List.NextResultUrl, autoRetry: List.retryForbidden, token: token);
if (res != null)
{
List.AddResult(res);
@@ -124,117 +633,390 @@ namespace C4IT.FASD.Communication.Citrix
return false;
}
- public class cCitrixResultList : List
+ }
+
+ public class cCitrixCommunicationCvad
+ {
+ public const string constCitrixCvadUrl = "cvad/";
+
+ public const string constCitrixApiMe = "manage/Me";
+ public const string constCitrixApiMachineNames = "manage/Machines?fields=DnsName";
+ public const string constCitrixApiSessions = "manage/Sessions?fields=Id,Uid,State,StartTime";
+
+ public cCitrixCommunicationBase Request { get; private set; }
+
+ public iCitrixCvadInfo CitrixInfo { get; private set; }
+
+ public cCitrixCommunicationCvad(cCitrixCommunicationCloudBase CitrixCloud)
{
- public string NextResultUrl { get; private set; } = null;
- public bool retryForbidden { get; private set; } = false;
+ this.Request = new cCitrixCommunicationBase(CitrixCloud, constCitrixCvadUrl);
+ this.CitrixInfo = CitrixCloud as iCitrixCvadInfo;
+ }
- public cCitrixResultList(bool retryForbidden)
+ public cCitrixCommunicationCvad(cCitrixCommunicationOnPremCvad OnPremCvad)
+ {
+ this.Request = new cCitrixCommunicationBase(OnPremCvad, null);
+ this.CitrixInfo = OnPremCvad as iCitrixCvadInfo;
+ }
+
+
+ public string GetServer()
+ {
+ return Request?.baseUri?.Host;
+ }
+
+ public async Task GetCustomerInfoAsync(CancellationToken Token)
+ {
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
+
+ try
{
- this.retryForbidden = retryForbidden;
- }
+ var _resultMe = await Request.RequestAsync(constCitrixApiMe, eHttpMethod.get, null);
- public bool hasRemaining
- {
- get
- {
- return !string.IsNullOrEmpty(NextResultUrl);
- }
- }
+ if (Token.IsCancellationRequested)
+ return null;
- public void AddResult(dynamic Result)
- {
- try
- {
- NextResultUrl = null;
+ if (_resultMe?.Result == null)
+ return null;
- if (Result.TryGetValue("@odata.nextLink", out JToken JT))
+ var _obj = _resultMe.Result.Customers;
+ var _customers = _obj as IEnumerable;
+
+ if (_customers == null)
+ return null;
+
+ cCitrixCustomerInfo _retVal = null;
+
+ foreach (var _customer in _customers) {
+ var id = _customer.Id;
+ if (id != CitrixInfo?.CustomerId)
+ continue;
+
+ _retVal = new cCitrixCustomerInfo()
{
- var JO = (JValue)JT;
+ Id = _customer.Id,
+ Name = _customer?.Name
+ };
- NextResultUrl = Result["@odata.nextLink"];
- }
-
- if (Result.TryGetValue("value", out JToken JT2))
- {
- foreach (dynamic Entry in Result.value)
+ _obj = _customer.Sites;
+ var _sites = _obj as IEnumerable;
+ if (_sites != null)
+ foreach (var _site in _sites)
+ {
try
{
- var val = new cCitrixResultBase(Entry);
- this.Add(val);
+ if (Guid.TryParse(_site.Id.ToString(), out Guid _id))
+ {
+ var siteInfo = new cCitrixSiteInfo()
+ {
+ Id = _id,
+ Name = _site.Name
+ };
+ _retVal.Sites[_id] = siteInfo;
+ }
}
catch (Exception E)
{
cLogManager.DefaultLogger.LogException(E);
}
+ }
+
+ }
+
+ return _retVal;
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ finally
+ {
+ if (CM != null) LogMethodEnd(CM);
+ }
+
+ return null;
+ }
+
+ public async Task> GetMachineNamesAsync(CancellationToken token)
+ {
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
+
+ try
+ {
+ var _result = await Request.RequestAsync(constCitrixApiMachineNames, eHttpMethod.get, null, token: token);
+
+ if (_result?.Result == null)
+ return null;
+
+ var _items = _result.Result?.Items as IEnumerable;
+
+ if (_items == null)
+ return null;
+
+ var _retVal = new List();
+ foreach ( var item in _items )
+ {
+ try
+ {
+ var _dnsName = item.DnsName?.ToString()?.ToLowerInvariant();
+ if (!string.IsNullOrEmpty( _dnsName ))
+ _retVal.Add( _dnsName );
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ }
+
+ return _retVal;
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ finally
+ {
+ if (CM != null) LogMethodEnd(CM);
+ }
+
+ return null;
+ }
+
+ public class SessionInfo
+ {
+ public string Id { get; set; }
+ public string Uid { get; set; }
+ public string State { get; set; }
+ public DateTime? StartTime { get; set; }
+ }
+
+ public async Task> GetSessionsAsync()
+ {
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
+ try
+ {
+ var _result = await Request.RequestAsync(constCitrixApiSessions, eHttpMethod.get, null);
+ if (_result?.Result == null)
+ return null;
+ var _items = _result.Result?.Items as IEnumerable;
+ if (_items == null)
+ return null;
+ var _retVal = new List();
+ foreach (var item in _items)
+ {
+ try
+ {
+ var _sessionInfo = new SessionInfo()
+ {
+ Id = item.Id?.ToString(),
+ Uid = item.Uid?.ToString(),
+ State = item.State?.ToString(),
+ StartTime = item.StartTime != null ? (DateTime?)item.StartTime : null
+ };
+ _retVal.Add(_sessionInfo);
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ }
+ return _retVal;
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ finally
+ {
+ if (CM != null) LogMethodEnd(CM);
+ }
+ return null;
+ }
+ }
+
+ public class cCitrixCommunicationMonitor
+ {
+ public const string constCitrixCloudUrl = "monitorodata/";
+
+ public const string constCitrixMachineNames = "Machines/?$select=DnsName&$filter=DesktopGroupId+ne+null+and+Name+ne+null";
+ public const string constCitrixUserList = "Users?$select=Id,Sid,Upn,Domain&$filter=Domain ne ''";
+ public const string constCitrixMachineList = "Machines?$select=Id,Sid,DnsName&$filter=DesktopGroupId ne null and Name ne null";
+ public const string constCitrixSessionListDetailed = "Sessions?$select=SessionKey,StartDate,EndDate,ConnectionState, UserId, MachineId&$expand=Machine($select=Id,DnsName,Name)&$filter=EndDate eq null or EndDate gt {0}";
+
+ public int MaxPageSize { get; set; } = 100;
+
+ public cCitrixCommunicationBase Request { get; private set; }
+
+ public cCitrixCommunicationMonitor(cCitrixCommunicationCloudBase CitrixCloud)
+ {
+ this.Request = new cCitrixCommunicationBase(CitrixCloud, constCitrixCloudUrl);
+ }
+
+ public cCitrixCommunicationMonitor(cCitrixCommunicationOnPremMonitor OnPremMonitor)
+ {
+ this.Request = new cCitrixCommunicationBase(OnPremMonitor, null);
+ }
+
+ private string getFormattedDateTime(int DayOffset = 0)
+ {
+ var _dateTime = DateTime.UtcNow.AddDays(DayOffset);
+ var _strDateTime = _dateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
+ return _strDateTime;
+ }
+
+ private string getFormattedGuid(Guid id)
+ {
+ return id.ToString("D");
+ }
+
+ public async Task> GetMachineNamesAsync(CancellationToken token)
+ {
+ var _processor = new ScanEntryStringListProcessor("DnsName", true);
+ var _count = await RequestListAsync(constCitrixMachineList, _processor.ProcessScannedItemAsync, token: token);
+ return _processor.Result;
+ }
+
+ public delegate Task ProcessScanEntryDelegate(dynamic ScanEntry, CancellationToken token);
+
+ public abstract class ScanEntryProcessor
+ {
+ public abstract Task ProcessScannedItemAsync(dynamic _node, CancellationToken token);
+ }
+
+ public class ScanEntryCountProcessor : ScanEntryProcessor
+ {
+ private string nameProperty = null;
+
+ public ScanEntryCountProcessor(string nameProperty)
+ {
+ this.nameProperty = nameProperty;
+ }
+
+ public async override Task ProcessScannedItemAsync(dynamic _node, CancellationToken token)
+ {
+ try
+ {
+ string _prop = cCitrixApiResultBase.GetStringFromDynamic(_node, nameProperty);
+ if (!string.IsNullOrEmpty(_prop))
+ return true;
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
+ return false;
+ }
+
+ }
+
+ public class ScanEntryStringListProcessor : ScanEntryProcessor
+ {
+ private string nameProperty = null;
+ private bool toLowercase = false;
+
+ public List Result = new List();
+
+ public ScanEntryStringListProcessor(string nameProperty, bool toLowercase = false)
+ {
+ this.nameProperty = nameProperty;
+ this.toLowercase = toLowercase;
+ }
+
+ public async override Task ProcessScannedItemAsync(dynamic _node, CancellationToken token)
+ {
+ try
+ {
+ string _prop = cCitrixApiResultBase.GetStringFromDynamic(_node, nameProperty);
+ if (!string.IsNullOrEmpty(_prop))
+ {
+ if (toLowercase)
+ _prop = _prop.ToLowerInvariant();
+ Result.Add(_prop);
+ return true;
}
}
catch (Exception E)
{
- cLogManager.DefaultLogger.LogException(E);
+ LogException(E);
}
+ return false;
}
}
- public class cCitrixResultBase
+ private async Task RequestListAsync(string Url, ProcessScanEntryDelegate ProcessScanEntry, CancellationToken token)
{
- public string ID { get; private set; } = null;
- public string ODataId { get; private set; } = null;
- public string DisplayName { get; private set; } = null;
+ MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
- public string Context { get; private set; } = null;
-
- public dynamic Result { get; private set; } = null;
-
- public cCitrixResultBase(dynamic Result, string namePropery = null)
+ try
{
- this.Result = Result;
-
- try { ID = Result.Id; } catch { }
- ;
- try
+ int countTotal = 0;
+ int skipping = 0;
+ int lastCount = 0;
+ do
{
- if (namePropery == null)
- namePropery = "displayName";
- if (Result.TryGetValue(namePropery, out JToken JT1))
+ lastCount = 0;
+ var _url = Url + $"&$top={MaxPageSize}&$skip={skipping}";
+ var _result = await Request.RequestAsync(_url, eHttpMethod.get, null, token: token);
+ if (_result == null || _result.Result == null)
+ return -1;
+
+ var _items = _result.Result?.value as IEnumerable;
+
+ if (_items == null)
+ return -1;
+
+ foreach (var item in _items)
{
- var _ty = JT1.GetType().ToString();
- if (JT1 is JValue _jVal)
- DisplayName = _jVal.Value?.ToString();
+ try
+ {
+ var _item = item as dynamic;
+ var _ok = await ProcessScanEntry(_item, token);
+ if (token.IsCancellationRequested)
+ return 0;
+ if (_ok)
+ {
+ lastCount++;
+ countTotal++;
+ }
+ }
+ catch (Exception E)
+ {
+ LogException(E);
+ }
}
- else if (Result.TryGetValue("name", out JToken JT2))
- DisplayName = Result.name;
- }
- catch { }
- try { Context = Result["@odata.context"]; } catch { }
- ODataId = GetStringFromDynamic(Result, "@odata.id");
- if (string.IsNullOrEmpty(ODataId))
- ODataId = @"https://api.cloud.com/" + ID;
- }
- public cCitrixResultBase(cCitrixResultBase Result)
+ skipping += lastCount;
+ } while (lastCount >= MaxPageSize);
+
+ return countTotal;
+ }
+ catch (Exception E)
{
- if (Result == null)
- return;
-
- this.Result = Result.Result;
- ID = Result.ID;
- ODataId = Result.ODataId;
- DisplayName = Result.DisplayName;
- Context = Result.Context;
+ LogException(E);
}
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static string GetStringFromDynamic(dynamic O, string ProperyName)
+ finally
{
- try
- {
- return (string)O[ProperyName];
- }
- catch { }
- return null;
+ if (CM != null) LogMethodEnd(CM);
}
+
+ return -1;
+ }
+
+ public async Task ScanUsersAsync(ScanEntryProcessor _processor, CancellationToken token)
+ {
+ return await RequestListAsync(constCitrixUserList, _processor.ProcessScannedItemAsync, token);
+ }
+
+ public async Task ScanMachinesAsync(ScanEntryProcessor _processor, CancellationToken token)
+ {
+ return await RequestListAsync(constCitrixMachineList, _processor.ProcessScannedItemAsync, token);
+ }
+
+ public async Task ScanSessionsAsync(ScanEntryProcessor _processor, int DayOffset, CancellationToken token)
+ {
+ var _url = string.Format(constCitrixSessionListDetailed, getFormattedDateTime(DayOffset));
+ return await RequestListAsync(_url, _processor.ProcessScannedItemAsync, token);
}
}
-}
+}
\ No newline at end of file
diff --git a/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs b/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs
index 543227b..a9863dc 100644
--- a/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs
+++ b/F4SD-Cockpit-ServerCore/DataHistoryCollector.cs
@@ -2,7 +2,11 @@
using System.Collections.Generic;
using System.Data.Common;
using System.Diagnostics;
+using System.DirectoryServices.AccountManagement;
+using System.DirectoryServices.ActiveDirectory;
using System.Globalization;
+using System.IdentityModel.Tokens.Jwt;
+using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
@@ -13,28 +17,26 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
-using System.IdentityModel.Tokens.Jwt;
-using System.DirectoryServices.AccountManagement;
-using System.DirectoryServices.ActiveDirectory;
-using System.IO;
-using Microsoft.IdentityModel.Tokens;
-
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-
-using C4IT.Configuration;
+using C4IT.DataHistoryProvider.Base.Modules.Citrix;
using C4IT.FASD.Base;
using C4IT.FASD.Licensing;
using C4IT.Logging;
+using C4IT.Matrix42.WebClient;
using C4IT.Security;
using C4IT.XML;
-using C4IT.Matrix42.WebClient;
using C4IT_DataHistoryProvider_Base;
using C4IT_DataHistoryProvider_Base.DataSources;
using C4IT_DataHistoryProvider_Base.Services;
+using Microsoft.Extensions.Logging;
+using Microsoft.IdentityModel.Tokens;
+
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+using static C4IT.FASD.Base.cF4sdQuickActionRevision;
using static C4IT.Logging.cLogManager;
@@ -105,7 +107,18 @@ namespace C4IT.DataHistoryProvider
public abstract Task DoScanAsync(bool Always, bool Rescan, cF4sdWebRequestInfo requestInfo, int LogDeep, CancellationToken Token, bool EnhancedDebug = false);
- public abstract Task> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep);
+ public virtual async Task> GetIds(cF4sdConnectorIds IdEntry, enumFasdInformationClass InfoClass, cF4sdWebRequestInfo requestInfo, int LogDeep)
+ {
+ await Task.CompletedTask;
+ if (IdEntry.sid == null)
+ return null;
+ return new List