// Copyright (c) 2014, Outercurve Foundation. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // - Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // - Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // - Neither the name of the Outercurve Foundation nor the names of its // contributors may be used to endorse or promote products derived from this // software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using System.Reflection; using System.Globalization; using Microsoft.Win32; using WebsitePanel.Providers; using WebsitePanel.Providers.HostedSolution; using WebsitePanel.Providers.Utils; using WebsitePanel.Server.Utils; using System.Management; using System.Management.Automation; using System.Management.Automation.Runspaces; using WebsitePanel.Providers.Common; using System.Runtime.InteropServices; using System.Linq; using WebsitePanel.Providers.DomainLookup; using WebsitePanel.Providers.DNS; namespace WebsitePanel.Providers.OS { public class Windows2012 : Windows2003 { #region Properties internal string PrimaryDomainController { get { return ProviderSettings["PrimaryDomainController"]; } } #endregion Properties public override bool IsInstalled() { Server.Utils.OS.WindowsVersion version = WebsitePanel.Server.Utils.OS.GetVersion(); return version == WebsitePanel.Server.Utils.OS.WindowsVersion.WindowsServer2012 || version == WebsitePanel.Server.Utils.OS.WindowsVersion.Windows8 || version == WebsitePanel.Server.Utils.OS.WindowsVersion.WindowsServer2012R2 || version == WebsitePanel.Server.Utils.OS.WindowsVersion.Windows81; } public override void SetQuotaLimitOnFolder(string folderPath, string shareNameDrive, QuotaType quotaType, string quotaLimit, int mode, string wmiUserName, string wmiPassword) { Log.WriteStart("SetQuotaLimitOnFolder"); Log.WriteInfo("FolderPath : {0}", folderPath); Log.WriteInfo("ShareNameDrive : {0}", shareNameDrive); Log.WriteInfo("QuotaLimit : {0}", quotaLimit); string path = Path.Combine(shareNameDrive + @":\", folderPath); Runspace runSpace = null; try { runSpace = OpenRunspace(); if (path.IndexOfAny(Path.GetInvalidPathChars()) == -1) { if (!FileUtils.DirectoryExists(path)) FileUtils.CreateDirectory(path); if (quotaLimit.Contains("-")) { RemoveOldQuotaOnFolder(runSpace, path); } else { var quota = CalculateQuota(quotaLimit); switch (mode) { //deleting old quota and creating new one case 0: { RemoveOldQuotaOnFolder(runSpace, path); ChangeQuotaOnFolder(runSpace, "New-FsrmQuota", path, quotaType, quota); break; } //modifying folder quota case 1: { ChangeQuotaOnFolder(runSpace, "Set-FsrmQuota", path, quotaType, quota); break; } } } } } catch (Exception ex) { Log.WriteError("SetQuotaLimitOnFolder", ex); throw; } finally { CloseRunspace(runSpace); } Log.WriteEnd("SetQuotaLimitOnFolder"); } public override Quota GetQuotaOnFolder(string folderPath, string wmiUserName, string wmiPassword) { Log.WriteStart("GetQuotaLimitOnFolder"); Log.WriteInfo("FolderPath : {0}", folderPath); Runspace runSpace = null; Quota quota = new Quota(); try { runSpace = OpenRunspace(); if (folderPath.IndexOfAny(Path.GetInvalidPathChars()) == -1) { Command cmd = new Command("Get-FsrmQuota"); cmd.Parameters.Add("Path", folderPath); var result = ExecuteShellCommand(runSpace, cmd, false); if (result.Count > 0) { quota.Size = ConvertBytesToMB(Convert.ToInt64(GetPSObjectProperty(result[0], "Size"))); quota.QuotaType = Convert.ToBoolean(GetPSObjectProperty(result[0], "SoftLimit")) ? QuotaType.Soft : QuotaType.Hard; quota.Usage = ConvertBytesToMB(Convert.ToInt64(GetPSObjectProperty(result[0], "usage"))); } } } catch (Exception ex) { Log.WriteError("GetQuotaLimitOnFolder", ex); throw; } finally { CloseRunspace(runSpace); } Log.WriteEnd("GetQuotaLimitOnFolder"); return quota; } public override Dictionary GetQuotasForOrganization(string folderPath, string wmiUserName, string wmiPassword) { Log.WriteStart("GetQuotasLimitsForOrganization"); Runspace runSpace = null; Quota quota = null; var quotas = new Dictionary(); try { runSpace = OpenRunspace(); Command cmd = new Command("Get-FsrmQuota"); cmd.Parameters.Add("Path", folderPath + "\\*"); var result = ExecuteShellCommand(runSpace, cmd, false); if (result.Count > 0) { foreach (var element in result) { quota = new Quota(); quota.Size = ConvertBytesToMB(Convert.ToInt64(GetPSObjectProperty(element, "Size"))); quota.QuotaType = Convert.ToBoolean(GetPSObjectProperty(element, "SoftLimit")) ? QuotaType.Soft : QuotaType.Hard; quota.Usage = ConvertBytesToMB(Convert.ToInt64(GetPSObjectProperty(element, "usage"))); quotas.Add(Convert.ToString(GetPSObjectProperty(element, "Path")), quota); } } } catch (Exception ex) { Log.WriteError("GetQuotasLimitsForOrganization", ex); throw; } finally { CloseRunspace(runSpace); } Log.WriteEnd("GetQuotasLimitsForOrganization"); return quotas; } public UInt64 CalculateQuota(string quota) { UInt64 OneKb = 1024; UInt64 OneMb = OneKb * 1024; UInt64 OneGb = OneMb * 1024; UInt64 result = 0; // Quota Unit if (quota.ToLower().Contains("gb")) { result = UInt64.Parse(quota.ToLower().Replace("gb", "")) * OneGb; } else if (quota.ToLower().Contains("mb")) { result = UInt64.Parse(quota.ToLower().Replace("mb", "")) * OneMb; } else { result = UInt64.Parse(quota.ToLower().Replace("kb", "")) * OneKb; } return result; } public int ConvertMegaBytesToGB(int megabytes) { int OneGb = 1024; if (megabytes == -1) return megabytes; return (int)(megabytes/ OneGb); } public int ConvertBytesToMB(long bytes) { int OneKb = 1024; int OneMb = OneKb * 1024; if (bytes == 0) return 0; return (int)(bytes / OneMb); } public void RemoveOldQuotaOnFolder(Runspace runSpace, string path) { try { runSpace = OpenRunspace(); if (!string.IsNullOrEmpty(path)) { Command cmd = new Command("Remove-FsrmQuota"); cmd.Parameters.Add("Path", path); ExecuteShellCommand(runSpace, cmd, false); } } catch { /* do nothing */ } } public void ChangeQuotaOnFolder(Runspace runSpace, string command, string path, QuotaType quotaType, UInt64 quota) { Command cmd = new Command(command); cmd.Parameters.Add("Path", path); cmd.Parameters.Add("Size", quota); if (quotaType == QuotaType.Soft) { cmd.Parameters.Add("SoftLimit", true); } ExecuteShellCommand(runSpace, cmd, false); } #region Domain LookUp public override DnsRecordInfo[] GetDomainDnsRecords(string domain, string dnsServer, DnsRecordType recordType) { List records = new List(); Runspace runSpace = null; try { runSpace = OpenRunspace(); Command cmd = new Command("Resolve-DnsName"); cmd.Parameters.Add("Name", domain); cmd.Parameters.Add("Server", dnsServer); cmd.Parameters.Add("Type", recordType.ToString()); var dnsRecordsPs = ExecuteShellCommand(runSpace, cmd, false); if (dnsRecordsPs != null) { foreach (var dnsRecordPs in dnsRecordsPs) { DnsRecordInfo newRecord = null; switch (recordType) { case DnsRecordType.MX: { newRecord = CreateDnsRecordFromPsObject(dnsRecordPs, "NameExchange"); break; } case DnsRecordType.NS: { newRecord = CreateDnsRecordFromPsObject(dnsRecordPs, "NameHost"); break; } default: continue; } if (newRecord != null) { newRecord.DnsServer = dnsServer; newRecord.RecordType = recordType; records.Add(newRecord); } } } } finally { CloseRunspace(runSpace); } return records.ToArray(); } private DnsRecordInfo CreateDnsRecordFromPsObject(PSObject psObject, string valueName) { if (!psObject.Members.Any(x => x.Name == valueName)) { return null; } var dnsRecord = new DnsRecordInfo { Value = Convert.ToString(GetPSObjectProperty(psObject, valueName)), }; return dnsRecord; } #endregion #region PowerShell integration private static InitialSessionState session = null; internal virtual Runspace OpenRunspace() { Log.WriteStart("OpenRunspace"); if (session == null) { session = InitialSessionState.CreateDefault(); session.ImportPSModule(new string[] { "FileServerResourceManager" }); } Runspace runSpace = RunspaceFactory.CreateRunspace(session); // runSpace.Open(); // runSpace.SessionStateProxy.SetVariable("ConfirmPreference", "none"); Log.WriteEnd("OpenRunspace"); return runSpace; } internal void CloseRunspace(Runspace runspace) { try { if (runspace != null && runspace.RunspaceStateInfo.State == RunspaceState.Opened) { runspace.Close(); } } catch (Exception ex) { Log.WriteError("Runspace error", ex); } } internal Collection ExecuteShellCommand(Runspace runSpace, Command cmd) { return ExecuteShellCommand(runSpace, cmd, true); } internal Collection ExecuteShellCommand(Runspace runSpace, Command cmd, bool useDomainController) { object[] errors; return ExecuteShellCommand(runSpace, cmd, useDomainController, out errors); } internal Collection ExecuteShellCommand(Runspace runSpace, Command cmd, out object[] errors) { return ExecuteShellCommand(runSpace, cmd, true, out errors); } internal Collection ExecuteShellCommand(Runspace runSpace, Command cmd, bool useDomainController, out object[] errors) { Log.WriteStart("ExecuteShellCommand"); List errorList = new List(); if (useDomainController) { CommandParameter dc = new CommandParameter("DomainController", PrimaryDomainController); if (!cmd.Parameters.Contains(dc)) { cmd.Parameters.Add(dc); } } Collection results = null; // Create a pipeline Pipeline pipeLine = runSpace.CreatePipeline(); using (pipeLine) { // Add the command pipeLine.Commands.Add(cmd); // Execute the pipeline and save the objects returned. results = pipeLine.Invoke(); // Log out any errors in the pipeline execution // NOTE: These errors are NOT thrown as exceptions! // Be sure to check this to ensure that no errors // happened while executing the command. 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); Log.WriteWarning(errorMessage); } } } pipeLine = null; errors = errorList.ToArray(); Log.WriteEnd("ExecuteShellCommand"); return results; } internal object GetPSObjectProperty(PSObject obj, string name) { return obj.Members[name].Value; } /// /// Returns the identity of the object from the shell execution result /// /// /// internal string GetResultObjectIdentity(Collection result) { Log.WriteStart("GetResultObjectIdentity"); if (result == null) throw new ArgumentNullException("result", "Execution result is not specified"); if (result.Count < 1) throw new ArgumentException("Execution result is empty", "result"); if (result.Count > 1) throw new ArgumentException("Execution result contains more than one object", "result"); PSMemberInfo info = result[0].Members["Identity"]; if (info == null) throw new ArgumentException("Execution result does not contain Identity property", "result"); string ret = info.Value.ToString(); Log.WriteEnd("GetResultObjectIdentity"); return ret; } internal string GetResultObjectDN(Collection result) { Log.WriteStart("GetResultObjectDN"); if (result == null) throw new ArgumentNullException("result", "Execution result is not specified"); if (result.Count < 1) throw new ArgumentException("Execution result does not contain any object"); if (result.Count > 1) throw new ArgumentException("Execution result contains more than one object"); PSMemberInfo info = result[0].Members["DistinguishedName"]; if (info == null) throw new ArgumentException("Execution result does not contain DistinguishedName property", "result"); string ret = info.Value.ToString(); Log.WriteEnd("GetResultObjectDN"); return ret; } #endregion } }