IT Praktyk Blog

How don't mock Exchange objects

Posted May 09, 2016; Last update June 02, 2016

Introduction

From some time I read and watch presentations about Pester and try use it with scripts wrote by me. Due that most of them is related to Microsoft Exchange Server specially I tried understand how I can mock cmdlets what are not available in standard PowerShell - like Get-ExchangeServer.

So after preparation and contemplation I wrote the first function designed to mock Get-ExchangeServer.

Action

As a base I took the function TestUser what you can see in the Dave’s Wyatt post ‘Testing Script Modules with Pester’ published on the Hey, Scripting Guy! Blog.

I checked what object type is returned by Get-ExchangeServer cmdlet - below is only partial output, full is available here.


[PS] > Get-ExchangeServer | Get-Member

   TypeName: Microsoft.Exchange.Data.Directory.Management.ExchangeServer

Name                            MemberType            Definition
----                            ----------            ----------
Clone                           Method                System.Object Clone(), System.Object ICloneable.Clone()
CopyChangesFrom                 Method                void IConfigurable.CopyChangesFrom(Microsoft.Exchange.Data.ICo...
Equals                          Method                bool Equals(System.Object obj)
GetHashCode                     Method                int GetHashCode()
GetProperties                   Method                System.Object[] GetProperties(System.Collections.Generic.IColl...

[...]

The reference of ExchangeServer class can be found on the MSDN page.

So I wrote the function New-MockedExchangeServer


<#
.SYNOPSIS
  Function intended to create Exchange Server object to use with Mock in Pester

      THIS FUNCTION DOESN'T WORK - IT IS EXAMPLE HOW YOU CAN'T MOCK !

.DESCRIPTION
  Function intended to create Exchange Server object to use with Mock in Pester.

.PARAMETER Name
  Name of Exchange server.

.PARAMETER AdminDisplaVersion
  Value for AdminDisplaVersion .

.PARAMETER IsClientAccessServer
  Set to true if server has installed Client Access Role.

.PARAMETER IsFrontendTransportServer
  Set to true if server has installed Client Access Role.

.PARAMETER IsHubTransportServer
  Set to true if server has installed Mailbox Role.

.PARAMETER IsMailboxServer
  Set to true if server has installed Mailbox Role.

.PARAMETER IsUnifiedMessagingServer
  Set to true if server has installed Mailbox Role.

.PARAMETER IsEdgeServer
  Set to true if a server is a Edge.

.EXAMPLE
  PS C:\> New-MockedExchangeServer

.NOTES
  AUTHOR: Wojciech Sciesinski, wojciech[at]sciesinski[dot]net
  KEYWORDS: PowerShell

  VERSIONS HISTORY
  0.1.0 -  2016-05-08 - initial version what doesn't work

  LICENSE
  Copyright (c) 2016 Wojciech Sciesinski
  This function is licensed under The MIT License (MIT)
  Full license text: https://opensource.org/licenses/MIT

#>
function New-MockedExchangeServer {
  [CmdletBinding(DefaultParameterSetName = 'IsNonEdgeServer')]
  [OutputType('Microsoft.Exchange.Data.Directory.Management.ExchangeServer')]
  param (
      [Parameter(ParameterSetName = 'IsEdgeServer',
                 ValueFromPipelineByPropertyName = $true)]
      [Parameter(ParameterSetName = 'IsNonEdgeServer',
                 ValueFromPipelineByPropertyName = $true)]
      [String]$Name = 'EX-1',
      [Parameter(ParameterSetName = 'IsEdgeServer')]
      [Parameter(ParameterSetName = 'IsNonEdgeServer')]
      [String]$AdminDisplaVersion = 'Version 15.0 (Build 1178.4)',
      [Parameter(ParameterSetName = 'IsNonEdgeServer')]
      [bool]$IsClientAccessServer = $true,
      [Parameter(ParameterSetName = 'IsNonEdgeServer')]
      [bool]$IsFrontendTransportServer = $true,
      [Parameter(ParameterSetName = 'IsNonEdgeServer')]
      [bool]$IsHubTransportServer = $true,
      [Parameter(ParameterSetName = 'IsNonEdgeServer')]
      [bool]$IsMailboxServer = $true,
      [Parameter(ParameterSetName = 'IsNonEdgeServer')]
      [bool]$IsUnifiedMessagingServer = $true,
      [Parameter(ParameterSetName = 'IsEdgeServer')]
      [ValidateSet($true)]
      [bool]$IsEdgeServer
  )

  Begin {

  }
  Process {

      $ExchangeServer = New-Object -TypeName Microsoft.Exchange.Data.Directory.Management.ExchangeServer

      $ExchangeServer.Name = $Name
      $ExchangeServer.AdminDisplayVersion = $AdminDisplaVersion

      switch ($PsCmdlet.ParameterSetName) {
          'IsEdgeServer' {
              $ExchangeServer.IsEdgeServer = $true
              $ExchangeServer.IsClientAccessServer = $false
              $ExchangeServer.IsFrontendTransportServer = $false
              $ExchangeServer.IsHubTransportServer = $false
              $ExchangeServer.IsMailboxServer = $false
              $ExchangeServer.IsUnifiedMessagingServer = $false
          }

          'IsNonEdgeServer' {

              $ExchangeServer.IsEdgeServer = $false
              $ExchangeServer.IsClientAccessServer = $IsClientAccessServer
              $ExchangeServer.IsFrontendTransportServer = $IsFrontendTransportServer
              $ExchangeServer.IsHubTransportServer = $IsHubTransportServer
              $ExchangeServer.IsMailboxServer = $IsMailboxServer
              $ExchangeServer.IsUnifiedMessagingServer = $IsUnifiedMessagingServer

          }
      }

  }
  End {

      Return $ExchangeServer

  }
}

Results

Result 1

When the function New-MockedExchangeServer is run on a workstation.


PS > ipmo Scripts:\Pester-ExchangeServer\Functions\New-MockedExchangeServer.ps1
PS > New-MockedExchangeServer
New-Object : Cannot find type [Microsoft.Exchange.Data.Directory.Management.ExchangeServer]: verify that the assembly
containing this type is loaded.
At C:\Users\Wojtek\Documents\Scripts\1-MyOnGitHub\Pester-ExchangeServer\Functions\New-MockedExchangeServer.ps1:70
char:20
+ ... ageServer = New-Object -TypeName Microsoft.Exchange.Data.Directory.Ma ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

The property 'Name' cannot be found on this object. Verify that the property exists and can be set.
At C:\Users\Wojtek\Documents\Scripts\1-MyOnGitHub\Pester-ExchangeServer\Functions\New-MockedExchangeServer.ps1:72
char:3
+         $ExchangeServer.Name = $Name
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

The property 'AdminDisplayVersion' cannot be found on this object. Verify that the property exists and can be set.
At C:\Users\Wojtek\Documents\Scripts\1-MyOnGitHub\Pester-ExchangeServer\Functions\New-MockedExchangeServer.ps1:73
char:3
+         $ExchageServer.AdminDisplayVersion = $AdminDisplaVersion
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

Result 2

When the function New-MockedExchangeServer is run on Exchange Server - directly in EMS.


[PS] Desktop:\>ipmo .\New-MockedExchangeServer.ps1
[PS] Desktop:\>New-MockedExchangeServer
The property 'Name' cannot be found on this object. Verify that the property exists and can be set.
At C:\Users\Administrator.EX2013\Desktop\New-MockedExchangeServer.ps1:72 char:3
+         $ExchangeServer.Name = $Name
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyNotFound

'AdminDisplayVersion' is a ReadOnly property.
At C:\Users\Administrator.EX2013\Desktop\New-MockedExchangeServer.ps1:73 char:3
+         $ExchageServer.AdminDisplayVersion = $AdminDisplaVersion
+         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException

'IsEdgeServer' is a ReadOnly property.
At C:\Users\Administrator.EX2013\Desktop\New-MockedExchangeServer.ps1:87 char:5
+                 $ExchageServer.IsEdgeServer = $false

[...]

'IsUnifiedMessagingServer' is a ReadOnly property.
At C:\Users\Administrator.EX2013\Desktop\New-MockedExchangeServer.ps1:92 char:5
+                 $ExchageServer.IsUnifiedMessagingServer = $IsUnifiedMessagingServer
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : PropertyAssignmentException


Name                Site                 ServerRole  Edition     AdminDisplayVersion
----                ----                 ----------  -------     -------------------
                                         None        Unknown


Summary

As a summary I know how I can’t mock Exchange Server objects. The New-MockedExchangeServer function need to be changed to return the object with the System.Management.Automation.PSObject type name.