From a7ee79fb882c31a1b2196bad476e937b0fcbb4d5 Mon Sep 17 00:00:00 2001 From: vfedosevich Date: Sun, 14 Apr 2013 17:16:12 +0300 Subject: [PATCH] Lync 2013 support --- WebsitePanel/Database/update_db.sql | 8 + .../HostedSolution}/LyncTransaction.cs | 74 +- .../WebsitePanel.Providers.Base.csproj | 2 + .../Lync2013.cs | 721 ++++++++++++++++++ .../LyncBase.cs | 611 +++++++++++++++ .../Properties/AssemblyInfo.cs | 36 + ...l.Providers.HostedSolution.Lync2013.csproj | 75 ++ .../HostedSolutionLog.cs | 2 +- ...bsitePanel.Providers.HostedSolution.csproj | 1 - WebsitePanel/Sources/WebsitePanel.Server.sln | 12 + 10 files changed, 1501 insertions(+), 41 deletions(-) rename WebsitePanel/Sources/{WebsitePanel.Providers.HostedSolution => WebsitePanel.Providers.Base/HostedSolution}/LyncTransaction.cs (50%) create mode 100644 WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Lync2013.cs create mode 100644 WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/LyncBase.cs create mode 100644 WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Properties/AssemblyInfo.cs create mode 100644 WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/WebsitePanel.Providers.HostedSolution.Lync2013.csproj diff --git a/WebsitePanel/Database/update_db.sql b/WebsitePanel/Database/update_db.sql index 31f110b4..c5a40d7f 100644 --- a/WebsitePanel/Database/update_db.sql +++ b/WebsitePanel/Database/update_db.sql @@ -433,6 +433,7 @@ GO UPDATE Providers SET ProviderType = N'WebsitePanel.Providers.HostedSolution.CRMProvider2011, WebsitePanel.Providers.HostedSolution.CRM2011' WHERE ProviderID = 1201 GO + IF NOT EXISTS (SELECT * FROM [dbo].[Providers] WHERE [DisplayName] = 'Hosted SharePoint Foundation 2013') BEGIN INSERT [dbo].[Providers] ([ProviderID], [GroupID], [ProviderName], [DisplayName], [ProviderType], [EditorControl], [DisableAutoDiscovery]) @@ -441,4 +442,11 @@ END GO UPDATE Providers SET ProviderType = N'WebsitePanel.Providers.HostedSolution.HostedSharePointServer2013, WebsitePanel.Providers.HostedSolution.SharePoint2013' WHERE ProviderID = 1301 +GO + +IF NOT EXISTS (SELECT * FROM [dbo].[Providers] WHERE [ProviderName] = 'Lync2013') +BEGIN +INSERT [dbo].[Providers] ([ProviderID], [GroupID], [ProviderName], [DisplayName], [ProviderType], [EditorControl], [DisableAutoDiscovery]) +VALUES (1401, 41, N'Lync2013', N'Microsoft Lync Server 2013 Multitenant Hosting Pack', N'WebsitePanel.Providers.HostedSolution.Lync2013, WebsitePanel.Providers.HostedSolution.Lync2013', N'Lync', NULL) +END GO \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/LyncTransaction.cs b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/LyncTransaction.cs similarity index 50% rename from WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/LyncTransaction.cs rename to WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/LyncTransaction.cs index 811a93ec..6fa9fc99 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/LyncTransaction.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/HostedSolution/LyncTransaction.cs @@ -30,68 +30,64 @@ using System.Collections.Generic; namespace WebsitePanel.Providers.HostedSolution { - internal class LyncTransaction + public class LyncTransaction { - List actions = null; + #region Fields + + private readonly List actions; + + #endregion + + #region Properties + + public List Actions + { + get { return actions; } + } + + #endregion + + #region Constructor public LyncTransaction() { actions = new List(); } - internal List Actions + #endregion + + #region Methods + + public void RegisterNewSipDomain(string id) { - get { return actions; } + Actions.Add(new TransactionAction { ActionType = TransactionAction.TransactionActionTypes.LyncNewSipDomain, Id = id }); } - internal void RegisterNewSipDomain(string id) + public void RegisterNewSimpleUrl(string sipDomain, string tenantID) { - TransactionAction action = new TransactionAction(); - action.ActionType = TransactionAction.TransactionActionTypes.LyncNewSipDomain; - action.Id = id; - Actions.Add(action); + Actions.Add(new TransactionAction { ActionType = TransactionAction.TransactionActionTypes.LyncNewSimpleUrl, Id = sipDomain, Account = tenantID }); } - internal void RegisterNewSimpleUrl(string sipDomain, string tenantID) + public void RegisterNewConferencingPolicy(string id) { - TransactionAction action = new TransactionAction(); - action.ActionType = TransactionAction.TransactionActionTypes.LyncNewSimpleUrl; - action.Id = sipDomain; - action.Account = tenantID; - Actions.Add(action); + Actions.Add(new TransactionAction { ActionType = TransactionAction.TransactionActionTypes.LyncNewConferencingPolicy, Id = id }); } - - internal void RegisterNewConferencingPolicy(string id) + public void RegisterNewCsExternalAccessPolicy(string id) { - TransactionAction action = new TransactionAction(); - action.ActionType = TransactionAction.TransactionActionTypes.LyncNewConferencingPolicy; - action.Id = id; - Actions.Add(action); + Actions.Add(new TransactionAction { ActionType = TransactionAction.TransactionActionTypes.LyncNewExternalAccessPolicy, Id = id }); } - internal void RegisterNewCsExternalAccessPolicy(string id) + public void RegisterNewCsMobilityPolicy(string id) { - TransactionAction action = new TransactionAction(); - action.ActionType = TransactionAction.TransactionActionTypes.LyncNewExternalAccessPolicy; - action.Id = id; - Actions.Add(action); + Actions.Add(new TransactionAction { ActionType = TransactionAction.TransactionActionTypes.LyncNewMobilityPolicy, Id = id }); } - internal void RegisterNewCsMobilityPolicy(string id) + public void RegisterNewCsUser(string id) { - TransactionAction action = new TransactionAction(); - action.ActionType = TransactionAction.TransactionActionTypes.LyncNewMobilityPolicy; - action.Id = id; - Actions.Add(action); + Actions.Add(new TransactionAction { ActionType = TransactionAction.TransactionActionTypes.LyncNewUser, Id = id }); } - internal void RegisterNewCsUser(string id) - { - TransactionAction action = new TransactionAction(); - action.ActionType = TransactionAction.TransactionActionTypes.LyncNewUser; - action.Id = id; - Actions.Add(action); - } + #endregion } -} +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj index 51aff26b..dd588836 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Providers.Base/WebsitePanel.Providers.Base.csproj @@ -63,6 +63,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Lync2013.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Lync2013.cs new file mode 100644 index 00000000..d09bd031 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Lync2013.cs @@ -0,0 +1,721 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.DirectoryServices; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Runspaces; +using Microsoft.Rtc.Management.WritableConfig.Settings.Edge; + +namespace WebsitePanel.Providers.HostedSolution +{ + public class Lync2013 : LyncBase + { + #region Constructor + + static Lync2013() + { + LyncRegistryPath = "SOFTWARE\\Microsoft\\Real-Time Communications"; + LyncVersion = "5"; + } + + #endregion + + #region Methods + + #region Organizations + + /// Creates organization. + /// The organization identifier. + /// The sip domain. + /// True - if conferencing video should be enabled. + /// The max conference size. + /// True - if federations should be enabled. + /// True - if enterprise voice should be enabled. + /// The tenant identifier. + internal override string CreateOrganizationInternal(string organizationId, string sipDomain, bool enableConferencingVideo, int maxConferenceSize, bool enabledFederation, bool enabledEnterpriseVoice) + { + sipDomain = sipDomain.ToLower(); + HostedSolutionLog.LogStart("CreateOrganizationInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + HostedSolutionLog.DebugInfo("sipDomain: {0}", sipDomain); + string tenantId; + LyncTransaction transaction = StartTransaction(); + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + var command = new Command("New-CsSipDomain"); + command.Parameters.Add("Identity", sipDomain); + ExecuteShellCommand(runspace, command, false); + transaction.RegisterNewSipDomain(sipDomain); + Guid id = Guid.NewGuid(); + + AddAdDomainName(organizationId, sipDomain); + + CreateSimpleUrl(runspace, id); + transaction.RegisterNewSimpleUrl(sipDomain, id.ToString()); + + command = new Command("New-CsConferencingPolicy"); + command.Parameters.Add("Identity", organizationId); + command.Parameters.Add("MaxMeetingSize", ((maxConferenceSize == -1) | (maxConferenceSize > 250)) ? 250 : maxConferenceSize); + command.Parameters.Add("AllowIPVideo", enableConferencingVideo); + ExecuteShellCommand(runspace, command, false); + transaction.RegisterNewConferencingPolicy(organizationId); + + command = new Command("New-CsExternalAccessPolicy"); + command.Parameters.Add("Identity", organizationId); + command.Parameters.Add("EnableFederationAccess", true); + command.Parameters.Add("EnableOutsideAccess", true); + command.Parameters.Add("EnablePublicCloudAccess", false); + command.Parameters.Add("EnablePublicCloudAudioVideoAccess", false); + ExecuteShellCommand(runspace, command, false); + transaction.RegisterNewCsExternalAccessPolicy(organizationId); + + var allowList = new AllowList(); + var domain = new DomainPattern(sipDomain); + allowList.AllowedDomain.Add(domain); + + AddFederationDomainInternal("", domain.Domain, PoolFQDN); + + command = new Command("New-CsMobilityPolicy"); + command.Parameters.Add("Identity", organizationId + " EnableOutSideVoice"); + command.Parameters.Add("EnableMobility", true); + command.Parameters.Add("EnableOutsideVoice", true); + ExecuteShellCommand(runspace, command, false); + transaction.RegisterNewCsMobilityPolicy(organizationId + " EnableOutSideVoice"); + + command = new Command("New-CsMobilityPolicy"); + command.Parameters.Add("Identity", organizationId + " DisableOutSideVoice"); + command.Parameters.Add("EnableMobility", true); + command.Parameters.Add("EnableOutsideVoice", false); + ExecuteShellCommand(runspace, command, false); + transaction.RegisterNewCsMobilityPolicy(organizationId + " DisableOutSideVoice"); + + command = new Command("Invoke-CsManagementStoreReplication"); + ExecuteShellCommand(runspace, command, false); + + tenantId = id.ToString(); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("CreateOrganizationInternal", ex); + RollbackTransaction(transaction); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("CreateOrganizationInternal"); + + return tenantId; + } + + /// Deletes organization. + /// The organization identifier. + /// The sip domain. + /// The result. + internal override bool DeleteOrganizationInternal(string organizationId, string sipDomain) + { + HostedSolutionLog.LogStart("DeleteOrganizationInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + HostedSolutionLog.DebugInfo("sipDomain: {0}", sipDomain); + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + string path = AddADPrefix(GetOrganizationPath(organizationId)); + DirectoryEntry ou = ActiveDirectoryUtils.GetADObject(path); + string[] sipDs = ActiveDirectoryUtils.GetADObjectPropertyMultiValue(ou, "Url"); + + foreach (string sipD in sipDs) + { + DeleteSipDomain(runspace, sipD); + } + + try + { + DeleteConferencingPolicy(runspace, organizationId); + } + catch (Exception) + { + } + + try + { + DeleteExternalAccessPolicy(runspace, organizationId); + } + catch (Exception) + { + } + + try + { + DeleteMobilityPolicy(runspace, organizationId + " EnableOutSideVoice"); + } + catch (Exception) + { + } + + try + { + DeleteMobilityPolicy(runspace, organizationId + " DisableOutSideVoice"); + } + catch (Exception) + { + } + + var command = new Command("Invoke-CsManagementStoreReplication"); + ExecuteShellCommand(runspace, command, false); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("DeleteOrganizationInternal", ex); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("DeleteOrganizationInternal"); + + return true; + } + + #endregion + + #region Users + + /// Creates the user. + /// The organization identifier. + /// The user UPN. + /// The Lync user plan. + /// The result. + internal override bool CreateUserInternal(string organizationId, string userUpn, LyncUserPlan plan) + { + HostedSolutionLog.LogStart("CreateUserInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + HostedSolutionLog.DebugInfo("userUpn: {0}", userUpn); + LyncTransaction transaction = StartTransaction(); + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + Guid guid = GetObjectGuid(organizationId, runspace); + string[] tmp = userUpn.Split('@'); + + if (tmp.Length < 2) + { + return false; + } + + var command = new Command("Get-CsSipDomain"); + Collection sipDomains = ExecuteShellCommand(runspace, command, false); + bool bSipDomainExists = sipDomains.Select(domain => (string) GetPSObjectProperty(domain, "Name")).Any(d => d.ToLower() == tmp[1].ToLower()); + + if (!bSipDomainExists) + { + command = new Command("New-CsSipDomain"); + command.Parameters.Add("Identity", tmp[1].ToLower()); + ExecuteShellCommand(runspace, command, false); + transaction.RegisterNewSipDomain(tmp[1].ToLower()); + AddAdDomainName(organizationId, tmp[1].ToLower()); + CreateSimpleUrl(runspace, guid); + transaction.RegisterNewSimpleUrl(tmp[1].ToLower(), guid.ToString()); + } + + command = new Command("Enable-CsUser"); + command.Parameters.Add("Identity", userUpn); + command.Parameters.Add("RegistrarPool", PoolFQDN); + command.Parameters.Add("SipAddressType", "UserPrincipalName"); + ExecuteShellCommand(runspace, command, false); + transaction.RegisterNewCsUser(userUpn); + + command = new Command("Get-CsAdUser"); + command.Parameters.Add("Identity", userUpn); + ExecuteShellCommand(runspace, command, false); + + SetLyncUserPlanInternal(organizationId, userUpn, plan, runspace); + command = new Command("Update-CsAddressBook"); + ExecuteShellCommand(runspace, command, false); + command = new Command("Update-CsUserDatabase"); + ExecuteShellCommand(runspace, command, false); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("CreateUserInternal", ex); + RollbackTransaction(transaction); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("CreateUserInternal"); + + return true; + } + + /// Gets users general settings. + /// The organization identifier. + /// The user UPN. + /// User settings. + internal override LyncUser GetLyncUserGeneralSettingsInternal(string organizationId, string userUpn) + { + HostedSolutionLog.LogStart("GetLyncUserGeneralSettingsInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + HostedSolutionLog.DebugInfo("userUpn: {0}", userUpn); + var lyncUser = new LyncUser(); + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + + var command = new Command("Get-CsUser"); + command.Parameters.Add("Identity", userUpn); + Collection result = ExecuteShellCommand(runspace, command, false); + PSObject user = result[0]; + + lyncUser.DisplayName = (string) GetPSObjectProperty(user, "DisplayName"); + lyncUser.SipAddress = (string) GetPSObjectProperty(user, "SipAddress"); + lyncUser.LineUri = (string) GetPSObjectProperty(user, "LineURI"); + + lyncUser.SipAddress = lyncUser.SipAddress.ToLower().Replace("sip:", ""); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("GetLyncUserGeneralSettingsInternal", ex); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("GetLyncUserGeneralSettingsInternal"); + + return lyncUser; + } + + /// Sets users general settings. + /// The organization identifier. + /// The user UPN. + /// The lync user settings. + /// The result. + internal override bool SetLyncUserGeneralSettingsInternal(string organizationId, string userUpn, LyncUser lyncUser) + { + HostedSolutionLog.LogStart("SetLyncUserGeneralSettingsInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + HostedSolutionLog.DebugInfo("userUpn: {0}", userUpn); + + bool ret = true; + Runspace runspace = null; + LyncTransaction transaction = StartTransaction(); + + try + { + runspace = OpenRunspace(); + Guid tenantId = GetObjectGuid(organizationId, runspace); + string[] tmp = userUpn.Split('@'); + + if (tmp.Length < 2) + { + return false; + } + + var command = new Command("Get-CsSipDomain"); + Collection sipDomains = ExecuteShellCommand(runspace, command, false); + bool bSipDomainExists = sipDomains.Select(domain => (string) GetPSObjectProperty(domain, "Name")).Any(d => d.ToLower() == tmp[1].ToLower()); + + if (!bSipDomainExists) + { + command = new Command("New-CsSipDomain"); + command.Parameters.Add("Identity", tmp[1].ToLower()); + ExecuteShellCommand(runspace, command, false); + + transaction.RegisterNewSipDomain(tmp[1].ToLower()); + + string path = AddADPrefix(GetOrganizationPath(organizationId)); + DirectoryEntry ou = ActiveDirectoryUtils.GetADObject(path); + string[] sipDs = ActiveDirectoryUtils.GetADObjectPropertyMultiValue(ou, "Url"); + var listSipDs = new List(); + listSipDs.AddRange(sipDs); + listSipDs.Add(tmp[1]); + + ActiveDirectoryUtils.SetADObjectPropertyValue(ou, "Url", listSipDs.ToArray()); + ou.CommitChanges(); + + CreateSimpleUrl(runspace, tenantId); + transaction.RegisterNewSimpleUrl(tmp[1].ToLower(), tenantId.ToString()); + + path = AddADPrefix(GetResultObjectDN(organizationId, runspace)); + DirectoryEntry user = ActiveDirectoryUtils.GetADObject(path); + + if (tmp.Length > 0) + { + string Url = SimpleUrlRoot + tmp[1]; + ActiveDirectoryUtils.SetADObjectPropertyValue(user, "msRTCSIP-BaseSimpleUrl", Url.ToLower()); + } + + user.CommitChanges(); + } + + command = new Command("Set-CsUser"); + command.Parameters.Add("Identity", userUpn); + + if (!string.IsNullOrEmpty(lyncUser.SipAddress)) + { + command.Parameters.Add("SipAddress", "SIP:" + lyncUser.SipAddress); + } + + if (!string.IsNullOrEmpty(lyncUser.SipAddress)) + { + command.Parameters.Add("LineUri", lyncUser.LineUri); + } + + ExecuteShellCommand(runspace, command, false); + + command = new Command("Update-CsAddressBook"); + ExecuteShellCommand(runspace, command, false); + + command = new Command("Update-CsUserDatabase"); + ExecuteShellCommand(runspace, command, false); + } + catch (Exception ex) + { + ret = false; + HostedSolutionLog.LogError("SetLyncUserGeneralSettingsInternal", ex); + RollbackTransaction(transaction); + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("SetLyncUserGeneralSettingsInternal"); + + return ret; + } + + /// Sets users lync plan. + /// The organization identifier. + /// The user UPN. + /// The lync plan. + /// The runspace. + /// The result. + internal override bool SetLyncUserPlanInternal(string organizationId, string userUpn, LyncUserPlan plan, Runspace runspace) + { + HostedSolutionLog.LogStart("SetLyncUserPlanInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + HostedSolutionLog.DebugInfo("userUpn: {0}", userUpn); + bool bCloseRunSpace = false; + + try + { + if (runspace == null) + { + runspace = OpenRunspace(); + bCloseRunSpace = true; + } + + var command = new Command("Grant-CsExternalAccessPolicy"); + command.Parameters.Add("Identity", userUpn); + command.Parameters.Add("PolicyName", plan.Federation ? organizationId : null); + ExecuteShellCommand(runspace, command, false); + + command = new Command("Grant-CsConferencingPolicy"); + command.Parameters.Add("Identity", userUpn); + command.Parameters.Add("PolicyName", plan.Federation ? organizationId : null); + ExecuteShellCommand(runspace, command, false); + + command = new Command("Grant-CsMobilityPolicy"); + command.Parameters.Add("Identity", userUpn); + + if (plan.Mobility) + { + command.Parameters.Add("PolicyName", plan.MobilityEnableOutsideVoice ? organizationId + " EnableOutSideVoice" : organizationId + " DisableOutSideVoice"); + } + else + { + command.Parameters.Add("PolicyName", null); + } + + ExecuteShellCommand(runspace, command, false); + command = new Command("Update-CsUserDatabase"); + ExecuteShellCommand(runspace, command, false); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("SetLyncUserPlanInternal", ex); + throw; + } + finally + { + if (bCloseRunSpace) + { + CloseRunspace(runspace); + } + } + + HostedSolutionLog.LogEnd("SetLyncUserPlanInternal"); + + return true; + } + + /// Deletes user. + /// The user UPN. + /// The result. + internal override bool DeleteUserInternal(string userUpn) + { + HostedSolutionLog.LogStart("DeleteUserInternal"); + HostedSolutionLog.DebugInfo("userUpn: {0}", userUpn); + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + DeleteUser(runspace, userUpn); + + var command = new Command("Get-CsAdUser"); + command.Parameters.Add("Identity", userUpn); + ExecuteShellCommand(runspace, command, false); + + command = new Command("Update-CsAddressBook"); + ExecuteShellCommand(runspace, command, false); + + command = new Command("Update-CsUserDatabase"); + ExecuteShellCommand(runspace, command, false); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("DeleteUserInternal", ex); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("DeleteUserInternal"); + + return true; + } + + #endregion + + #region Sytsem Related Methods + + /// Refreshes configuration. + internal override void ReloadConfigurationInternal() + { + HostedSolutionLog.LogStart("ReloadConfigurationInternal"); + Runspace runspace = null; + try + { + runspace = OpenRunspace(); + + var command = new Command("Enable-CsComputer"); + ExecuteShellCommand(runspace, command, false); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("ReloadConfigurationInternal", ex); + throw; + } + finally + { + CloseRunspace(runspace); + } + HostedSolutionLog.LogEnd("ReloadConfigurationInternal"); + } + + #endregion + + #region Federation Domains + + /// Gets allowed domains. + /// The organization identifier. + /// Allowed domains. + internal override LyncFederationDomain[] GetFederationDomainsInternal(string organizationId) + { + HostedSolutionLog.LogStart("GetFederationDomainsInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + LyncFederationDomain[] domains; + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + domains = GetFederationDomainsInternal(runspace); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("GetFederationDomainsInternal", ex); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("GetFederationDomainsInternal"); + + return domains; + } + + /// Gets allowed domains. + /// The runspace. + /// Allowed domains. + private LyncFederationDomain[] GetFederationDomainsInternal(Runspace runspace) + { + var domains = new List(); + var command = new Command("Get-CsAllowedDomain"); + Collection result = ExecuteShellCommand(runspace, command, false); + + if ((result != null) && (result.Count > 0)) + { + domains = result.Select(psObject => new LyncFederationDomain {DomainName = psObject.Properties["Domain"].Value.ToString()}).ToList(); + } + + return domains.ToArray(); + } + + /// Adds domain to allowed list. + /// The organization identifier. + /// The domain name. + /// The ProxyFQDN. + /// The result. + internal override bool AddFederationDomainInternal(string organizationId, string domainName, string proxyFqdn) + { + domainName = domainName.ToLower(); + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + var command = new Command("Get-CsAllowedDomain"); + command.Parameters.Add("Identity", domainName); + Collection result = ExecuteShellCommand(runspace, command, false); + + if (result != null && !result.Any()) + { + command = new Command("New-CsAllowedDomain"); + command.Parameters.Add("Identity", domainName); + ExecuteShellCommand(runspace, command, false); + + command = new Command("Set-CsAllowedDomain"); + command.Parameters.Add("Identity", domainName); + command.Parameters.Add("ProxyFQDN", PoolFQDN); + ExecuteShellCommand(runspace, command, false); + } + } + catch (Exception ex) + { + HostedSolutionLog.LogError("AddFederationDomainInternal", ex); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("AddFederationDomainInternal"); + + return true; + } + + /// Removes domain from allowed list. + /// The organization identifier. + /// The domain name. + /// The result. + internal override bool RemoveFederationDomainInternal(string organizationId, string domainName) + { + HostedSolutionLog.LogStart("RemoveFederationDomainInternal"); + HostedSolutionLog.DebugInfo("organizationId: {0}", organizationId); + HostedSolutionLog.DebugInfo("domainName: {0}", domainName); + Runspace runspace = null; + + try + { + runspace = OpenRunspace(); + var command = new Command("Remove-CsAllowedDomain"); + command.Parameters.Add("Identity", domainName); + ExecuteShellCommand(runspace, command, false); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("RemoveFederationDomainInternal", ex); + throw; + } + finally + { + CloseRunspace(runspace); + } + + HostedSolutionLog.LogEnd("RemoveFederationDomainInternal"); + + return true; + } + + /// Gets organization lync identifier. + /// The organization identifier. + /// The runspace. + /// Organization lync identifier. + private Guid GetObjectGuid(string organizationId, Runspace runspace) + { + string path = GetOrganizationPath(organizationId); + var scripts = new List {string.Format("Get-ADOrganizationalUnit -Identity \"{0}\"", path)}; + Collection result = ExecuteShellCommand(runspace, scripts); + + if (result != null && result.Any()) + { + return new Guid(result.First().Properties["ObjectGuid"].Value.ToString()); + } + + return Guid.NewGuid(); + } + + /// Gets organization distinguished name. + /// The organization identifier. + /// The runspace. + /// The distinguished name. + private string GetResultObjectDN(string organizationId, Runspace runspace) + { + HostedSolutionLog.LogStart("GetResultObjectDN"); + + string path = GetOrganizationPath(organizationId); + var scripts = new List {string.Format("Get-ADOrganizationalUnit -Identity \"{0}\"", path)}; + Collection result = ExecuteShellCommand(runspace, scripts); + + if (result != null && result.Any()) + { + return result.First().Properties["DistinguishedName"].Value.ToString(); + } + + throw new ArgumentException("Execution result does not contain DistinguishedName property"); + } + + /// Adds domain to AD. + /// The organization identifier. + /// The domain name. + private void AddAdDomainName(string organizationId, string domainName) + { + string path = AddADPrefix(GetOrganizationPath(organizationId)); + DirectoryEntry ou = ActiveDirectoryUtils.GetADObject(path); + ActiveDirectoryUtils.SetADObjectPropertyValue(ou, "Url", new[] {domainName}); + ou.CommitChanges(); + } + + #endregion + + #endregion + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/LyncBase.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/LyncBase.cs new file mode 100644 index 00000000..0b62181d --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/LyncBase.cs @@ -0,0 +1,611 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Management.Automation; +using System.Management.Automation.Runspaces; +using System.Text; +using Microsoft.Win32; + +namespace WebsitePanel.Providers.HostedSolution +{ + public class LyncBase : HostingServiceProviderBase, ILyncServer + { + #region Fields + + private static InitialSessionState session; + + #endregion + + #region Properties + + internal static string LyncRegistryPath { get; set; } + internal static string LyncVersion { get; set; } + + internal string PoolFQDN + { + get { return ProviderSettings[LyncConstants.PoolFQDN]; } + } + + internal string SimpleUrlRoot + { + get { return ProviderSettings[LyncConstants.SimpleUrlRoot]; } + } + + internal string PrimaryDomainController + { + get { return ProviderSettings["PrimaryDomainController"]; } + } + + internal string RootOU + { + get { return ProviderSettings["RootOU"]; } + } + + internal string RootDomain + { + get { return ServerSettings.ADRootDomain; } + } + + #endregion + + #region Methods + + public string CreateOrganization(string organizationId, string sipDomain, bool enableConferencing, bool enableConferencingVideo, int maxConferenceSize, bool enabledFederation, bool enabledEnterpriseVoice) + { + return CreateOrganizationInternal(organizationId, sipDomain, enableConferencingVideo, maxConferenceSize, enabledFederation, enabledEnterpriseVoice); + } + + public virtual bool DeleteOrganization(string organizationId, string sipDomain) + { + return DeleteOrganizationInternal(organizationId, sipDomain); + } + + public virtual bool CreateUser(string organizationId, string userUpn, LyncUserPlan plan) + { + return CreateUserInternal(organizationId, userUpn, plan); + } + + public virtual LyncUser GetLyncUserGeneralSettings(string organizationId, string userUpn) + { + return GetLyncUserGeneralSettingsInternal(organizationId, userUpn); + } + + public virtual bool SetLyncUserGeneralSettings(string organizationId, string userUpn, LyncUser lyncUser) + { + return SetLyncUserGeneralSettingsInternal(organizationId, userUpn, lyncUser); + } + + public virtual bool SetLyncUserPlan(string organizationId, string userUpn, LyncUserPlan plan) + { + return SetLyncUserPlanInternal(organizationId, userUpn, plan, null); + } + + public virtual bool DeleteUser(string userUpn) + { + return DeleteUserInternal(userUpn); + } + + public virtual LyncFederationDomain[] GetFederationDomains(string organizationId) + { + return GetFederationDomainsInternal(organizationId); + } + + public virtual bool AddFederationDomain(string organizationId, string domainName, string proxyFqdn) + { + return AddFederationDomainInternal(organizationId, domainName, proxyFqdn); + } + + public virtual bool RemoveFederationDomain(string organizationId, string domainName) + { + return RemoveFederationDomainInternal(organizationId, domainName); + } + + public virtual void ReloadConfiguration() + { + ReloadConfigurationInternal(); + } + + public override bool IsInstalled() + { + bool bResult = false; + RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(LyncRegistryPath); + + if (registryKey != null) + { + var value = (string) registryKey.GetValue("ProductVersion", null); + + if (value.StartsWith(LyncVersion)) + { + bResult = true; + } + + registryKey.Close(); + } + + return bResult; + } + + internal virtual string CreateOrganizationInternal(string organizationId, string sipDomain, bool enableConferencingVideo, int maxConferenceSize, bool enabledFederation, bool enabledEnterpriseVoice) + { + throw new NotImplementedException(); + } + + internal virtual bool DeleteOrganizationInternal(string organizationId, string sipDomain) + { + throw new NotImplementedException(); + } + + internal virtual bool CreateUserInternal(string organizationId, string userUpn, LyncUserPlan plan) + { + throw new NotImplementedException(); + } + + internal virtual LyncUser GetLyncUserGeneralSettingsInternal(string organizationId, string userUpn) + { + throw new NotImplementedException(); + } + + internal virtual bool SetLyncUserGeneralSettingsInternal(string organizationId, string userUpn, LyncUser lyncUser) + { + throw new NotImplementedException(); + } + + internal virtual bool SetLyncUserPlanInternal(string organizationId, string userUpn, LyncUserPlan plan, Runspace runspace) + { + throw new NotImplementedException(); + } + + internal virtual bool DeleteUserInternal(string userUpn) + { + throw new NotImplementedException(); + } + + internal virtual LyncFederationDomain[] GetFederationDomainsInternal(string organizationId) + { + throw new NotImplementedException(); + } + + internal virtual bool AddFederationDomainInternal(string organizationId, string domainName, string proxyFqdn) + { + throw new NotImplementedException(); + } + + internal virtual bool RemoveFederationDomainInternal(string organizationId, string domainName) + { + throw new NotImplementedException(); + } + + internal virtual void ReloadConfigurationInternal() + { + throw new NotImplementedException(); + } + + #region PowerShell integration + + /// Opens runspace. + /// The runspace. + internal Runspace OpenRunspace() + { + HostedSolutionLog.LogStart("OpenRunspace"); + + if (session == null) + { + session = InitialSessionState.CreateDefault(); + session.ImportPSModule(new[] {"ActiveDirectory", "Lync"}); + } + + Runspace runspace = RunspaceFactory.CreateRunspace(session); + runspace.Open(); + runspace.SessionStateProxy.SetVariable("ConfirmPreference", "none"); + HostedSolutionLog.LogEnd("OpenRunspace"); + + return runspace; + } + + /// Closes runspace. + /// The runspace. + internal void CloseRunspace(Runspace runspace) + { + try + { + if (runspace != null && runspace.RunspaceStateInfo.State == RunspaceState.Opened) + { + runspace.Close(); + } + } + catch (Exception ex) + { + HostedSolutionLog.LogError("Runspace error", ex); + } + } + + /// Executes shell command. + /// The runspace. + /// Scripts list. + /// The result. + internal Collection ExecuteShellCommand(Runspace runspace, List scripts) + { + object[] errors; + return ExecuteShellCommand(runspace, scripts, out errors); + } + + /// Executes shell command. + /// The runspace. + /// The command. + /// True - if domain controller should be used. + /// The result. + internal Collection ExecuteShellCommand(Runspace runspace, Command command, bool useDomainController) + { + object[] errors; + return ExecuteShellCommand(runspace, command, useDomainController, out errors); + } + + /// Executes shell command. + /// The runspace. + /// The command. + /// Errors list. + /// The result. + internal Collection ExecuteShellCommand(Runspace runspace, Command command, out object[] errors) + { + return ExecuteShellCommand(runspace, command, true, out errors); + } + + /// Executes shell command. + /// The runspace. + /// The command. + /// True - if domain controller should be used. + /// Errors list. + /// The result. + internal Collection ExecuteShellCommand(Runspace runspace, Command command, bool useDomainController, out object[] errors) + { + HostedSolutionLog.LogStart("ExecuteShellCommand"); + var errorList = new List(); + + if (useDomainController) + { + var dc = new CommandParameter("DomainController", PrimaryDomainController); + if (!command.Parameters.Contains(dc)) + { + command.Parameters.Add(dc); + } + } + + HostedSolutionLog.DebugCommand(command); + Collection results; + Pipeline pipeLine = runspace.CreatePipeline(); + + using (pipeLine) + { + pipeLine.Commands.Add(command); + results = pipeLine.Invoke(); + + if (pipeLine.Error != null && pipeLine.Error.Count > 0) + { + foreach (object item in pipeLine.Error.ReadToEnd()) + { + errorList.Add(item); + string errorMessage = string.Format("Invoke error: {0}", item); + HostedSolutionLog.LogWarning(errorMessage); + } + } + } + + errors = errorList.ToArray(); + HostedSolutionLog.LogEnd("ExecuteShellCommand"); + + return results; + } + + /// Executes shell command. + /// The runspace. + /// Scripts list. + /// Errors list. + /// The result. + internal Collection ExecuteShellCommand(Runspace runspace, List scripts, out object[] errors) + { + HostedSolutionLog.LogStart("ExecuteShellCommand"); + var errorList = new List(); + Collection results; + + using (Pipeline pipeLine = runspace.CreatePipeline()) + { + foreach (string script in scripts) + { + pipeLine.Commands.AddScript(script); + } + + results = pipeLine.Invoke(); + + if (pipeLine.Error != null && pipeLine.Error.Count > 0) + { + foreach (object item in pipeLine.Error.ReadToEnd()) + { + errorList.Add(item); + string errorMessage = string.Format("Invoke error: {0}", item); + HostedSolutionLog.LogWarning(errorMessage); + + throw new ArgumentException(scripts.First()); + } + } + } + + errors = errorList.ToArray(); + HostedSolutionLog.LogEnd("ExecuteShellCommand"); + + return results; + } + + /// Gets PSObject property value. + /// The object. + /// The property name. + /// The property value. + internal object GetPSObjectProperty(PSObject obj, string name) + { + return obj.Members[name].Value; + } + + #endregion + + #region Transactions + + /// Starts the transaction. + /// The transaction. + internal LyncTransaction StartTransaction() + { + return new LyncTransaction(); + } + + /// Rollbacks the transaction. + /// The transaction. + internal void RollbackTransaction(LyncTransaction transaction) + { + HostedSolutionLog.LogStart("RollbackTransaction"); + Runspace runspace = null; + try + { + runspace = OpenRunspace(); + + for (int i = transaction.Actions.Count - 1; i > -1; i--) + { + try + { + RollbackAction(transaction.Actions[i], runspace); + } + catch (Exception ex) + { + HostedSolutionLog.LogError("Rollback error", ex); + } + } + } + catch (Exception ex) + { + HostedSolutionLog.LogError("Rollback error", ex); + } + finally + { + CloseRunspace(runspace); + } + HostedSolutionLog.LogEnd("RollbackTransaction"); + } + + /// Rollbacks lync action. + /// The action. + /// The runspace. + private void RollbackAction(TransactionAction action, Runspace runspace) + { + HostedSolutionLog.LogInfo("Rollback action: {0}", action.ActionType); + switch (action.ActionType) + { + case TransactionAction.TransactionActionTypes.LyncNewSipDomain: + DeleteSipDomain(runspace, action.Id); + break; + case TransactionAction.TransactionActionTypes.LyncNewUser: + DeleteUser(runspace, action.Id); + break; + case TransactionAction.TransactionActionTypes.LyncNewConferencingPolicy: + DeleteConferencingPolicy(runspace, action.Id); + break; + case TransactionAction.TransactionActionTypes.LyncNewExternalAccessPolicy: + DeleteExternalAccessPolicy(runspace, action.Id); + break; + case TransactionAction.TransactionActionTypes.LyncNewMobilityPolicy: + DeleteMobilityPolicy(runspace, action.Id); + break; + } + } + + #endregion + + #region Helpers + + /// Gets organizations AD path. + /// The organization identifier. + /// The organization AD path. + internal string GetOrganizationPath(string organizationId) + { + var sb = new StringBuilder(); + AppendOUPath(sb, organizationId); + AppendOUPath(sb, RootOU); + AppendDomainPath(sb, RootDomain); + + return sb.ToString(); + } + + /// Appends organizational unit path. + /// The string builder. + /// The organizational unit. + internal static void AppendOUPath(StringBuilder sb, string ou) + { + if (string.IsNullOrEmpty(ou)) + { + return; + } + + string path = ou.Replace("/", "\\"); + string[] parts = path.Split('\\'); + for (int i = parts.Length - 1; i != -1; i--) + { + sb.Append("OU=").Append(parts[i]).Append(","); + } + } + + /// Appends domain path. + /// The string builder. + /// The domain name. + internal static void AppendDomainPath(StringBuilder sb, string domain) + { + if (string.IsNullOrEmpty(domain)) + { + return; + } + + string[] parts = domain.Split('.'); + + for (int i = 0; i < parts.Length; i++) + { + sb.Append("DC=").Append(parts[i]); + + if (i < (parts.Length - 1)) + { + sb.Append(","); + } + } + } + + /// Adds AD prefix. + /// The path. + /// The result. + internal string AddADPrefix(string path) + { + string dn = path; + if (!dn.ToUpper().StartsWith("LDAP://")) + { + dn = string.Format("LDAP://{0}/{1}", PrimaryDomainController, dn); + } + return dn; + } + + /// Deletes sip domain. + /// The runspace. + /// The identifier. + internal void DeleteSipDomain(Runspace runspace, string id) + { + HostedSolutionLog.LogStart("DeleteSipDomain"); + HostedSolutionLog.DebugInfo("SipDomain : {0}", id); + var command = new Command("Remove-CsSipDomain"); + command.Parameters.Add("Identity", id); + command.Parameters.Add("Confirm", false); + command.Parameters.Add("Force", true); + ExecuteShellCommand(runspace, command, false); + HostedSolutionLog.LogEnd("DeleteSipDomain"); + } + + /// Deletes user. + /// The runspace. + /// The user UPN. + internal void DeleteUser(Runspace runspace, string userUpn) + { + HostedSolutionLog.LogStart("DeleteUser"); + HostedSolutionLog.DebugInfo("userUpn : {0}", userUpn); + + var command = new Command("Disable-CsUser"); + command.Parameters.Add("Identity", userUpn); + command.Parameters.Add("Confirm", false); + + ExecuteShellCommand(runspace, command, false); + HostedSolutionLog.LogEnd("DeleteUser"); + } + + /// Deletes conferencing policy. + /// The runspace. + /// The policy name. + internal void DeleteConferencingPolicy(Runspace runspace, string policyName) + { + HostedSolutionLog.LogStart("DeleteConferencingPolicy"); + HostedSolutionLog.DebugInfo("policyName : {0}", policyName); + + var command = new Command("Remove-CsConferencingPolicy"); + command.Parameters.Add("Identity", policyName); + command.Parameters.Add("Confirm", false); + command.Parameters.Add("Force", true); + + ExecuteShellCommand(runspace, command, false); + HostedSolutionLog.LogEnd("DeleteConferencingPolicy"); + } + + /// Deletes external access policy. + /// The runspace. + /// The policy name. + internal void DeleteExternalAccessPolicy(Runspace runspace, string policyName) + { + HostedSolutionLog.LogStart("DeleteExternalAccessPolicy"); + HostedSolutionLog.DebugInfo("policyName : {0}", policyName); + + var command = new Command("Remove-CsExternalAccessPolicy"); + command.Parameters.Add("Identity", policyName); + command.Parameters.Add("Confirm", false); + command.Parameters.Add("Force", true); + + ExecuteShellCommand(runspace, command, false); + HostedSolutionLog.LogEnd("DeleteExternalAccessPolicy"); + } + + /// Deletes mobility policy. + /// The runspace. + /// The policy name. + internal void DeleteMobilityPolicy(Runspace runspace, string policyName) + { + HostedSolutionLog.LogStart("DeleteMobilityPolicy"); + HostedSolutionLog.DebugInfo("policyName : {0}", policyName); + + var command = new Command("Remove-CsMobilityPolicy"); + command.Parameters.Add("Identity", policyName); + command.Parameters.Add("Confirm", false); + command.Parameters.Add("Force", true); + + ExecuteShellCommand(runspace, command, false); + HostedSolutionLog.LogEnd("DeleteMobilityPolicy"); + } + + /// Creates simple url. + /// The runspace. + /// The identifier. + internal void CreateSimpleUrl(Runspace runspace, Guid id) + { + var command = new Command("Get-CsSipDomain"); + Collection sipDomains = ExecuteShellCommand(runspace, command, false); + + IList SimpleUrls = new List(); + + foreach (PSObject domain in sipDomains) + { + var d = (string) GetPSObjectProperty(domain, "Name"); + string Url = SimpleUrlRoot + d; + + command = new Command("New-CsSimpleUrlEntry"); + command.Parameters.Add("Url", Url); + Collection simpleUrlEntry = ExecuteShellCommand(runspace, command, false); + + command = new Command("New-CsSimpleUrl"); + command.Parameters.Add("Component", "meet"); + command.Parameters.Add("Domain", d); + command.Parameters.Add("SimpleUrl", simpleUrlEntry[0]); + command.Parameters.Add("ActiveUrl", Url); + Collection simpleUrl = ExecuteShellCommand(runspace, command, false); + + SimpleUrls.Add(simpleUrl[0]); + } + + command = new Command("Set-CsSimpleUrlConfiguration"); + command.Parameters.Add("Identity", "Global"); + command.Parameters.Add("Tenant", id); + command.Parameters.Add("SimpleUrl", SimpleUrls); + ExecuteShellCommand(runspace, command, false); + } + + #endregion + + #endregion + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Properties/AssemblyInfo.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a0a74091 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/Properties/AssemblyInfo.cs @@ -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("WebsitePanel.Providers.HostedSolution.Lync2013")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("WebsitePanel.Providers.HostedSolution.Lync2013")] +[assembly: AssemblyCopyright("Copyright © 2013")] +[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("24c20bdd-51ad-406c-9999-96e432477a79")] + +// 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")] diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/WebsitePanel.Providers.HostedSolution.Lync2013.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/WebsitePanel.Providers.HostedSolution.Lync2013.csproj new file mode 100644 index 00000000..1fddfa62 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution.Lync2013/WebsitePanel.Providers.HostedSolution.Lync2013.csproj @@ -0,0 +1,75 @@ + + + + + Debug + AnyCPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209} + Library + Properties + WebsitePanel.Providers.HostedSolution.Lync2013 + WebsitePanel.Providers.HostedSolution.Lync2013 + v4.5 + 512 + + + true + full + false + ..\WebsitePanel.Server\bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\..\Lib\References\Microsoft\Microsoft.Rtc.Management.Core.dll + + + False + ..\..\Lib\References\Microsoft\Microsoft.Rtc.Management.WritableConfig.dll + + + + + + + + + + + + + + + + + + + + {684C932A-6C75-46AC-A327-F3689D89EB42} + WebsitePanel.Providers.Base + + + {A06DE5E4-4331-47E1-8F46-7B846146B559} + WebsitePanel.Providers.HostedSolution + + + + + \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/HostedSolutionLog.cs b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/HostedSolutionLog.cs index e2adb2f8..93b39b45 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/HostedSolutionLog.cs +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/HostedSolutionLog.cs @@ -122,7 +122,7 @@ namespace WebsitePanel.Providers.HostedSolution return res; } - internal static void DebugCommand(Command cmd) + public static void DebugCommand(Command cmd) { StringBuilder sb = new StringBuilder(cmd.CommandText); foreach (CommandParameter parameter in cmd.Parameters) diff --git a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj index 2bfc8678..7d9abbd1 100644 --- a/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj +++ b/WebsitePanel/Sources/WebsitePanel.Providers.HostedSolution/WebsitePanel.Providers.HostedSolution.csproj @@ -156,7 +156,6 @@ - diff --git a/WebsitePanel/Sources/WebsitePanel.Server.sln b/WebsitePanel/Sources/WebsitePanel.Server.sln index 8eb00736..57bd62de 100644 --- a/WebsitePanel/Sources/WebsitePanel.Server.sln +++ b/WebsitePanel/Sources/WebsitePanel.Server.sln @@ -132,6 +132,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.Host EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.HostedSolution.SharePoint2013", "WebsitePanel.Providers.HostedSolution.SharePoint2013\WebsitePanel.Providers.HostedSolution.SharePoint2013.csproj", "{24762DC8-6078-4F10-A524-C94ED59BD5D1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebsitePanel.Providers.HostedSolution.Lync2013", "WebsitePanel.Providers.HostedSolution.Lync2013\WebsitePanel.Providers.HostedSolution.Lync2013.csproj", "{EF36A05F-5573-4ED2-A47D-689F1CA1A209}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -672,6 +674,16 @@ Global {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU {24762DC8-6078-4F10-A524-C94ED59BD5D1}.Release|x86.ActiveCfg = Release|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Debug|x86.ActiveCfg = Debug|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Release|Any CPU.Build.0 = Release|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EF36A05F-5573-4ED2-A47D-689F1CA1A209}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE