Exchange
Filtering Exchange PowerShell Locally
As an Exchange developer, it’s quite possible you’ve run across this error message:
Assignment statements are not allowed in restricted language mode or a Data section.
Or you’ve possibly seen this one:
Script block literals are not allowed in restricted language mode or a Data section.
While it’s quite easy to change the PSLanguageMode to FullLanguage instead of RestrictedLanguage it may be that you can’t do that for one reason or another. Here’s a small method I put together for filtering the results locally. Use your discretion about the size of your resultsets to bring back.
public IEnumerable<PSObject> ApplyPSFilter(IEnumerable psData, ScriptBlock scriptBlock) { using (var ps = System.Management.Automation.PowerShell.Create()) { ps.AddCommand("Where-Object"); ps.AddParameter("FilterScript", scriptBlock); return ps.Invoke(psData); } }
Using Credentials to Get Remote PowerShell Connection to Exchange Connection
Saw this come across the search logs so I figured I’d detail the steps needed to supply credentials to a remote PowerShell connection to Exchange. Since we’re connecting to another system to run the Exchange PS cmdlets, and we are not loading a PSSnapin, the remote system needs to have those cmdlets available. I’m also separating this out into individual methods for easy re-use.
To setup a remote connection, we need to create a new WSManConnectionInfo object. We’re specifically going to use the constructor that takes a Uri for the connection endpoint, a string value for the Uri of the shell and the credentials we want to use.
WSManConnectionInfo Constructor (Uri, String, PSCredential)
The Uri will be specific to your situation and will look something like this : http://myexchangeserver.domain.corp/powershellThe shell is pretty simple. In this case it is : http://scemas.microsoft.com/powershell/Microsoft.Exchange
And last but not least it the PSCredential needed for the connection. PSCredential takes a string for the Username and a SecureString for the password. Here’s an small method to pass in a string and get a SecureString back :
SecureString GetSecurePassword(string password) { var securePassword = new SecureString(); foreach (var c in password) { securePassword.AppendChar(c); } return securePassword; }
With that out of the way, let’s take a look at a snippet for getting the connection info :
WSManConnectionInfo GetConnectionInfo() { var securePassword = GetSecurePassword(password); var cred = new PSCredential(username, securePassword); var connectionInfo = new WSManConnectionInfo(new Uri("http://superserver.corp/powershell), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", cred); connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Credssp; //or Basic, Digest, Kerberos etc. return connectionInfo; }
Now let’s put it all together to make a remote connection :
using (var runspace = RunspaceFactory.CreateRunspace(connectionInfo)) { using (var ps = System.Management.Automation.PowerShell.Create()) { //psCommand was created above ps.Commands = psCommand; runspace.Open(); ps.Runspace = runspace; try { var results = ps.Invoke(); if (!ps.HadErrors) { runspace.Close(); //Yay! no errors. Do something else? } catch (RemoteException ex) { //error handling here } } }
So, a couple of things to mention here. First, psCommand was created like this. You could also create a Pipeline if you have more than one command to run or even use it to create a PS script to run. Also, if you need to do something with the results of the command, well, you’ll have to either make this return the results ((FavoriteCollectionType) or modify this to suit your needs. Second, we verify that the command had no errors (no exception but didn’t run successfully for whatever reason) but that’s it. Might want to expand here or in the calling method.
I hope this has been informative. 😀
Creating Exchange 2013 Mailbox in C#
Holy moly it’s been a long time since I posted. Here’s a quick code snippet on using C# to create a mailbox to hopefully kick a string of posts off. This creates an AD account for the user unlike my previous article on creating a mailbox in Exchange 2010. And since I listed a gotcha in that article, I’ll leave a tip in this one after the code. 😀
var psc = new PSCommand(); psc.AddCommand("New-Mailbox"); psc.AddParameter("Name", newUser.UserName); psc.AddParameter("UserPrincipalName", upn); psc.AddParameter("Alias", upn); psc.AddParameter("PrimarySmtpAddress", string.Format("{0}@{1}", newUser.UserName, domainName).ToLower()); psc.AddParameter("OrganizationalUnit", domainDn); psc.AddParameter("SamAccountName", samAccount); psc.AddParameter("Password", _ps.CreateSecurePassword("mysupersecretpassword")); psc.AddParameter("DomainController", domainController); PowerShell ps = PowerShell.Create(); ps.Commands = psc; try { var result = ps.Invoke(); if (!ps.HadErrors) { Console.WriteLine("Congrats! User created successfully"); } } catch (RemoteException ex) { //Error conditions here... }
Easy enough. Now for the tip. If you specify the PrimarySmtpAddress it will automatically set the EmailAddressPolicyEnabled value to false. So leave that parameter out if it’s important for your org.
Creating Exchange 2010 Mailboxes in C#
Wow, it’s been a while! I had full intentions of creating regular posts but that kind of slipped away. So I’ll make this one fairly short and just highlight the basics of creating an Exchange 2010 mailbox via remote code. Nothing fancy, but I will highlight one gotcha that I encountered when updating our user creation code after we migrated from Exchange 2003. Keep in mind that Exchange 2010 is built on Powershell and as such, all of connections and manipulation must be done through it.
First, we want to add our usings…
using System.Management.Automation; using System.Management.Automation.Remoting; using System.Management.Automation.Runspaces;
Next, we’re going to create the PSCredential, the WSManConnectionInfo, and the Runspace. We’ll then create a powershell command, invoke the powershell with the command and cross our fingers. 😀
PSCredential newCred = (PSCredential)null; WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("http://exchangeserver01.my.domain/powershell?serializationLevel=Full"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", newCred); connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos; Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo); PowerShell powershell = PowerShell.Create(); PSCommand command = new PSCommand(); command.AddCommand("Enable-Mailbox"); command.AddParameter("Identity", user.Guid.ToString()); command.AddParameter("Alias", user.UserName); command.AddParameter("DomainController", ConnectingServer); powershell.Commands = command; try { runspace.Open(); powershell.Runspace = runspace; Collectionresults = powershell.Invoke(); } catch (Exception ex) { string er = ex.InnerException.ToString(); } finally { runspace.Dispose(); runspace = null; powershell.Dispose(); powershell = null; }
Now, a couple of things to note…
1) My gotcha…You don’t find a lot of information about creating a PSCredential using the credentials of the currently logged in user. Even the MSDN documentation only shows one constructor where you pass in a username and password. After searching around, some trial and error, I finally found this post detailing creating the PSCredential using Windows Authentication with no username or password supplied. Supplying credentials isn’t a problem, but as we log the account creations, and we didn’t have this issue when creating boxes in 2003, I wanted as seamless transition as possible. So this code just replaced the old code and my other Admins had no idea anything was different.
2) Accounts for my users need to be created at one of many different sites, and many times it’s not a site I’m currently at. So, the account is created on the ‘local to them’ server so they can immediately login and not need to wait for replication. Because of this, Exchange needs to know what server holds the account. If you don’t need this functionality, you can remove the DomainController command parameter above.
3) It is important to properly dispose of the runspace and powershell objects. Make sure this is done.
Exchange Free/Busy Problems
After searching for a few hours and feeling seriously inadequate in my Google-Fu, I finally found a fix for a problem that doesn’t seem to have happened to anyone else. So, if you have run across this issue, I feel your pain…
The boss lady called yesterday to let me know that she could not email her calendar with ONLY Free/Busy information.
Now, her error showed a date range for a month, not a single day. Changing the options to include Limited data worked fine. But this isn’t always acceptable. If you’re sending this info to a vendor to help with scheduling a meeting, the vendor doesn’t need to know you have lunch plans with a competitor or an interview scheduled for next Friday. They just need to know you aren’t available.
As I mentioned earlier, I searched for at least an hour and a half for this error. After verifying that this occurred on my machine as well, I ruled out Outlook and started looking for solutions regarding Exchange. I came across this great Technet article. I downloaded the MAPI Editor tool and proceeded to follow the instructions in the Removing Free/Busy Information from the Schedule+ Free/Busy Folder section.
To remove Free/Busy information from the Schedule+ Free/Busy folder
- Log on as an account that has Exchange Full Administrative permissions. For more information about permissions, see Microsoft Knowledge Base article 823018, “Overview of Exchange administrative role permissions in Exchange 2003” at http://go.microsoft.com/fwlink/?linkid=3052&kbid=823018.
- Start MAPI Editor.
- On the Session menu, click Logon and Display Store Table.
Note:
If the Choose Profile dialog box does not appear, you are probably already logged on to a profile. Log off the client and profile, and try step 3 again. - Select the profile that you created for the directory service mailbox, and then click OK.
- On the MDB menu, click Open Public Folder Store, select Use Admin Privileges, and then click OK.
- In the Public Folders window, expand Public Root, and then expand NON_IPM_SUBTREE. The SCHEDULE+ FREE BUSY folder is displayed.
- Expand the SCHEDULE+ FREE BUSY folder.
The subfolders of the Schedule + Free/Busy folder will be of the form EX:/o=Organization/ou=domain.
- Double-click the appropriate folder to open it.
Note:
The folder could have several messages in it. Press Escape (ESC) to stop loading messages. - Table/Create and Apply Content Restriction can be used to restrict the table to show only messages you are looking for. For example, because the subjects of free/busy messages take the form USER-/CN=container/CN=username, a restriction on PR_SUBJECT (0x0037001E) for the value “username” with the flags 0x00010001 (FL_SUBSTRING | FL_IGNORECASE) could be used to locate one specific message. Note that on large folders, restrictions may take time to apply.
- When the problem message is located, if you want to delete it, right-click the message, and then click Delete Message.
- When you are prompted, select Permanent Deletion (deletes to deleted item retention…) from the drop-down list, and then click OK.
- Using Outlook, create a new appointment for this user to force re-creation of the Free/Busy message.
Voila! Emailing the calendar with only Free/Busy status works as expected. 😀