简体   繁体   中英

Invoking Exchange Management Shell from C#

I'm currently using .NET 3.5 / C# to develop a Windows service that performs automated Exchange operations. This service basically watches a SQL database for operations to perform then spawns PowerShell and redirects the output so that results can be monitored from a UI residing elsewhere. Below is the code I'm using to invoke the process...

Action<object, DataReceivedEventArgs> DataReceived = (sender, data) =>
{
    // Log data in SQL
};
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "powershell.exe"
p.StartInfo.Arguments = arguments;

// Arguments are (they're coming from SQL, didn't feel like escaping everything just for this example)
// -command ". 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'; Connect-ExchangeServer -auto; Get-Mailbox –ResultSize unlimited | Search-Mailbox -SearchQuery ... stuff ...

p.StartInfo.LoadUserProfile = true;           
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.OutputDataReceived += new DataReceivedEventHandler(DataReceived);
p.Start();

This code can do things like run ping, tracert, nslookup, echo, dir, and all of the usual command-line suspects with behavior identical to as if I typed it into a command prompt. For instance, I could copy-paste the above into the Run box and it would work flawlessly. Whenever I try to run it as above, however, I receive the following:

Get-ItemProperty : Cannot find path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup' because it does not exist.
At C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1:46 char:34
+ $global:exbin = (get-itemproperty <<<<  HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup).MsiInstallPath + "bin\"
    + CategoryInfo          : ObjectNotFound: (HKLM:\SOFTWARE\...erver\v14\Setup:String) [Get-ItemProperty], ItemNotFo 
    undException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand

Get-ItemProperty : Cannot find path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup' because it does not exist.
At C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1:47 char:38
+ $global:exinstall = (get-itemproperty <<<<  HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup).MsiInstallPath
    + CategoryInfo          : ObjectNotFound: (HKLM:\SOFTWARE\...erver\v14\Setup:String) [Get-ItemProperty], ItemNotFo 
    undException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand

Get-ItemProperty : Cannot find path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup' because it does not exist.
At C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1:48 char:38
+ $global:exscripts = (get-itemproperty <<<<  HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup).MsiInstallPath + "scri
pts\"
    + CategoryInfo          : ObjectNotFound: (HKLM:\SOFTWARE\...erver\v14\Setup:String) [Get-ItemProperty], ItemNotFo 
    undException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand

The term 'bin\CommonConnectFunctions.ps1' is not recognized as the name of a cmdlet, function, script file, or operable
    program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1:52 char:2
+ . <<<<  $global:exbin"CommonConnectFunctions.ps1"
    + CategoryInfo          : ObjectNotFound: (bin\CommonConnectFunctions.ps1:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

A whole slew of other errors follows after this, but from going over the RemoteExchange PowerShell script I've determined that it all comes down to those first three errors: not being able to read from the registry. Does anyone have any idea as to why this might be happening?

Things I've tried to get this to work:

  • Running this code in a console app as opposed to a service context.
  • Every time I've run it I've done so as a domain and Exchange admin and I never got an UAC prompts, so I doubt the issue is one of credentials
  • Checked registry keys... The HKLM key it's looking at also has full read permissions granted to everbody
  • I've enabled unsigned PowerShell script execution on the server
  • Putting the command into a PowerShell script and invoking that programmatically
  • Hardcoding the registry keys' values into the PowerShell script (which just gives me another set of registry read errors further down the line)
  • Using ShellExecute on the process (this can't be done with output redirection, which I require)
  • Explicitly setting environment variables on the StartInfo to match the ones in the spawning environment

To anyone that can give me a hand... thanks a billion!

***EDIT: Perhaps I should clarify the hardcoding bit. I already cracked open RemoteExchange.ps1 and set the variables that are erroring out to their correct values (as opposed to using GetProperty or whatever) and I get marginally farther:

Exception calling "TryLoadExchangeTypes" with "2" argument(s): "Unable to determine the installed file version from the
 registry key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ExchangeServer\v14\Setup'."
At C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1:79 char:92
+ $typeLoadResult = [Microsoft.Exchange.Configuration.Tasks.TaskHelper]::TryLoadExchangeTypes <<<< ($ManagementPath, $t
ypeListToCheck)
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : DotNetMethodException

From what I'm surmising from looking at like 79 this isn't something I can change. It's trying to load types from a library and to do that it needs to look at the registry still, so I can't just fix a variable.

Just try to compile your program in x64.

I know it is weird but, in x86 managed powershell, some cmdlets can't see registry keys form x64 programs.

(I got the clue from: "One of these things is not like the other | Home Of The Scary DBA" : http://www.scarydba.com/2010/06/30/one-of-these-things-is-not-like-the-other/ )

You can open the Exchange.ps1 that resides in \\bin, and edit the variables that appear under

## EXCHANGE VARIABLEs ########################################################

Change $global:exbin, $global:exinstall, and $global:exscripts to be hard coded paths to

"C:\Program Files\Microsoft\Exchange Server\V14\bin\"
"C:\Program Files\Microsoft\Exchange Server\V14\"
"C:\Program Files\Microsoft\Exchange Server\V14\scripts\"

This is not an ideal solution, but the workaround should not impact anything else calling these variables.

Had the same problem and actually finally figured it out. My previous answer was completely wrong.

I answered it correctly here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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