Difference between revisions of "PowerShell API Wrapper Tutorial"

[unchecked revision][unchecked revision]
Line 26: Line 26:
  
 
== Importing the MailStore PowerShell API Wrapper ==
 
== Importing the MailStore PowerShell API Wrapper ==
The MailStore PowerShell API Wrapper is implemented as a PowerShell Script Module (''MSSPE.PS.Lib.psm1'') and can thus be imported in a PowerShell session via its manifest (''MSSPE.PS.Lib.psd1'') by using ''Import-Module''.
+
The MailStore PowerShell API Wrapper is implemented as a PowerShell Script Module (''MS.PS.Lib.psm1'') and can thus be imported in a PowerShell session via its manifest (''MS.PS.Lib.psd1'') by using ''Import-Module''.
  
 
Please open a PowerShell session and import the API wrapper module using this command:
 
Please open a PowerShell session and import the API wrapper module using this command:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   Import-Module "C:\MailStore SPE Scripting Tutorial\PowerShell\API-Wrapper\MSSPE.PS.Lib.psd1"
+
   Import-Module "C:\MailStore SPE Scripting Tutorial\PowerShell\API-Wrapper\MS.PS.Lib.psd1"
 
</source>
 
</source>
  
Line 38: Line 38:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   Get-Module MSSPE.PS.Lib | fl
+
   Get-Module MS.PS.Lib | fl
 
</source>
 
</source>
  
Line 44: Line 44:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   (Get-Module MSSPE.PS.Lib).ExportedFunctions
+
   (Get-Module MS.PS.Lib).ExportedFunctions
 
</source>
 
</source>
  
Line 50: Line 50:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   Get-Help *MSSPE*
+
   Get-Help *MSApi*
 
</source>
 
</source>
  
Line 59: Line 59:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   Import-Module '..\API-Wrapper\MSS.PS.Lib.psd1'
+
   Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
   $msspeapiclient = New-MSSPEApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8470 -IgnoreInvalidSSLCerts
+
   $MSApiClient = New-MSApiClient -Username admin -Password admin -ManagementServer localhost -Port 8474 -IgnoreInvalidSSLCerts
   $return = Invoke-MSSPEApiCall $msspeapiclient "GetEnvironmentInfo"
+
   $return = Invoke-MSApiCall $MSApiClient "GetEnvironmentInfo"
 
   $return.Data.result | fl
 
   $return.Data.result | fl
 
</source>
 
</source>
  
The function ''New-MSSPEApiClient'' creates a new API client object which the ''Invoke-MSSPEApiCall'' function uses for API calls. The values for ''-Username'' and ''-Password'' have to be supplied, while ''-ManagementServer'' defaults to "localhost" and  ''-Port'' defaults to "8470". The switch ''-IgnoreInvalidSSLCerts'' has to be set if untrusted certificates are used; otherwise an error occurs.
+
The function ''New-MSApiClient'' creates a new API client object which the ''Invoke-MSApiCall'' function uses for API calls. The values for ''-Username'' and ''-Password'' have to be supplied, while ''-ManagementServer'' defaults to "localhost" and  ''-Port'' defaults to "8474". The switch ''-IgnoreInvalidSSLCerts'' has to be set if untrusted certificates are used; otherwise an error occurs.
  
Apart from the API client object, ''Invoke-MSSPEApiCall'' needs an [[Management_API_-_Function_Reference|API command]] and its parameters if applicable. The command ''[[Management_API_-_Function_Reference#GetEnvironmentInfo|GetEnvironmentInfo]]'' in the script does not have any parameters and returns an object as follows:
+
Apart from the API client object, ''Invoke-MSApiCall'' needs an [[Management_API_-_Function_Reference|API command]] and its parameters if applicable. The command ''[[Management_API_-_Function_Reference#GetEnvironmentInfo|GetEnvironmentInfo]]'' in the script does not have any parameters and returns an object as follows:
  
 
   Type  : JSON
 
   Type  : JSON
 
   Token :  
 
   Token :  
   Data  : @{error=; token=;
+
   Data  : @{error=; token=; statusVersion=2; statusCode=succeeded; percentProgress=; statusText=; result=; logOutput=}
            antiXsrfToken=3bbMS5ztVju5lUE7FQLUFG7CbXzDKdrGjPfQCGFkbWlu;
 
            statusVersion=2; statusCode=succeeded; percentProgress=;
 
            statusText=; result=; logOutput=}
 
  
 
The object's ''Type'' property has the value "JSON" for synchronous API commands or "JOB" for asynchronous API commands (see below); it characterizes the type of the object contained in the ''Data'' property. The ''Token'' property is only relevant for asynchronous API commands.
 
The object's ''Type'' property has the value "JSON" for synchronous API commands or "JOB" for asynchronous API commands (see below); it characterizes the type of the object contained in the ''Data'' property. The ''Token'' property is only relevant for asynchronous API commands.
Line 82: Line 79:
 
   error          :  
 
   error          :  
 
   token          :  
 
   token          :  
  antiXsrfToken  : 3bbMS5ztVju5lUE7FQLUFG7CbXzDKdrGjPfQCGFkbWlu
 
 
   statusVersion  : 2
 
   statusVersion  : 2
 
   statusCode      : succeeded
 
   statusCode      : succeeded
 
   percentProgress :  
 
   percentProgress :  
 
   statusText      :  
 
   statusText      :  
   result          : @{version=8.5.0.9292;
+
   result          : @{version=9.0.3.9845; copyright=Copyright (c) 2005-2014 MailStore Software GmbH; licenseeName=MailStore; licenseeID=23634; serverName=tutorial.mailstore.test; userName=admin; systemProperties=}
                      copyright=Copyright (c) 2005-2013 MailStore Software GmbH;
+
   logOutput      :
                      licenseeName=MailStore Software GmbH; licenseeID=10510;
 
                      serverName=tutorial.msspe.test; userName=admin; systemProperties=}
 
   logOutput      :  
 
  
 
The ''result'' property of that object has the actual return value if the request succeeded as indicated by the ''statusCode'':
 
The ''result'' property of that object has the actual return value if the request succeeded as indicated by the ''statusCode'':
  
   version          : 8.5.0.9292
+
   version          : 9.0.3.9845
   copyright        : Copyright (c) 2005-2013 MailStore Software GmbH
+
   copyright        : Copyright (c) 2005-2014 MailStore Software GmbH
 
   licenseeName    : MailStore Software GmbH
 
   licenseeName    : MailStore Software GmbH
   licenseeID      : 10510
+
   licenseeID      : 23634
   serverName      : tutorial.msspe.test
+
   serverName      : tutorial.mailstore.test
 
   userName        : admin
 
   userName        : admin
   systemProperties : @{processors=System.Object[]; totalPhysicalMemory=4398800896; operatingSystem=Microsoft Windows Server 2012 Standard}
+
   systemProperties : @{processors=System.Object[]; totalPhysicalMemory=2146947072; operatingSystem=Microsoft Windows Server 2012 Standard}
 
    
 
    
 
=== Calling API Wrapper Functions with Parameters ===
 
=== Calling API Wrapper Functions with Parameters ===
For most MailStore SPE Management API commands you need to provide parameters. Of course, the MailStore PowerShell API Wrapper's ''Invoke-MSSPEApiCall'' function can submit these parameters, as demonstrated by the following script (''Example2.ps1'' in the tutorial package):
+
For most MailStore SPE Management API commands you need to provide parameters. Of course, the MailStore PowerShell API Wrapper's ''Invoke-MSApiCall'' function can submit these parameters, as demonstrated by the following script (''Example2.ps1'' in the tutorial package):
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   Import-Module '..\API-Wrapper\MSS.PS.Lib.psd1'
+
   Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
   $msspeapiclient = New-MSSPEApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8470 -IgnoreInvalidSSLCerts
+
   $MSApiclient = New-MSApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8474 -IgnoreInvalidSSLCerts
   $instances = (Invoke-MSSPEApiCall $msspeapiclient "GetInstances" @{instanceFilter = "*"}).Data.result
+
   $return = (Invoke-MSApiCall $MSApiclient "GetInstances" @{instanceFilter = "*"})
 +
  if ($return.Type -eq "JOB") {
 +
      Wait-Job $return.Data
 +
      $instances = (Receive-Job $return.Data).Data.result
 +
  } else {
 +
      $instances = $return.Data.result
 +
  }
 
   foreach ($instance in $instances) {
 
   foreach ($instance in $instances) {
    $users = (Invoke-MSSPEApiCall $msspeapiclient "GetUsers" @{instanceID = $instance.instanceID}).Data.result
+
      $users = (Invoke-MSApiCall $MSapiclient "GetUsers" @{instanceID = $instance.instanceID}).Data.result
    foreach ($user in $users) {
+
      foreach ($user in $users) {
      (Invoke-MSSPEApiCall $msspeapiclient "GetUserInfo" @{instanceID = $instance.instanceID; userName = $user.userName}).Data.result | fl
+
          (Invoke-MSApiCall $MSapiclient "GetUserInfo" @{instanceID = $instance.instanceID; userName = $user.userName}).Data.result | fl
    }
+
      }
}
+
  }
 
</source>
 
</source>
  
The scripts lists details about the users created in a MailStore SPE instance. Because the MailStore PowerShell API Wrapper converts MailStore SPE Management API responses into objects, their properties can be used directly in the script's workflow. The function ''Invoke-MSSPEApiCall'' expects parameters as a hashtable, e.g. ''@{parametername1 = value1; parametername2 = value2;...}''. Parameter names are case sensitive.
+
The scripts lists details about the users created in a MailStore SPE instance. Because the MailStore PowerShell API Wrapper converts API responses into objects, their properties can be used directly in the script's workflow. The function ''Invoke-MSApiCall'' expects parameters as a hashtable, e.g. ''@{parametername1 = value1; parametername2 = value2;...}''. Parameter names are case sensitive.
  
First, a list of all MailStore SPE instances is requested with the API command ''[[Management_API_-_Function_Reference#GetInstances|GetInstances]]'' which returns an array of instances as follows:
+
First, a list of all MailStore SPE instances is requested with the API command ''[[Management_API_-_Function_Reference#GetInstances|GetInstances]]''. In case of many instances this command could be executed asynchronously by the server and return a job object (see below) otherwise an array of instances as follows is returned:
 
    
 
    
 
   instanceID    : test01
 
   instanceID    : test01
   alias          : test1
+
   alias          : tutorial
   displayName    : test01
+
   displayName    : Tutorial Test Instance
   instanceHost  : tutorial.msspe.test
+
   instanceHost  : tutorial.mailstore.test
 
   startMode      : automatic
 
   startMode      : automatic
 
   processID      : 3140
 
   processID      : 3140
Line 131: Line 130:
 
   startStopError :  
 
   startStopError :  
  
The script now iterates over this array using the ''instanceID'' property of each entry as a parameter for the API command ''[[Management_API_-_Function_Reference#GetUsers|GetUsers]]''. The list of users of each instance is then also iterated over and each user's properties is requested via ''[[Management_API_-_Function_Reference#GetUserInfo|GetUserInfo]]'':
+
The script now iterates over this array using the ''instanceID'' property of each entry as a parameter for the API command ''[[Management_API_-_Function_Reference#GetUsers|GetUsers]]''. The list of users of each instance is then also iterated over and each user's properties are requested via ''[[Management_API_-_Function_Reference#GetUserInfo|GetUserInfo]]'':
  
 
For the entry listed above the result could be as follows:
 
For the entry listed above the result could be as follows:
Line 147: Line 146:
  
 
=== Calling API Wrapper Functions for Asynchronous API Commands ===
 
=== Calling API Wrapper Functions for Asynchronous API Commands ===
Management API commands, whose execution typically take more time, are executed asynchronously on the server. The MailStore PowerShell API Wrapper identifies calls of such [[Management_API_-_Using_the_API#Long_Running_Processes|asynchronously executed API commands]] and executes them as [http://technet.microsoft.com/en-us/library/hh847783%28v=wps.620%29.aspx PowerShell Jobs] in the background.
+
The server may decide to execute Management API commands asynchronously if their execution may take more time. The MailStore PowerShell API Wrapper identifies calls of such [[Management_API_-_Using_the_API#Long_Running_Processes|asynchronously executed API commands]] and executes them as [http://technet.microsoft.com/en-us/library/hh847783%28v=wps.620%29.aspx PowerShell Jobs] in the background.
  
 
==== Processing API Wrapper PowerShell Jobs Synchronously ====
 
==== Processing API Wrapper PowerShell Jobs Synchronously ====
Line 153: Line 152:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   Import-Module '..\API-Wrapper\MSSPE.PS.Lib.psd1'
+
   Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
   $msspeapiclient = New-MSSPEApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8470 -IgnoreInvalidSSLCerts
+
   $MSApiclient = New-MSApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8474 -IgnoreInvalidSSLCerts
   $instances = (Invoke-MSSPEApiCall $msspeapiclient "GetInstances" @{instanceFilter = "*"}).Data.result
+
   $return = (Invoke-MSApiCall $MSApiclient "GetInstances" @{instanceFilter = "*"})
   $return = Invoke-MSSPEApiCall $msspeapiclient "VerifyStore" @{instanceID = $instances[0].instanceID; id = "1"}
+
  if ($return.Type -eq "JOB") {
 +
      Wait-Job $return.Data
 +
      $instances = (Receive-Job $return.Data).Data.result
 +
  } else {
 +
      $instances = $return.Data.result
 +
  }
 +
   $return = Invoke-MSApiCall $MSApiclient "VerifyStore" @{instanceID = $instances[0].instanceID; id = "1"}
 
   $return | fl
 
   $return | fl
 
   if ($return.Type -eq "JOB") {
 
   if ($return.Type -eq "JOB") {
Line 166: Line 171:
 
</source>
 
</source>
  
The API command ''[[Management_API_-_Function_Reference#VerifyStore|VerifyStore]]'' called in the script returns an object with the ''Type'' property "JOB".
+
The API commands ''[[Management_API_-_Function_Reference#GetInstances|GetInstances]]'' and ''[[Management_API_-_Function_Reference#VerifyStore|VerifyStore]]'' called in the script regularly return objects with the ''Type'' property "JOB".
  
 
   Type  : JOB
 
   Type  : JOB
   Token : safad479020950b9d11db8c10bf2b17883
+
   Token : sa90edf0029de319e62e856aeb47678325
 
   Data  : System.Management.Automation.PSRemotingJob
 
   Data  : System.Management.Automation.PSRemotingJob
  
Line 178: Line 183:
 
   Type      : JSON
 
   Type      : JSON
 
   Token      :  
 
   Token      :  
   Data      : @{error=; token=;
+
   Data      : @{error=; token=sa90edf0029de319e62e856aeb47678325; statusVersion=32; statusCode=succeeded; percentProgress=100; statusText=; result=; logOutput=}
                antiXsrfToken=m8aLU93JK7fHid6WofHFIqwhBtZTofCyAfrQCGFkbWlu;
+
   RunspaceId : 451b5d8b-dcc3-4eec-820e-3dbd2bcb4c5f
                statusVersion=739; statusCode=succeeded; percentProgress=100;
 
                statusText=; result=; logOutput=}
 
   RunspaceId : f91d1638-b143-465d-b248-7d2f6c0aa843
 
  
 
<p class=msnote>'''Please note:''' The ''RunspaceId'' is generated by the PowerShell automatically and can be ignored here.</p>
 
<p class=msnote>'''Please note:''' The ''RunspaceId'' is generated by the PowerShell automatically and can be ignored here.</p>
Line 190: Line 192:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   Import-Module '..\API-Wrapper\MSSPE.PS.Lib.psd1'
+
   Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
   $msspeapiclient = New-MSSPEApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8470 -IgnoreInvalidSSLCerts
+
   $MSApiclient = New-MSApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8474 -IgnoreInvalidSSLCerts
   $instances = (Invoke-MSSPEApiCall $msspeapiclient "GetInstances" @{instanceFilter = "*"}).Data.result
+
   $instances = (Invoke-MSApiCall $MSApiclient "GetInstances" @{instanceFilter = "*"}).Data.result
   $return = Invoke-MSSPEApiCall $msspeapiclient "VerifyStore" @{instanceID = $instances[0].instanceID; id = "1"}
+
   $return = Invoke-MSApiCall $MSApiclient "VerifyStore" @{instanceID = $instances[0].instanceID; id = "1"}
 
   $return | fl
 
   $return | fl
 
   if ($return.Type -eq "JOB") {
 
   if ($return.Type -eq "JOB") {
Line 204: Line 206:
 
Here the script subscribes to the event that is triggered by the background job via [http://technet.microsoft.com/en-us/library/hh849967.aspx Register-EngineEvent], using the return object's ''Token'' property as ''SourceIdentifier''. By that property the event relates to the triggering PowerShell Job and thus to the server process. The ''Action'' script block is itself created as a PowerShell Job that is executed with each triggering of the event. Through the ''MessageData'' property of the ''$event'' [http://technet.microsoft.com/en-us/library/hh847768.aspx automatic variable] the script block can access the return object provided by the background job. That object's ''Data'' property contains the status of the server process:
 
Here the script subscribes to the event that is triggered by the background job via [http://technet.microsoft.com/en-us/library/hh849967.aspx Register-EngineEvent], using the return object's ''Token'' property as ''SourceIdentifier''. By that property the event relates to the triggering PowerShell Job and thus to the server process. The ''Action'' script block is itself created as a PowerShell Job that is executed with each triggering of the event. Through the ''MessageData'' property of the ''$event'' [http://technet.microsoft.com/en-us/library/hh847768.aspx automatic variable] the script block can access the return object provided by the background job. That object's ''Data'' property contains the status of the server process:
  
   @{error=; token=; antiXsrfToken=gI0ZE1TLMQwVCgudNCLBuQEX0Gv5943YBvrQCGFkbWlu;
+
   @{error=; token=sae8b8eaa3f645d11ee0207797cebbc0b1; statusVersion=8;
     statusVersion=8; statusCode=running; percentProgress=1; statusText=; result=;
+
     statusCode=running; percentProgress=1; statusText=; result=;
 
     logOutput=  300 messages verified...
 
     logOutput=  300 messages verified...
 
   }
 
   }
Line 215: Line 217:
  
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
 
<source lang="powershell" smart-tabs="true" toolbar="false" gutter="false">
   invoke-MSSPEApiCall $msspeapiclient "cancel-async" @{token = $return.Token}
+
   Invoke-MSApiCall $MSApiclient "cancel-async" @{token = $return.Token}
 
</source>
 
</source>
 
<p class=msnote>'''Please note:''' In order for the cancel request to succeed, a valid ''antiXsrfToken'' has to be supplied to the API client object as well. An ''antiXsrfToken'' is valid for 5 minutes and can be retrieved through the status object.</p>
 

Revision as of 14:44, 12 August 2014

This tutorial aims to explain the usage of the MailStore Service Provider Edition Management API through simple Windows PowerShell example scripts. Basic knowledge of MailStore SPE, Windows and PowerShell is a necessary precondition.

The API wrapper used in this tutorial is an example implementation of a MailStore SPE Management API client. As communication with the Management API is done via web requests, it is possible to create different implementations that use the corresponding PowerShell cmdlets. However, such implementations are out of scope of this tutorial.

Please note: It is strongly recommended to use a non-productive test environment for this tutorial as well as for script development in general, in order to prevent loss of data or other problems.

Installation of Necessary Components

The examples demonstrated here use the MailStore PowerShell API Wrapper and are compatible with Windows PowerShell 3.0 and higher. Depending on your version of Windows it might be necessary to download and install a compatible version of PowerShell first. You can find the components necessary for this tutorial here:

Please take note of the system requirements and further notices for the respective version of the Windows Management Framework.

Important Notice: Installation of a Windows Management Framework on systems that require a specific version of Windows PowerShell, such as Microsoft Exchange Servers, is not supported and may lead to massive system failures and data loss.

After downloading and installing Windows PowerShell (if necessary) please unzip the MailStore PowerShell API Wrapper and the example scripts (to C:\MailStore SPE Scripting Tutorial\PowerShell\ by default).

Neither the MailStore PowerShell API Wrapper nor the example scripts are digitally signed, therefore execution of such scripts has to be enabled in an administrative PowerShell session using

  Set-ExecutionPolicy -ExecutionPolicy Unrestricted

Importing the MailStore PowerShell API Wrapper

The MailStore PowerShell API Wrapper is implemented as a PowerShell Script Module (MS.PS.Lib.psm1) and can thus be imported in a PowerShell session via its manifest (MS.PS.Lib.psd1) by using Import-Module.

Please open a PowerShell session and import the API wrapper module using this command:

  Import-Module "C:\MailStore SPE Scripting Tutorial\PowerShell\API-Wrapper\MS.PS.Lib.psd1"

Getting Information about the MailStore PowerShell API Wrapper

The MailStore PowerShell API Wrapper provides several functions to access the MailStore SPE Management API, following PowerShell conventions. Enter the following command to get information about these features:

  Get-Module MS.PS.Lib | fl

More detailed information is available via the module's properties. For example,

  (Get-Module MS.PS.Lib).ExportedFunctions

returns the functions provided by the module. Via

  Get-Help *MSApi*

the MailStore PowerShell API Wrapper returns inline help for all its functions.

Calling API Wrapper Functions

The following example script (Example1.ps1 in the tutorial package) explains the basic usage of MailStore PowerShell API Wrapper functions.

  Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
  $MSApiClient = New-MSApiClient -Username admin -Password admin -ManagementServer localhost -Port 8474 -IgnoreInvalidSSLCerts
  $return = Invoke-MSApiCall $MSApiClient "GetEnvironmentInfo"
  $return.Data.result | fl

The function New-MSApiClient creates a new API client object which the Invoke-MSApiCall function uses for API calls. The values for -Username and -Password have to be supplied, while -ManagementServer defaults to "localhost" and -Port defaults to "8474". The switch -IgnoreInvalidSSLCerts has to be set if untrusted certificates are used; otherwise an error occurs.

Apart from the API client object, Invoke-MSApiCall needs an API command and its parameters if applicable. The command GetEnvironmentInfo in the script does not have any parameters and returns an object as follows:

 Type  : JSON
 Token : 
 Data  : @{error=; token=; statusVersion=2; statusCode=succeeded; percentProgress=; statusText=; result=; logOutput=}

The object's Type property has the value "JSON" for synchronous API commands or "JOB" for asynchronous API commands (see below); it characterizes the type of the object contained in the Data property. The Token property is only relevant for asynchronous API commands.

The Data property contains a JSON status object returned by MailStore SPE:

 error           : 
 token           : 
 statusVersion   : 2
 statusCode      : succeeded
 percentProgress : 
 statusText      : 
 result          : @{version=9.0.3.9845; copyright=Copyright (c) 2005-2014 MailStore Software GmbH; licenseeName=MailStore; licenseeID=23634; serverName=tutorial.mailstore.test; userName=admin; systemProperties=}
 logOutput       :  

The result property of that object has the actual return value if the request succeeded as indicated by the statusCode:

 version          : 9.0.3.9845
 copyright        : Copyright (c) 2005-2014 MailStore Software GmbH
 licenseeName     : MailStore Software GmbH
 licenseeID       : 23634
 serverName       : tutorial.mailstore.test
 userName         : admin
 systemProperties : @{processors=System.Object[]; totalPhysicalMemory=2146947072; operatingSystem=Microsoft Windows Server 2012 Standard}
 

Calling API Wrapper Functions with Parameters

For most MailStore SPE Management API commands you need to provide parameters. Of course, the MailStore PowerShell API Wrapper's Invoke-MSApiCall function can submit these parameters, as demonstrated by the following script (Example2.ps1 in the tutorial package):

  Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
  $MSApiclient = New-MSApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8474 -IgnoreInvalidSSLCerts
  $return = (Invoke-MSApiCall $MSApiclient "GetInstances" @{instanceFilter = "*"})
  if ($return.Type -eq "JOB") {
      Wait-Job $return.Data
      $instances = (Receive-Job $return.Data).Data.result
  } else {
      $instances = $return.Data.result
  }
  foreach ($instance in $instances) {
      $users = (Invoke-MSApiCall $MSapiclient "GetUsers" @{instanceID = $instance.instanceID}).Data.result
      foreach ($user in $users) {
          (Invoke-MSApiCall $MSapiclient "GetUserInfo" @{instanceID = $instance.instanceID; userName = $user.userName}).Data.result | fl
      }
  }

The scripts lists details about the users created in a MailStore SPE instance. Because the MailStore PowerShell API Wrapper converts API responses into objects, their properties can be used directly in the script's workflow. The function Invoke-MSApiCall expects parameters as a hashtable, e.g. @{parametername1 = value1; parametername2 = value2;...}. Parameter names are case sensitive.

First, a list of all MailStore SPE instances is requested with the API command GetInstances. In case of many instances this command could be executed asynchronously by the server and return a job object (see below) otherwise an array of instances as follows is returned:

 instanceID     : test01
 alias          : tutorial
 displayName    : Tutorial Test Instance
 instanceHost   : tutorial.mailstore.test
 startMode      : automatic
 processID      : 3140
 status         : running
 startStopError : 

The script now iterates over this array using the instanceID property of each entry as a parameter for the API command GetUsers. The list of users of each instance is then also iterated over and each user's properties are requested via GetUserInfo:

For the entry listed above the result could be as follows:

 userName            : johndoe
 fullName            : John Doe
 distinguishedName   : 
 authentication      : integrated
 emailAddresses      : {}
 pop3UserNames       : {}
 privileges          : {login, changePassword}
 privilegesOnFolders : {@{folder=johndoe; privileges=System.Object[]}}

As can be seen in the privilegesOnFolders property, returned objects may be nested and may also contain further objects.

Calling API Wrapper Functions for Asynchronous API Commands

The server may decide to execute Management API commands asynchronously if their execution may take more time. The MailStore PowerShell API Wrapper identifies calls of such asynchronously executed API commands and executes them as PowerShell Jobs in the background.

Processing API Wrapper PowerShell Jobs Synchronously

A script's execution can be interrupted until a PowerShell Job created by the API wrapper terminates as demonstrated by the following script (Example3.ps1 in the tutorial package):

  Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
  $MSApiclient = New-MSApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8474 -IgnoreInvalidSSLCerts
  $return = (Invoke-MSApiCall $MSApiclient "GetInstances" @{instanceFilter = "*"})
  if ($return.Type -eq "JOB") {
      Wait-Job $return.Data
      $instances = (Receive-Job $return.Data).Data.result
  } else {
      $instances = $return.Data.result
  }
  $return = Invoke-MSApiCall $MSApiclient "VerifyStore" @{instanceID = $instances[0].instanceID; id = "1"}
  $return | fl
  if ($return.Type -eq "JOB") {
      Wait-Job $return.Data
      Receive-Job $return.Data
  } else {
      $return.Data
  }

The API commands GetInstances and VerifyStore called in the script regularly return objects with the Type property "JOB".

 Type  : JOB
 Token : sa90edf0029de319e62e856aeb47678325
 Data  : System.Management.Automation.PSRemotingJob

In contrast to objects returned by synchronous API command calls, the Token property now contains a unique ID returned by the server that identifies the server process; it is important for event handling (see below). The Data property contains the PowerShell Job which processes the status objects returned by the server in the background.

This PowerShell Job monitors the status of its corresponding server process and is terminated when that process is finished. Through the PowerShell cmdlet Wait-Job the scripts waits until the job has been completed, getting the job's results through Receive-Job:

 Type       : JSON
 Token      : 
 Data       : @{error=; token=sa90edf0029de319e62e856aeb47678325; statusVersion=32; statusCode=succeeded; percentProgress=100; statusText=; result=; logOutput=}
 RunspaceId : 451b5d8b-dcc3-4eec-820e-3dbd2bcb4c5f

Please note: The RunspaceId is generated by the PowerShell automatically and can be ignored here.

Processing API Wrapper PowerShell Jobs Asynchronously

Instead of interrupting a script's execution, the PowerShell Jobs created by the API wrapper can be reacted to while they are running in the background. These jobs trigger a PowerShell EngineEvent with each status request that the script can subscribe to execute further code on each occurrence. To demonstrate this, the previous script needs to be adapted only a bit (Example4.ps1 in the tutorial package):

  Import-Module '..\API-Wrapper\MS.PS.Lib.psd1'
  $MSApiclient = New-MSApiClient -Username "admin" -Password "admin" -ManagementServer "localhost" -Port 8474 -IgnoreInvalidSSLCerts
  $instances = (Invoke-MSApiCall $MSApiclient "GetInstances" @{instanceFilter = "*"}).Data.result
  $return = Invoke-MSApiCall $MSApiclient "VerifyStore" @{instanceID = $instances[0].instanceID; id = "1"}
  $return | fl
  if ($return.Type -eq "JOB") {
      $mssevent = Register-EngineEvent -SourceIdentifier $return.Token -Action {write-host $event.MessageData.Data}
  } else {
      $return.Data
  }

Here the script subscribes to the event that is triggered by the background job via Register-EngineEvent, using the return object's Token property as SourceIdentifier. By that property the event relates to the triggering PowerShell Job and thus to the server process. The Action script block is itself created as a PowerShell Job that is executed with each triggering of the event. Through the MessageData property of the $event automatic variable the script block can access the return object provided by the background job. That object's Data property contains the status of the server process:

 @{error=; token=sae8b8eaa3f645d11ee0207797cebbc0b1; statusVersion=8;
   statusCode=running; percentProgress=1; statusText=; result=;
   logOutput=  300 messages verified...
  }

Via these mechanisms the script can execute further tasks while monitoring the server process in the background. Execution and handling of multiple asynchronous API commands is also possible this way.

Cancelling Asynchronous API Wrapper PowerShell Jobs

To cancel the execution of an asynchronous API command, use cancel-async with the asynchronous command's token as a parameter. For the example above the call would be:

  Invoke-MSApiCall $MSApiclient "cancel-async" @{token = $return.Token}