繁体   English   中英

c#中的powershell交换命令-运行空间限制

[英]powershell exchange commands in c# - runspace limits

最近我一直在 .net 项目中创建一些模块,它通过远程 powershell 发送命令到交换服务器。 我的符文空间有很多问题 - 有时它的状态被破坏了,有时我超过了允许的最大连接数(3)

我不知道该怎么做。 下面的代码不是很好,但它比早期的代码效果更好 - 所以现在请不要看质量

第一个类负责返回符文空间(和 powershell 连接) - 我已经将这个类注册为单例(它是 webapi 项目)

public class PowershellCommandEnvironment : IPowershellCommandEnvironment, IDisposable
{
    readonly (string user, string password) powerShellAuth;
    private static Runspace _runspace = null;
    WSManConnectionInfo _connectionInfo;
    

    public PowershellCommandEnvironment()
    {
        powerShellAuth.user = CloudConfigurationManager.GetSetting("ExchangePowerShellUser");
        powerShellAuth.password = CloudConfigurationManager.GetSetting("ExchangePowerShellPassword");

        SecureString secureStrin = new NetworkCredential("", powerShellAuth.password).SecurePassword;
        var creds = new PSCredential(powerShellAuth.user, secureStrin);
        _connectionInfo = new WSManConnectionInfo(new Uri("https://outlook.office365.com/powershell-liveid/"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", creds);
        _connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
        _connectionInfo.MaximumConnectionRedirectionCount = 2;
        _runspace = RunspaceFactory.CreateRunspace(_connectionInfo);
        _runspace.StateChanged += _runspace_StateChanged;


    }

    private void _runspace_StateChanged(object sender, RunspaceStateEventArgs e)
    {
        var state = _runspace.RunspaceStateInfo.State;
        switch (state)
        {
            case RunspaceState.Broken:
                _runspace.Close();
                _runspace.Dispose();
                _runspace = RunspaceFactory.CreateRunspace(_connectionInfo);
                break;

            case RunspaceState.Opening:
                Thread.Sleep(500);
                break;

            case RunspaceState.BeforeOpen:
                _runspace.Open();
                break;
        }
    }

    public Runspace GetRunspace()
    {
      
            while (_runspace.RunspaceStateInfo.State != RunspaceState.Opened)
            {

                OpenRunSpaceTimeExceededAttempt(0);
                Thread.Sleep(100);
            }
            return _runspace;
        
      
    }

    private void OpenRunSpaceTimeExceededAttempt(int attempt)
    {
        if (attempt > 2)
            return;

  
        try
        {
            var state = _runspace?.RunspaceStateInfo.State;
            if (_runspace == null || state == RunspaceState.Closed)
            {
                _runspace = RunspaceFactory.CreateRunspace(_connectionInfo);
                _runspace.Open();
            }


            if (state == RunspaceState.BeforeOpen)
                _runspace.Open();


   
            if (!(state == RunspaceState.Opened))
            {
                OpenRunSpaceTimeExceededAttempt(attempt+1);
            }
        }
        catch (Exception ex)
        {
            if (ex.Message.Contains("Please wait for"))
            {
                System.Threading.Thread.Sleep(10000);
            }
            OpenRunSpaceTimeExceededAttempt(attempt + 1);
        }
    }

 

    public void Dispose()
    {
        _runspace.Dispose();
    }
}

第二个类是PowershellComand,负责执行命令

protected abstract Dictionary<string, object> Parameters { get; set; }
        protected abstract string Command { get; }

        private static Runspace _runspace = null;
        public PowershellCommand(IPowershellCommandEnvironment powershellCommandEnvironment)
        {
            _runspace = powershellCommandEnvironment.GetRunspace();
            Parameters = new Dictionary<string, object>();
            
        }
      
        public T Execute(int attemp=0)
        {
            if (attemp > 2)
                return null;

            try
            {
                using (var powershell = System.Management.Automation.PowerShell.Create())
                {
                    powershell.Runspace = _runspace;
                        
                    powershell.AddCommand(Command);
                    foreach (var param in Parameters)
                    {
                        powershell.AddParameter(param.Key, param.Value);
                    }
                    Collection<PSObject> result = powershell.Invoke();
                    powershell.Runspace.Dispose();
                    return Map(result);
                }
            }
            catch(Exception ex)
            {
                string logMessage = $"Command ${Command} not suceeded.{Environment.NewLine} {ex.Message} {ex.InnerException?.Message}";
                _logger.Log(LogLevel.Error, logMessage);
                int sleep = 5000;
                if (ex.Message.Contains("Please wait for"))
                {
                    sleep = 10000;
                    _logger.Log(LogLevel.Error, "waiting 10000 seconds (powershell command time exceeded");
                 
                }
                Thread.Sleep(sleep);
                return Execute(attemp+1);
            }
        }

        protected abstract T Map(IEnumerable<PSObject> psobj);

此类由特定类派生,这些类使用参数覆盖了 Command(如 Get-Group、Get-User 等)

它可以工作,但通常有一些来自 powershell remote 的错误:-超出了符文空间的限制(我认为我只创建了一个 - 如果它坏了,我正在处理它并创建新的) - 执行时间限制 - 我必须在最新命令后等待 X 秒调用... -bad xml - 这是最奇怪的事情 - 远程 powershell 回答我我发送了错误的 xml 数据 - 它很少发生并且是完全随机的

我知道代码有点混乱,但是当我尝试了我在互联网上找到的最简单的方法时,确实有更多与时间限制和运行空间限制相关的错误

这些命令将经常执行 - 就像 5 个用户可以同时执行某个命令一样。

使用远程 powershell 是在 Exchange 上对启用安全的邮件启用组进行操作的唯一可能方法,因此我无法使用图形 api ...

我通过组合锁和单例解决了这个问题;)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM