Exchange Server 2010 Portable Command Guide: Advanced Techniques
Date: Jul 7, 2011
This chapter provides information and commands concerning the following topics:
- Working with pipelines
- Running programs
- Creating and running scripts
- Registry modifications with PowerShell
- Understanding quotes
Working with Pipelines
When you pipeline, you take the output of one cmdlet and use it in a subsequent cmdlet to perform another operation. This simple act ensures that you can string together very simple cmdlets into complex operations. Some of the reasons you may wish to pipeline include the following:
- You need to pass data from the output of one cmdlet to a subsequent cmdlet.
- You need to perform multiple actions on one or more Exchange objects without having to do so individually.
- You need to pass data output between dissimilar nouns.
- You need the system to report errors or warnings.
You can use pipelining to pass data from the output of one cmdlet to a subsequent cmdlet in order to perform another operation. This operation might work like what's shown in the following table.
Get-User -OrganizationalUnit OUName | Enable-Mailbox -Database "DatabaseName" PS C:\UsersAdministrator>Get-User -OrganizationalUnit Assemblers | Enable-Mailbox -Database "AssemblyDB" |
After acquiring a new assembly plant in Philadelphia, you need to create mailboxes in the AssemblyDB database for all users in the Assemblers OU, which is a child of the Philadelphia OU. This pipelined cmdlet retrieves a list of all users in the Assemblers OU and passes the resultset to the Enable-Mailbox cmdlet, which creates the mailboxes for those users. In Figure 3-1, you can see that there are two users in the Assemblers OU in Active Directory Users and Computers. However, in Figure 3-2, there are no mailboxes present for these users. Figure 3-3 demonstrates the cmdlet used for creating mailboxes for existing users using a Get-User cmdlet piped to an Enable-Mailbox cmdlet. Finally, in Figure 3-4, you can see that the mailboxes have been created. |
Figure 3-1 Users in the Assemblers OU in Active Directory Users and Computers
Figure 3-2 No mailboxes present in the Exchange Management Console for the Assemblers OU users
Figure 3-3 Mailboxes for users in the Assemblers OU created with the Enable-Mailbox cmdlet
Figure 3-4 Mailboxes now present in the Exchange Management Console for the Assemblers OU users
You can also use pipelining to combine several actions. In that way, you can use one cmdlet to gather the mailboxes for all managers, VPs, and anyone in the Assembly department in your organization who has an Exchange mailbox and then a second cmdlet to set multiple quota values on those distinct groups of mailboxes. Performing multiple actions on Exchange objects might work like what's shown in the following table.
Get-User -Filter {((Title -like Title1Name) -or (Title -like Title2Name) -or (Department -eq DepartmentName )) -and (RecipientTypeDetails -eqRecipientType )} | Set-Mailbox -IssueWarningQuota size1 -ProhibitSendQuota size2 -ProhibitSendReceiveQuota size3 -UseDatabaseQuotaDefaults $boolean value PS C:\Users\Administrator>Get-User -Filter {((Title -like "*Manager*") -or (Title -like "*VP*") -or (Department -eq "Assembly")) -and (RecipientTypeDetails -eq "UserMailbox")} | Set-Mailbox -IssueWarningQuota 900MB -ProhibitSendQuota 1GB -ProhibitSendReceiveQuota unlimited -UseDatabaseQuotaDefaults $false |
You have very distinct groups of users who need unique quotas applied to their mailboxes. You cannot use a quota at the database level because these users are spread across multiple databases. All managers, VPs, and users in the Assembly department need these quotas applied to their mailboxes regardless of the server or database where their mailbox is located. You can combine the collecting of the distinct groups of users with the application of the unique quotas on the mailboxes with a piped cmdlet, as shown. |
You can pipe data between dissimilar nouns. You might find that you want to use the data from one cmdlet within another cmdlet, but the object types do not match. This can happen if one cmdlet references one noun (such as by importing information from a .csv file with an Import-CSV cmdlet, where "CSV" is the noun) and you then want to use that imported data to create a new user account as well as an Exchange mailbox, which you can do with the New-Mailbox cmdlet, where "Mailbox" is the noun. Finally, you might wish to add title and department attributes to the user account (not the mailbox), which references the "User" noun. Passing data output between dissimilar nouns might work like what's shown in the following table.
Import-CSV "C:\filename.csv" | ForEach-Object -Begin { $Pass = ConvertTo-SecureString password -asPlainText -force} -Process {New-Mailbox -Name $_.Name -UserPrincipalName "$($_.UserName)@ DomainName" -OrganizationalUnit "OUName" -Database "DatabaseName" -Password $Pass -ResetPasswordOnNextLogon $true | Set-User -Title $_.Title -Department $_.Department} PS C:\Users\Administrator>Import-CSV "C:\FileFromHR.csv" | ForEach-Object -Begin {$Pass = ConvertTo-SecureString "Pa$$w0rd" -asPlainText -force} -Process {New-Mailbox -Name $_.Name -UserPrincipalName "$($_.UserName) @DomainName" -OrganizationalUnit "OUName" -Database "DatabaseName" -Password $Pass -ResetPasswordOnNextLogon $true | Set-User -Title $_.Title -Department $_.Department} |
You need to import several users from a .csv file given to you by the HR department. The noun initially used is "CSV". You then wish to create the user and the mailbox at the same time, but that requires setting a password for each user. You create a password and save it as a secure string, which the Active Directory will accept. You use a variable ($Pass) to store the secure string password. This involves the New-Mailbox cmdlet, which utilizes the "Mailbox" noun. Finally, you want to add values to title and department, which are properties of the user, so you need to reference the "User" noun to do that. |
You can also report errors or warnings though pipelining, which might work like what's shown in the following table.
$Name = "Custom Text" PS C:\Users Administrator> $Warn = "This is an example of a custom warning that you might create that could provide an onscreen warning when some condition exists." $Name | Write-Warning PS C:\Users Administrator> $Warn | Write-Warning |
This illustrates how you could pipe a string to the Write-Warning cmdlet. You could save the string in a variable, as shown in the first pair of cmdlets, and then pipe the string to Write-Warning, as shown in the second pair of cmdlets. |
Running Programs
Unlike cmd.exe, Exchange Management Shell (EMS) can process cmdlets in one of two ways. It analyzes what you have typed and decides whether it should be interpreted as an expression (Typing 1 + 1 produces a result of 2 in Expression mode) or as a command, which works similarly to the way that cmd.exe works. In Command mode, if what you have typed has no errors, it will be executed. If you begin a line of code with a number, a quote, or a dollar sign ($), EMS will function in Expression mode. This can be observed when you type $compute = 1+1 and press Enter. When you subsequently type $computer and press Enter, the output will be the number "2".
What if you are interested in running a program and you have defined the variable $Prog to run it—how can you tell EMS to execute $Prog as a command and not display it as a value? The use of the ampersand (&) character is how you can do this, as shown in the following table.
PS C:\UsersAdministrator>$Prog= C:\Windows\System32\ calc.exe PS C:\UsersAdministrator>$Prog PS C:\UsersAdministrator>&$Prog |
If you define the variable $Prog as shown in the example, the Windows Calculator will not launch when you subsequently type $Prog, but the result that is displayed will be C:\Windows\System32\calc.exe. EMS is displaying the value of the variable, not executing it. However, if you type &$Prog, the Windows Calculator will launch successfully. |
To run a batch file, you need cmd.exe to launch first, so you could do something like what's shown in the following table.
PS C:\UsersAdministrator>cmd.exe /c MyTest.bat |
Here, /c tells the batch file to carry out the command and then terminate cmd.exe It is not necessary to use & with cmd.exe. |
For a VBScript executable, you also need cmd.exe to launch first, so you could do something like what's shown in the following table.
PS C:\Users\Administrator> &"cscript.exe MyVBScript.vbs param1 param2" |
Because you are launching another executable, & is required. |
To run PowerShell scripts from a cmd.exe prompt, you need to use powershell.exe. In previous versions of PowerShell, you used msh.exe. Powershell.exe is run as shown in the following table.
PS C:\UsersAdministrator> powershell.exe-noexit "C:\MyScripts\MyTest.ps1" |
Powershell.exe is the Windows PowerShell executable. The -noexit switch is an optional parameter that tells the PowerShell console to remain open after the script finishes. |
This technique will be illustrated in the section that follows.
Creating and Running Scripts
In most cases, you will run individual cmdlets to achieve your desired result, and with the use of pipelining you can combine cmdlets together to allow for creative results. However, just like from a Windows command prompt, a single line of code may not be able to provide you with the ability to do everything you desire. From the Windows command prompt, it is common to use a .bat file to group multiple commands into a single file, but that will not work in Exchange Management Shell. But, do not fear. PowerShell offers support for a scripting language, based on the Microsoft .NET Framework, and those scripts can be used to automate tasks or run multiple cmdlets together when pipelining is not appropriate. The Shell lets you create scripts, assign variables in the scripts, perform looping operations, and use conditional logic in the scripts. This is all done within a text file using PowerShell cmdlets. When you save the text file with a .ps1 extension, it is executable from Exchange Management Shell.
By creating your own library of these .ps1 scripts, you can automate tasks and efficiently run your scripts on any computer that has Exchange Management Shell installed on it. The following example illustrates how to create a script to perform the five steps necessary to configure Messaging Records Management.
Create a text file with a .ps1 extension. In the example that follows, the file will be called C:\Users\Administrator\MRM_Retention.ps1. |
Five steps are involved in configuring Messaging Records Management. This is commonly configured from Exchange Management Console (prior to Service Pack 1) because each step is performed in a unique place and no single cmdlet will perform all five steps. However, in the Console, there is no single wizard that will perform all five steps either. Therefore, you want to create a script to perform all five steps together in a PowerShell script. |
New-ManagedFolder -Name "ObjectName" -FolderName "FolderName" PS C:\Users\Administrator> New-ManagedFolder -Name "Retention" -FolderName "Retention" |
Step 1: Create a new managed custom folder. |
$AgeLimit = New-TimeSpan -Day ValueInDays PS C:\Users\Administrator> $AgeLimit = New-TimeSpan -Day 1100 |
Create a variable to use in step 2. |
New-ManagedContentSettings -Name "ContentSettingsName" -FolderName "FolderName" -MessageClass "MessageClassType" -RetentionEnabled $boolean value -AgeLimitForRetention $AgeLimit -RetentionAction RetentionActionType PS C:\Users\Administrator> New-ManagedContentSettings -Name "Retention Settings for Retention Folder" -FolderName "Retention" -MessageClass * -RetentionEnabled: $true -AgeLimitForRetention $AgeLimit -RetentionAction PermanentlyDelete |
Step 2: Create managed content settings for the 3 Year Retention Folder, which permanently deletes all items after 3 years or 1,100 days. |
New-ManagedFolderMailboxPolicy -Name "PolicyName" -ManagedFolderLinks "Folder(s)ToBeLinked ToPolicy" PS C:\Users\Administrator>New- ManagedFolderMailboxPolicy -Name "Executives Mailbox Policy" -ManagedFolderLinks "Retention" |
Step 3: Create a managed folder mailbox policy. |
Set-Mailbox -Identity MailboxUsername -ManagedFolderMailboxPolicy "PolicyName" PS C:\Users\Administrator>Set-Mailbox -Identity Administrator -ManagedFolderMailboxPolicy "Executives Mailbox Policy" |
Step 4: Apply the managed folder mailbox policy to a mailbox. |
PS C:\Users\Administrator>$ServerName = cmd /c echo %computername% PS C:\Users\Administrator>Set- MailboxServer -ID $ServerName -ManagedFolderAssistantSchedule "Schedule" PS C:\Users\Administrator>Set- MailboxServer -ID $ServerName -ManagedFolderAssistantSchedule "Sun.12:00-Sun.11:00" |
Step 5: Schedule the Managed Folder Assistant to run each day. |
PS C:\Users\Administrator> Start-ManagedFolderAssistant |
Alternate step 5: Start the Managed Folder Assistant manually. |
# Step 1: Create a new managed custom folder. New-ManagedFolder -Name "Retention" -FolderName "Retention" # Create a variable, "$AgeLimit," to use in Step Number 2. $AgeLimit = New-TimeSpan -Day 1100 # Step 2: Create managed content settings for the 3 Year Retention Folder that permanently deletes all items after 3 years or 1100 days. New-ManagedContentSettings -Name "Retention Settings for Retention Folder" -FolderName "Retention" -MessageClass * -RetentionEnabled:$true -AgeLimitForRetention $AgeLimit -RetentionAction PermanentlyDelete # Step 3: Create a managed folder mailbox policy. New-ManagedFolderMailboxPolicy -Name "Executives Mailbox Policy" -ManagedFolderLinks "Retention" # Step 4: Apply the managed folder mailbox policy to a mailbox. Set-Mailbox -Identity Administrator -ManagedFolderMailboxPolicy "Executives Mailbox Policy" # Step 5: Start the Managed Folder Assistant manually. Start-ManagedFolderAssistant |
The completed script with all steps combined in a file. The # sign indicates a remark, and that line will not be executed. Save this file with a name such as C:\Users\Administrator>MRM_Retention.ps1. |
PS C:\Users\Administrator>.\ MRM_Retention.ps1 |
Run the script as shown in Figure 3-5. |
Figure 3-5 Running the MRM_Retention.ps1 script created in the example
Figures 3-6, 3-7, 3-8, and 3-9 show the results after the script has been run.
Figure 3-6 Custom folder and content settings on a folder viewed from the Exchange Management Console
Figure 3-7 Managed folder mailbox policy viewed from the Exchange Management Console
Figure 3-8 Executives mailbox policy linked to a user, as viewed from the Exchange Management Console
Figure 3-9 Retention folder viewed on user's Outlook Web App client
Registry Modifications with PowerShell
It is very easy to modify the registry of a server by using Exchange Management Shell and the Set-ItemProperty cmdlet. Performing the registry change from within Exchange Management Shell means that you can incorporate the change into a .ps1 script, and you can also pipeline it to multiple servers as needed. You must have permission to make this change or your attempt will fail. The examples in the following table illustrate how to change the timeout values for the OWA cookies used by forms-based authentication on a Client Access Server.
Use the following cmdlets at your own risk.
Set-ItemProperty RegistryPath -Name TimeoutType -Value TimeInMinutes -Type RegistryValueType PS C:\Users\Administrator> Set-ItemProperty "HKLM:\SYSTEM\ CurrentControlSet\Services\ MSExchange OWA" -Name PrivateTimeout -Value 360 -Type Dword |
This example sets the Private Computer cookie timeout value to 360 minutes, or 6 hours, for the Outlook Web App client. |
Set-ItemProperty RegistryPath -Name TimeoutType -Value TimeInMinutes -Type RegistryValueType PS C:\Users\Administrator> Set-ItemProperty "HKLM:\SYSTEM\ CurrentControlSet\Services\ MSExchange OWA" -Name PublicTimeout -Value 30 -Type Dword |
This example sets the Public Computer cookie timeout value to 30 minutes for the Outlook Web App client. |
Understanding Quotes
PowerShell uses four different types of quotes. As an administrator, you are most interested in single ordinary and double ordinary quotes. A developer would be more interested in the here-strings. The four types of quotes are explained in the following table.
Single ordinary quotes: $a="Champs" 'World $a' => World $a |
In single quotes, variable names are not expanded and escape sequences are not interpreted. |
Double ordinary quotes: $a="Champs""World $a" => World Champs |
Inside double quotes, variable names are replaced with their values and PowerShell escape sequences are interpreted. |
Single here-strings: $b="Two" $x = @' " Easy as One $b Three ! " '@ $x produces: " Easy as One $b Three ! " |
In single here-strings, variable names are not expanded and escape sequences are not interpreted. A single here-string begins with @' and ends with '@. PowerShell here-strings are similar to here-documents in Perl. |
Double here-strings: $b="Two" $x = @" " Easy as One Two Three ! " "@ $x produces: " Easy as One Two Three ! " |
Inside double here-strings, variable names are replaced with their values and PowerShell escape sequences are interpreted. A double here-string begins with @" and ends with "@. PowerShell here-strings are similar to here-documents in Perl. |