Archive for December, 2011

Function: New-LocalExchangeConnection – Ensure Your PowerShell Script is Connected to Exchange 2010

December 28th, 2011 11 comments
Download PDF

When writing scripts that execute commands on an Exchange server, for Exchange 2010, it’s important to ensure that you’re running within a session connected to an Exchange server, and that all Exchange cmdlets are available. In Exchange 2007, we could load the Exchange snapins. But 2010 doesn’t use snapins. Some people would say that you can simply load the modules, but loading the modules bypasses RBAC, and is thus, not recommended. Mike Pfeiffer wrote a great article Managing Exchange 2010 with Remote PowerShell that sheds some light. It’s worth a read.

A solution around this is to run a PowerShell script that comes built into Exchange 2010. This makes available the Connect-ExchangeServer cmdlet, which will connect via remote PowerShell to Exchange. We can specify a server, or let the -auto option connect to the best server via autodiscover. New-LocalExchangeConnection is a function I wrote to connect:

function New-LocalExchangeConnection	{ 
	[cmdletBinding(SupportsShouldProcess = $true)]
	Write-Verbose "Checking for Exchange Management Shell"
	$Sessions = Get-PSSession | Where-Object {$_.ConfigurationName -eq "Microsoft.Exchange"}
	if (!($Sessions)){
		if (Test-Path "$env:ExchangeInstallPath\bin\RemoteExchange.ps1"){
			Write-Verbose "Exchange Management Shell not found - Loading..."
			. "$env:ExchangeInstallPath\bin\RemoteExchange.ps1"
			Write-Verbose "Exchange Management Shell loaded"
			Write-Verbose "Connecting to Exchange server"
			Connect-ExchangeServer -auto
			if (Get-PSSession | Where-Object {$_.ConfigurationName -eq "Microsoft.Exchange"}){
				Write-Verbose "Connected to Exchange Server"
				Write-Host "An error has occurred" -ForegroundColor red
			Write-Warning "Exchange Management Shell is not available on this computer"
		Write-Verbose "Exchange Management Shell already loaded"
} # end function New-LocalExchangeConnection

Calling this within your script will make ensuring that your script is running with access to Exchange cmdlets much simpler.

Function: Set-ModuleStatus – PowerShell Function for Loading and Verifying Modules

December 27th, 2011 12 comments
Download PDF

PowerShell-logo-128x84Often in my PowerShell scripts, I need to either load a specific module, or verify it’s loaded. Manually, of course, we can use Get-Module, Import-Module, etc. But in automation scripts, we need to programtically make sure the module is loaded or load it if it’s not. I wrote this function and it’s worked well for me. introducing Get-ModuleStatus:

function Set-ModuleStatus { 
	[CmdletBinding(SupportsShouldProcess = $True)]
	param	(
		[parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No module name specified!")] 
		[string] $name
		# Executes once for each pipeline object
		# the $_ variable represents the current input object		
		if (!(Get-Module -name "$name")) { 
			if (Get-Module -ListAvailable | Where-Object Name -eq "$name") { 
				Import-Module -Name "$name" 
				# module was imported
				# return $true
			} else {
				# module was not available
				# return $false
		} else {
			# Write-Output "$_ module already imported"
			# return $true
	} # end PROCESS
} # end function Set-ModuleStatus

Call it supplying the module name, such as

Set-ModuleStatus Lync

You can use logic such as

if (Set-ModuleStatus Lync){Write-Host "Lync module is loaded}else{Write-Host "Lync module is NOT loaded" -ForegroundColor red}

Simple and effective. You can also pipe module names to it, such as:

“lync”,”activedirectory” | Set-ModuleStatus


v1.2 – 02-07-2014 –

v1.1 – 09-17-2012 -

v1.0 Get-ModuleStatus.ps1

Categories: PowerShell Tags: ,

Function: New-Password – Creating Passwords with PowerShell

December 26th, 2011 2 comments
Download PDF

PowerShell logoWhen creating new accounts, an admin needs to assign a password. We often then check the box to force a user to change their password when they logon for the first time. Some organizations will use a ‘default’ password for all new accounts. That’s fraught with security implications, and I’ve never recommended it. The downside is that you, as an admin, need to think up a password for each new account. I know how it is – you look around at things on your desk, items on the wall, looking for ideas. Then you have to make sure your super password meets your organizations password requirements, including length and complexity. Well, no more!

Enter New-Password. This function takes one simple input – length. It then spits out a password of said length, using upper and lower case letters, numbers, and punctuation, as well as a phonetic version. If you choose not to use some of the punctuation characters, feel free to just put a ‘#’ in front of that particular line.

function New-Password	{
  Displays a complex password.

  Displays a complex password. Output includes password, and phonetic breakdown of the password.

  Version                 : 1.3
  Wish List               :
  Rights Required         : No special rights required
                          : If script is not signed, ExecutionPolicy of RemoteSigned (recommended) or Unrestricted (not recommended)
                          : If script is signed, ExecutionPolicy of AllSigned (recommended), RemoteSigned, 
                            or Unrestricted (not recommended)
  Sched Task Required     : No
  Lync/Skype4B Version    : N/A
  Author/Copyright        : © Pat Richard, Skype for Business MVP - All Rights Reserved
  Email/Blog/Twitter      : @patrichard
  Dedicated Post          :
  Disclaimer              : You running this script means you won't blame me if this breaks your stuff. This script is
                            provided AS IS without warranty of any kind. I disclaim all implied warranties including, 
                            without limitation, any implied warranties of merchantability or of fitness for a particular
                            purpose. The entire risk arising out of the use or performance of the sample scripts and 
                            documentation remains with you. In no event shall I be liable for any damages whatsoever 
                            (including, without limitation, damages for loss of business profits, business interruption,
                            loss of business information, or other pecuniary loss) arising out of the use of or inability
                            to use the script or documentation. 
  Acknowledgements        : 
  Assumptions             : ExecutionPolicy of AllSigned (recommended), RemoteSigned or Unrestricted (not recommended)
  Limitations             : 
  Known issues            : None yet, but I'm sure you'll find some!                        

Function: New-Password – Creating Passwords with PowerShell
.EXAMPLE New-Password -Length <integer> Description ----------- Creates a password of the defined length .EXAMPLE New-Password -Length <integer> -ExcludeSymbols Description ----------- Creates a password of the defined length, but does not utilize the following characters: !$%^-_:;{}<># &@]~ .INPUTS This function does support pipeline input. #> #Requires -Version 3.0 [CmdletBinding(SupportsShouldProcess = $true)] param( #Defines the length of the desired password [Parameter(ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $True)] [ValidateNotNullOrEmpty()] [ValidatePattern("[0-9]")] [int] $Length = 12, #When specified, only uses alphanumeric characters for the password [Parameter(ValueFromPipeline = $False, ValueFromPipelineByPropertyName = $True)] [switch] $ExcludeSymbols ) PROCESS { $pw = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" if (!$ExcludeSymbols) { $pw += "!$%^-_:;{}<># &@]~" } $password = -join ([Char[]]$pw | Get-Random -count $length) Write-Output "`nPassword: $password`n" ForEach ($character in [char[]]"$password"){ [string]$ThisLetter = $character switch ($ThisLetter) { a {$ThisWord = "alpha"} b {$ThisWord = "bravo"} c {$ThisWord = "charlie"} d {$ThisWord = "delta"} e {$ThisWord = "echo"} f {$ThisWord = "foxtrot"} g {$ThisWord = "golf"} h {$ThisWord = "hotel"} i {$ThisWord = "india"} j {$ThisWord = "juliett"} k {$ThisWord = "kilo"} l {$ThisWord = "lima"} m {$ThisWord = "mike"} n {$ThisWord = "november"} o {$ThisWord = "oscar"} p {$ThisWord = "papa"} q {$ThisWord = "quebec"} r {$ThisWord = "romeo"} s {$ThisWord = "sierra"} t {$ThisWord = "tango"} u {$ThisWord = "uniform"} v {$ThisWord = "victor"} w {$ThisWord = "whiskey"} x {$ThisWord = "xray"} y {$ThisWord = "yankee"} z {$ThisWord = "zulu"} 1 {$ThisWord = "one"} 2 {$ThisWord = "two"} 3 {$ThisWord = "three"} 4 {$ThisWord = "four"} 5 {$ThisWord = "five"} 6 {$ThisWord = "six"} 7 {$ThisWord = "seven"} 8 {$ThisWord = "eight"} 9 {$ThisWord = "nine"} 0 {$ThisWord = "zero"} ! {$ThisWord = "exclamation"} $ {$ThisWord = "dollar"} % {$ThisWord = "percent"} ^ {$ThisWord = "carat"} - {$ThisWord = "hyphen"} _ {$ThisWord = "underscore"} : {$ThisWord = "colon"} `; {$ThisWord = "semicolon"} `{ {$ThisWord = "left-brace"} `} {$ThisWord = "right-brace"} `/ {$ThisWord = "backslash"} `< {$ThisWord = "less-than"} `> {$ThisWord = "greater-than"} `# {$ThisWord = "pound"} `& {$ThisWord = "ampersand"} `@ {$ThisWord = "at"} `] {$ThisWord = "right-bracket"} `~ {$ThisWord = "tilde"} default {$ThisWord = "space"} } if ($ThisLetter -cmatch $ThisLetter.ToUpper()){ $ThisWord = $ThisWord.ToUpper() } $phonetic = $phonetic+" " +$ThisWord } $phonetic = $phonetic.trim() Write-Output "Phonetic: $phonetic" "Password: $password`nPhonetic: $phonetic" | clip Write-Output "`n`nThis information has been sent to the clipboard" } END{ Remove-Variable ThisWord Remove-Variable ThisLetter Remove-Variable Password Remove-Variable Phonetic Remove-Variable Pw } } # end function New-Password

Now, stick that function in your PowerShell profile. Each time you need a new password, use

New-Password -Length [number]

such as

New-Password -Length 12

And you now have a password to use.

12 character password







You can also specify -ExcludeSymbols to return only an alphanumeric password, bypassing the added complexity of using non-alphanumeric symbols.

New-Password -Length 12 -ExcludeSymbols

12 character alphanumeric password

Functions: Get-LocalAdminGroupMembership and Set-LocalAdminGroupMembership – Local Admin Group Membership on Remote Machines

December 22nd, 2011 No comments
Download PDF

PowerShell-logo-128x84While writing some PowerShell scripts to automate the installation of Exchange on over 100 servers, I needed to set and then verify that a group (in this case, “Exchange Trusted Subsystem”) was a member of the local admins group on some remote servers.

We start with Get-LocalAdminGroupMembership. This function merely checks the local admins group on a remote server to see if the group to be added is already a member. If it is, it returns $true, if not, $false. We need to pass it two variables: $ComputerName, and $Member. We don’t need to run this function. It’s called from the second function.

function Get-LocalAdminGroupMembership	{
		[Parameter(Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		$ComputerNameÂ&nbsp;= &quot;.&quot;,
		[Parameter(Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
	if($ComputerNameÂ&nbsp;-eqÂ&nbsp;&#039;.&#039;){$ComputerNameÂ&nbsp;= (get-WmiObjectÂ&nbsp;win32_computersystem).Name}
	$computer = [ADSI](&quot;WinNT://&quot; + $ComputerNameÂ&nbsp;+ &quot;,computer&quot;)
	$Group = $computer.psbase.children.find(&quot;Administrators&quot;)
	$members= $Group.psbase.invoke(&quot;Members&quot;) | % {$_.GetType().InvokeMember(&quot;Name&quot;, &#039;GetProperty&#039;, $null, $_, $null)}
	if ($members -matchÂ&nbsp;$member){return $true}else{return $false}
} # end function Get-LocalAdminGroupMembership


The second function does all the heavy lifting.

function Set-LocalAdminGroupMembershipÂ&nbsp;{
		[Parameter(Position=0, Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		[string]$ComputerNameÂ&nbsp;= &#039;.&#039;,
		[Parameter(Position=1, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		[Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
		[string]$Domain = $env:USERDNSDOMAIN

		if (!(Get-LocalAdminGroupMembershipÂ&nbsp;-ComputerNameÂ&nbsp;&quot;$ComputerName&quot; -MemberÂ&nbsp;&quot;$Member&quot;)){
			if($ComputerNameÂ&nbsp;-eqÂ&nbsp;&#039;.&#039;){$ComputerNameÂ&nbsp;= $env:ComputerName.ToUpper()}    

  			$adsiÂ&nbsp;= [ADSI]&quot;WinNT://$ComputerName/administrators,group&quot;
	  		Write-Host &quot;Not connected to a domain.&quot; -ForegroundColorÂ&nbsp;&quot;red&quot;
		} else {
			Write-Host &quot;`&quot;$Account`&quot; is already a local admin on $ComputerName&quot; -ForegroundColorÂ&nbsp;yellow
		Get-LocalAdminGroupMembershipÂ&nbsp;-ComputerComputerÂ&nbsp;&quot;$ComputerName&quot; -MemberÂ&nbsp;&quot;$Member&quot;
	}# Process
} # end function Set-LocalAdminGroupMembership

We call Set-LocalAdminGroupMembership and pass it the same parameters, $ComputerName and $Member

Set-LocalAdminGroupMembershipÂ&nbsp;-ComputerNameÂ&nbsp;mycomputerÂ&nbsp;-Member &quot;Exchange Trusted Subsystem&quot;

The function will add the group to the local admins group, and then do a Get-LocalAdminGroupMembership for that same group and dump the results to the screen.

Function: New-Pause – Pausing PowerShell Scripts

December 21st, 2011 No comments
Download PDF

Yesterday, I wrote about a sleep function to cause a predetermined delay in a script. Today, I give you a short function, New-Pause. New-Pause stops a script and waits for the user to press a key before continuing.

function New-Pause {
 Write-Host &quot;Press any key to continue&quot; -ForegroundColor green
 $x = $host.UI.RawUI.ReadKey(&quot;NoEcho,IncludeKeyDown&quot;)
} # end function New-Pause

Call the function using



Once any key is pressed, your script can continue.

Categories: PowerShell Tags: ,

Function: New-Sleep – When You Need a Delay

December 20th, 2011 6 comments
Download PDF

On a recent project, I needed some PowerShell scripts to wait for a few seconds just to ensure that some other processes were finished and I wasn’t issuing too many commands to some Exchange servers too quickly. I came up with this little function:

function New-Sleep {
		[parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Mandatory = $true, HelpMessage = "No time specified")]
	for ($i=1; $i -lt $s; $i++) {
	Write-Progress -Activity "Waiting $s seconds..." -PercentComplete (100/$s*$i) -CurrentOperation "$TimeLeft seconds left ($i elapsed)" -Status "Please wait"
	Start-Sleep -Seconds 1
	Write-Progress -Completed $true -Status "Please wait"
} # end function New-Sleep

Call the function like this:

New-Sleep -s 60

Where the value of $s is the number of seconds you want to sleep. The display tells you how long your sleeping for, how much time is left, and how much time has elapsed.



Download the function below.


v1.0 New-Sleep.ps1

Categories: PowerShell Tags: ,

December 2011 Technical Rollup: Unified Communications

December 12th, 2011 No comments
Download PDF



OpsVault — Operate and Optimize IT

Microsoft Premier Support UK – Site Home – TechNet Blogs

Antigen & Forefront

Forefront Team Blog – Site Home – TechNet Blogs

Forefront Server Security Support Blog – Site Home – TechNet Blogs


  1. Exchange Server 2010 SP2
  2. What’s New in Exchange 2010 SP2
  3. Exchange Server 2010 SP2 Unified Messaging Language Packs
  4. Exchange Server 2010 SP2 Help

Exchange Team Blog – Site Home – TechNet Blogs

MCS UK Unified Communications Blog – Site Home – TechNet Blogs

Hosted Messaging Collaboration

Lync, Office Communication Server & LiveMeeting

  1. Lync Server 2010 Hotfix KB 2493736 (Cumulative Update 4)
  2. Lync Server 2010 Documentation Help File
  3. Lync Server 2010 Mobility Guide
  4. Lync Server 2010 Mobility Service and Lync Server 2010 Autodiscover Service

NextHop – Site Home – TechNet Blogs

Lync Team Blog – Site Home – TechNet Blogs



NextHop – Site Home – TechNet Blogs

The Master Blog – Site Home – TechNet Blogs

New KBs

Antigen & Forefront

Microsoft Forefront Online Protection for Exchange:

  1. “A synchronization error occurred between your Active Directory environment and the Hosted Archive service” error message in Exchange Hosted Archive
  2. “An unexpected error has occurred” error when you delete junk email messages from the spam quarantine mailbox in Forefront Online Protection for Exchange
  3. The sign-in page is not displayed, or a “Page not found” error occurs, after a new version of the Forefront Online Protection for Exchange Administration Center is released
  4. A blank webpage appears when you click the answer-back URL in a message that is encrypted by Exchange Hosted Encryption in Windows Live Hotmail
  5. How to add a disclaimer or footer to outgoing mail messages through Forefront Online Protection for Exchange
  6. The footer for outgoing email messages does not work in Forefront Online Protection for Exchange
  7. How to create a policy for a group of users in a stand-alone Forefront Online Protection for Exchange environment


Microsoft Exchange Server 2003 Enterprise Edition

  1. You cannot connect to Outlook Mobile Access on a server that is running Exchange Server 2003
  2. How to redirect an HTTP connection to HTTPS for Outlook Web Access clients and how to redirect the Default Web Site to point to the Exchange virtual directory
  3. Error message when you try to synchronize a Windows Mobile-based device by using Exchange ActiveSync for Exchange 2003 or for Exchange 2007 or for Exchange 2010: “Synchronization failed”
  4. Error message when you use ActiveSync to synchronize a Windows Mobile-based device to Exchange 2003: “0x85030027 — The Exchange Server requires certificates to log on”

Microsoft Exchange Server 2003 Service Pack 2

  1. Incremental changes of free/busy information may not be successful replicated from Exchange Server 2010 to Exchange Server 2003

Microsoft Exchange Server 2003 Standard Edition

  1. The W3wp.exe process uses almost 100 percent of CPU resources when you synchronize large email messages in Exchange Server 2003 Service Pack 2

Microsoft Exchange Server 2007 Enterprise Edition

  1. The Fax feature stops working in Exchange Server 2007 SP3
  2. Store.exe intermittently stops responding in an Exchange Server 2007 environment

Microsoft Exchange Server 2007 Service Pack 1

  1. Email messages cannot be delivered to the Hub Transport server in an Exchange Server 2007 environment

Microsoft Exchange Server 2007 Standard Edition

  1. “HTTP 400 Bad Request” error when you connect to an Exchange Server 2007 mailbox by using Outlook Web App
  2. The synchronization session of the mobile device fails, and you receive error code “0X85010015” when you try to synchronize a mobile device by using Exchange ActiveSync in Exchange Server 2007

Microsoft Exchange Server 2010 Enterprise

  1. Office Communications Server 2007 IM integration with Exchange 2010 OWA does not work for all users
  2. “Cannot open your default e-mail folder” error when users try to open their mailboxes in Outlook after migration to Exchange 2010
  3. An Exchange Server 2010 database store grows unexpectedly large
  4. Email message content is missing in OWA
  5. Error when you try to change the default global address list recipient filter in Exchange Server 2010

Microsoft Exchange Server 2010 Standard

  1. Windows Network Load Balancing does not work in an Exchange Server cluster
  2. You receive an error message when you try to create an Exchange Server 2010 DAG

Lync, Office Communication Server & LiveMeeting

Microsoft Office Communicator 2007

  1. Additional authentication prompt is displayed when an external network user signs in to an Office Communicator 2007 client

Microsoft Office Live Meeting 2007

  1. Live Meeting 2007 loads a blank white screen when joining a Live Meeting on Macintosh computer
  2. How to use Microsoft Office Live Meeting 2007 on a Macintosh computer


Microsoft Office Outlook 2003

  1. Description of the Outlook 2003 Junk Email Filter update: November 8, 2011
  2. “80004005-501-4B9-560” synchronization error logs in the Outlook Sync Issues folder

Microsoft Office Outlook 2007

  1. Outlook receives a message that has an attachment that is named “not supported calendar message.ics”

Microsoft Outlook 2000 Standard Edition

  1. Outlook Meeting Request to DL Shows Members As Optional
  2. OL2000: (CW) Sending Pasted Bitmap from Word Behaves Differently

Microsoft Outlook 2010

  1. Description of the Outlook 2010 update: November 8, 2011
  2. You receive an error message when you publish Internet free/busy information in Outlook 2010
  3. The Mailbox Cleanup Wizard does not start in Outlook 2010 when the mailbox is full
  4. Outlook 2010 does not display Journal entries for a contact
  5. Outlook Issues that occur when you use the ExtractOrganizedMeetings registry value

Exchange Server 2010 SP2 Is Now Available

December 5th, 2011 No comments
Download PDF

Microsoft has released Service Pack 2 (SP2) for Exchange Server 2010. Release Notes for Exchange 2010 SP2 includes a list of known issues.

The 535MB download is just like RTM – a full install package. Existing installations can be upgraded, as new installs can be completed with the Service Pack integrated.


What’s New in Exchange 2010 SP2

The What’s New in Exchange 2010 SP2 has comprehensive list of the changes and enhancements, including:

Address Book Policies

This is a long sought after feature which allows the segmentation of the Global Address List. This essentially allows an organization to have different address books visible to different users and/or groups. This is great, especially in large organization that may want users to just see users in their division, or if an org wants to do a multi-tenant scenario.

Outlook Mobile Access (OWA mini)

This is essentially the old Outlook Mobile Access brought back to life, which allows devices with small screens, such as mobile devices, to see a simple to use web page for accessing their mailbox. This is great for devices that don’t support Exchange ActiveSync.

Hybrid Configuration Wizard

This feature is based around on-premise and cloud based scenarios such as Office365.

OWA Cross-Site redirection

Redirection of client connections across AD sites is now possible.

Installation notes

Schema Updates

The service pack does do schema updates in order to support some of the new features.

Required Role Features

Also, on Client Access Servers (CAS), the IIS 6 WMI Compatibility feature is now required.

Installing from the command line

Upgrading is quite simple. Open a command prompt and navigate to the folder containing the extracted files and run:

Setup /m:upgrade /InstallWindowsComponents

The setup routine will automatically install the Web-WMI feature if needed, and upgrade the server.

Installation of SP2 via command prompt

Installation of SP2 via command prompt

Installation from the graphical user interface (GUI)

As mentioned above, the IIS 6 WMI Compatibility (Web-WMI) feature is required. If you plan to install the Service Pack using the GUI, you must manually add this feature. To install the feature, open PowerShell, and type:

Import-Module ServerManager Add-WindowsFeature web-wmi

As shown below.

Add-WindowsFeature Web-WMI

If you don’t manually install this feature, the service pack installation will fail:

SP2 fails - IIS 6 WMI Compatibility required

SP2 fails – IIS 6 WMI Compatibility required

Once the SP2 file is downloaded, double click on it to extract the files to a folder.

Navigate to the folder containing the extracted files and double click on setup.exe and follow the prompts.

Installation on Database Availability Groups (DAG)

If you are going to apply SP2 to servers that are members of a DAG, run the StartDagServerMaintenance.ps1 script on the server first. This accomplishes several things, including suspending mailboxdatabase copying for each database; prevents the activation of databases on the server and moves active copies on the server to copies on other servers; prevents the server from taking on the PAM role. When finished, run the StopDagServerMaintenance.ps1 script, which allows databases to be activated, begins the copying, and allows the server to become the PAM. Mike Pfeiffer has a great blog post on this process.


Download the Service Pack from the Microsoft Download Center here.

A stand-alone version of the SP2 Help file is available here.

Unified Messaging language packs for SP2 are available here.