{"id":136,"date":"2020-01-09T09:34:03","date_gmt":"2020-01-09T14:34:03","guid":{"rendered":"http:\/\/ayling.tech\/blog\/?p=136"},"modified":"2023-01-04T16:33:55","modified_gmt":"2023-01-04T21:33:55","slug":"powershell-and-exchange-with-c","status":"publish","type":"post","link":"https:\/\/shortbooks.online\/blog\/2020\/powershell-and-exchange-with-c\/","title":{"rendered":"PowerShell and Exchange with C#"},"content":{"rendered":"\n<p>When writing a program that needs to interact with Exchange (whether on-premises or off-premises\/online), the easiest way is to use PowerShell commands.<\/p>\n\n\n\n<p>This is done by adding the following above your namespace declaration:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">using System.Management.Automation;<\/pre>\n\n\n\n<p>The key thing that I have found to be a problem for C# programs using PowerShell is that occasionally you will receive an error message that says &#8220;A connection to the directory on which to process the request was unavailable. This is likely a transient condition.&#8221;<\/p>\n\n\n\n<p>This is caused by trying to query PowerShell too often. If you are using PowerShell to query Exchange, you have a connection string that you will use &#8211; something like these two commands:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$Global:exchangeUri = \"http:\/\/powershell.onyourdomain\";$session = New-PSSession -Name $Global:sessionName -ConfigurationName Microsoft.Exchange -ConnectionUri $Global:exchangeUri -Authentication Kerberos;\nImport-PSSession $session<\/pre>\n\n\n\n<p>If you attempt to do this every time you want to update some information in Exchange, or every time you want to query something in Exchange, you will quickly experience the transient condition error.<\/p>\n\n\n\n<p>To avoid this, make a connection once per session. I have done this, in the code below, using an object named &#8220;Exchange&#8221; (because I&#8217;m imaginative like that):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public class Exchange\n{\n    public Exchange(bool onPrem, string userEmail = \"NoEmail\", string password = \"NoPassword\")\n    {\n        OnPrem = onPrem;\n        if (!OnPrem)\n        {\n            if (password == \"NoPassword\" || userEmail == \"NoEmail\")\n                throw new ArgumentException(\"If Online Exchange, we must have a username and password passed\");\n            CreateCredential(password, userEmail);\n        }\n    }\n    Runspace _LocalRunSpace { get; set; }\n    Runspace LocalRunSpace\n    {\n        get\n        {\n            if (_LocalRunSpace == null)\n            {\n                _LocalRunSpace = RunspaceFactory.CreateRunspace();\n                _LocalRunSpace.Open();\n            }\n            return _LocalRunSpace;\n        }\n    }\n    private PSCredential Credential;\n    private PSCredential CreateCredential(string password, string emailAddress)\n    {\n        SecureString secpassword = new SecureString();\n        foreach (char c in password)\n            secpassword.AppendChar(c);\n        return Credential = new PSCredential(emailAddress, secpassword);\n    }\n    private bool OnPrem { get; set; }\n private PowerShell _powershell { get; set; }\nprivate PowerShell PowerShellInstance\n{\n     get\n     {\n          if (_powershell == null)\n          {\n             _powershell = PowerShell.Create();\n             _powershell.Runspace = LocalRunSpace;\n             if (OnPrem)\n             {\n                  _powershell.AddScript(exchangeScript);\n                  Collection results = _powershell.Invoke();\n                  foreach (PSObject result in results)\n                      Console.WriteLine(result.ToString());\n              }\n              else\n              {\n                  var newSession = _powershell.AddCommand(\"New-PSSession\")\n                         .AddParameter(\"ConfigurationName\", \"Microsoft.Exchange\")\n                           .AddParameter(\"ConnectionUri\", \"https:\/\/ps.outlook.com\/powershell\/\")\n                           .AddParameter(\"Credential\", Credential)\n                           .AddParameter(\"Authentication\", \"Basic\")\n                           .AddParameter(\"AllowRedirection\", true)\n                           .Invoke();\n                  var session = newSession[0];\n                  _powershell.Commands.Clear();\n                  Collection results = _powershell\n                           .AddCommand(\"Import-PSSession\")\n                           .AddParameter(\"Session\", session)\n                           .Invoke();\n                  <code>foreach (PSObject result in results)                           <\/code>\n                         <code>Console.WriteLine(result.ToString());                              <\/code>\n              <code>}<\/code>\n           <code>}<\/code>\n     <code>return _powershell;<\/code>\n     <code>}<\/code>\n<code>}<\/code>   <\/pre>\n\n\n\n<p>You can then use a method like the following, to run commands against the existing PowerShell connection. When I need both online exchange, and on-prem exchange, I create two instances of the Exchange object, and each will persist for as long as they are needed:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public string RunCommand(string command)\n{\n     try\n     {\n          PowerShellInstance.Commands.Clear();\n          PowerShellInstance.AddScript(command);          \n          PowerShellInstance.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);\n          Collection results;\n          try { results = PowerShellInstance.Invoke(); }\n          catch (System.Threading.ThreadAbortException threadError)\n          {\n                Console.WriteLine(\"PowerShell script ran into thread error:\\n\" + threadError.Message);\n                return string.Empty;\n           }\n <code>          string dataToReturn = string.Empty;<\/code>\n           <code>foreach (PSObject result in results)<\/code>\n                <code>dataToReturn += string.Format(result.ToString(), \"; \");              <\/code>\n           <code>return dataToReturn;<\/code>\n      <code>}<\/code>\n      <code>catch { return string.Empty; }<\/code>\n<code>}<\/code><\/pre>\n\n\n\n<p>I hope this is helpful. If you have any questions or comments, please use the comments section below!<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"shortbooksLink\">I write short stories and o\u00feer fiction &#8211; check \u00feem out at <a href=\"https:\/\/shortbooks.online\" title=\"\">shortbooks.online<\/a><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity\"\/>\n\n\n\n<p>Like many creative people on \u00fee internet, I have a Patreon account. If you would like to support my creative writing (on <a href=\"https:\/\/shortbooks.online\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/shortbooks.online<\/a>) or my blogging efforts, please take a look at <a href=\"https:\/\/www.patreon.com\/gavinayling\" target=\"_blank\" rel=\"noreferrer noopener\">my Patreon page<\/a>.<\/p>\n\n\n\n<a href=\"https:\/\/www.patreon.com\/bePatron?u=58356065\" data-patreon-widget-type=\"become-patron-button\">Become a Patron!<\/a><script async=\"\" src=\"https:\/\/c6.patreon.com\/becomePatronButton.bundle.js\"><\/script>\n","protected":false},"excerpt":{"rendered":"<p>When writing a program that needs to interact with Exchange (whether on-premises or off-premises\/online), the easiest way is to use PowerShell commands. This is done by adding the following above your namespace declaration: using System.Management.Automation; The key thing that I have found to be a problem for C# programs using PowerShell is that occasionally you will receive an error message that says &#8220;A connection to the directory on which to process the request was unavailable. This is likely a transient&#8230;<\/p>\n<p class=\"read-more\"><a class=\"btn btn-default\" href=\"https:\/\/shortbooks.online\/blog\/2020\/powershell-and-exchange-with-c\/\"> Read More<span class=\"screen-reader-text\">  Read More<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":127,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"content-type":"","footnotes":""},"categories":[14],"tags":[15,36,34,35],"class_list":["post-136","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code","tag-c","tag-object","tag-powershell","tag-transient-condition"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/posts\/136","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/comments?post=136"}],"version-history":[{"count":1,"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/posts\/136\/revisions"}],"predecessor-version":[{"id":983,"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/posts\/136\/revisions\/983"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/media\/127"}],"wp:attachment":[{"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/media?parent=136"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/categories?post=136"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/shortbooks.online\/blog\/wp-json\/wp\/v2\/tags?post=136"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}