Getting Started: Scripting Incuity EMI models with PowerShell

by Klaus Graefensteiner 16. February 2009 15:13

Introduction

The Incuity EMI (Enterprise Manufacturing Intelligence) software lets you connect to various plant historians, real time plant data servers and conventional relational database servers and access the underlying information through an unified entity model. The heart of the model is a powerful and elegant meta-repository. The setup of the data sources and the creation of the entity model can be automated by using an easy to use client .NET API. This article describes how to get started with this API and demonstrates the creation of a connector to the plant historian server from Wonderware using PowerShell.

This article applies to Incuity EMI Server 2.6.1

Manufacturing Entities

Figure 1: Manufacturing Entities

Client API

The Incuity EMI Client install deploys two .NET assemblies to the GAC that can be used to automate tasks that are normally performed by users via the IncuityManager tool.

The two assemblies are called:

  • Dataworks.MI.Core.dll
  • Dataworks.MI.Core.Client.dll

Copies of these files can usually be found in C:\Inetpub\wwwroot\Incuity\bin

Resources

There are two main sources of information available on a server or client system. The first one is the online documentation and the other are sample scripts in VB.NET.

Online Documentation

The online documentation can be found here: C:\Inetpub\wwwroot\Incuity\Documentation\WebHelp\index.htm

The chapter about scripting is located here: C:\Inetpub\wwwroot\Incuity\Documentation\WebHelp\AnalysisServices\ClientSideScripting

Here is the list of topics that is covered in the scripting help:

  • appendix_a_configuring_sharpdevelop.htm
  • basic_code_constructs.htm
  • client_side_scripting_modified_for_help_import.htm
  • coding_reference_summary.htm
  • environment_and_tools.htm

Sample Files

The sample script files can be found on all EMI client machines in the following folder: C:\Program Files\Incuity\Samples\Scriptlets

Here is the list of available samples:

  • AllItemTypes.vb
  • CreateAndResyncInSqlConnector.vb
  • CreateMsSqlConnectorWithMappedTypes.vb
  • CreatePlatformWithMappedTypes.vb
  • Export.vb
  • Extruder.vb
  • HelloWorld.cs
  • InvokeItemOperations.vb
  • RetrieveHistory.vb
  • RetrieveLive.vb
  • SingleItem.vb
  • SingleItemType.vb

Toolbox

There are three tools that will make scripting Incuity EMI configurations a very pleasant experience. The PowerShell ISE (Integrated Scripting Environment), Reflector and the IncuityManager tool that basically constitutes a client API reference application.

PowerShell 2.0 - ISE

PowerShell 2.0 is not released at the moment, but the pre-release version CTP3 can be downloaded here. This install comes with the greatest scripting tool ever. The editor is based on the Visual Studio 2010 text editor and provides a great debugger for PowerShell scripts. It is more stable than any other tool I tried out so far.

PowerShell ISE

Figure 2: PowerShell 2.0 Integrated Scripting Environment

Reflector

The .NET framework tool that I can’t life without is the Reflector, which can be downloaded here. It let’s you browse .NET assemblies and discover and study the public API of the assembly. The following screenshot contains a list of namespaces that the Incuity EMI client API provides.

Reflector reflecting Incuity EMI Client API

Figure 3: Reflector reflecting Incuity EMI Client API

IncuityManager

The IncuityManager is a GUI application that implements the client API. Almost any configuration task that can be accomplished with this tool, can also be coded in a similar fashion using the client API. I recommend to first get familiar with the configuration steps in the GUI and then follow the same sequence when developing a script. The following example shows the different elements of the model and how they are used in the IncuityManager. Let’s create a Connector to the InSql historian and import its tags.

InSql Connector Properties   

Figure 4: InSql Connector Properties

First lets create a new Connector. Connectors are part of the system namespace of the model. They link the model to plant floor data.

InSqlConnector Instance SecurityMapping Properties

Figure 5: Security Mapping property

A SecuriyMappingStrategy needs to be created and passed as parameter during the creation of the connector instance. This strategy encapsulates the login information that the connection to the historian database requires.

InSql Connector Operations And Parameters

Figure 6: Connector Operations

Operations are procedures that can be invoked on a connector type or instance. The IncuityManager lists the available choices.

InSql Connector Instance Properties

Figure 7: InSql Connector Instance Properties

Connector Types and Instances can expose a different set of properties and operations.

InSql Connector Instance Operations

Figure 8: Connector Instance Operations

Synchronize and Import Operations read the namespaces of the InSql Historian and create proxy entities in the Incuity namespace.

InSql Tag Properties

Figure 9: InSql Tag Properties

A successful import results in a collection of InSql tags that are listed under the InSql Connector instance.

Hello Connector Sample

The following PowerShell script automates the creation of an InSql Connector and the import of the historian tags.

PowerShell script

   1: $EMIVersion = $Null
   2:  
   3: function Test-EMIClientInstall()
   4: {
   5:     if ($(Test-Path "C:\Inetpub\wwwroot\Incuity\Bin\DataWorks.MI.Core.dll") -eq $false)
   6:     {
   7:         Throw "DataWorks.MI.Core.dll not found. Is EMI Client intalled on this machine?"
   8:     }
   9:     return $True
  10: }
  11:  
  12:  
  13: function Load-EMIClientAssemblies()
  14: {
  15:     $CoreAssembly = [System.Reflection.Assembly]::LoadWithPartialName("DataWorks.MI.Core")
  16:     $CoreClientAssembly = [System.Reflection.Assembly]::LoadWithPartialName("DataWorks.MI.Core.Client")
  17: }
  18:  
  19:  
  20: # How to get the version of the Incuity System
  21: function Get-EMIVersion()
  22: {
  23:     if( $Script:EMIVersion -eq $Null)
  24:     {
  25:         $Version = [DataWorks.MI.Core.Client.Globals]::Version
  26:         $Script:EMIVersion = $Version
  27:     }
  28:     return $Version    
  29: }
  30:  
  31: function Initialize-EMIClient()
  32: {
  33:     [DataWorks.MI.Core.Client.Globals]::Initialize()
  34:  
  35: }
  36:  
  37:  
  38: function Get-InSqlwwAdminToken()
  39: {
  40:     $InSqlwwAdminToken = [DataWorks.MI.Core.Item]::GetInstance("System.Security.Mappings.InSqlwwAdminToken")
  41:     if ($InSqlwwAdminToken -eq $Null)
  42:     {
  43:         $InSqlwwAdminToken = New-FixedCredentials -UserName "wwAdmin" -Password "wwAdmin" -TokenName "wwAdminToken"
  44:     }
  45:     return $InSqlwwAdminToken
  46: }
  47:  
  48:  
  49: function New-FixedCredentials([string] $UserName, [string] $Password, [string] $TokenName)
  50: {         
  51:     Trap { [DataWorks.MI.Core.Persistence]::AbortTransaction(); [DataWorks.MI.Core.Persistence]::CloseTransaction(); throw }
  52:     &{
  53:         
  54:         $SecurityPath = "Core."
  55:  
  56:         If ( $Script:EMIVersion.Major -eq 3)
  57:         {
  58:             $SecurityPath = "Core.Security."
  59:         }
  60:  
  61:  
  62:         [DataWorks.MI.Core.Persistence]::BeginNewTransaction()
  63:         
  64:         #Get the Mappings collection property of the System.Security system item
  65:         $SecurityItem = [DataWorks.MI.Core.Item]::GetInstance([DataWorks.MI.Core.Namespace.NamespaceProvider]::FQNSecurity)
  66:         [DataWorks.MI.Core.IProperty] $ParentToAddTo = $SecurityItem.Properties["Mappings"]
  67:         
  68:         $ValueBag = New-Object -TypeName "DataWorks.MI.Core.Collections.NamedValueBag"
  69:     
  70:         $ValueBag.Add("SecurityMappingStrategyHolder", $SecurityItem)
  71:         
  72:         #Create new Security Strategy and add it to the System.Security.Mappings property
  73:         $CredentialsStrategy = [DataWorks.MI.Core.Item]::CreateInstance([string] $($SecurityPath + "UseFixedCredentials"), $TokenName , [DataWorks.MI.Core.Collections.NamedValueBag] $ValueBag, [DataWorks.MI.Core.IProperty] $ParentToAddTo)
  74:         
  75:         $ValueBag.Clear()
  76:     
  77:         $ValueBag.Add("UserName", $UserName)
  78:         $ValueBag.Add("Password", [DataWorks.MI.Core.Security.DataEncryptor]::Encrypt($Password))
  79:  
  80:         $MappedCredentialsProperty = $CredentialsStrategy.Properties["MappedCredentials"]
  81:         
  82:         #Create new SimpleCredential Login and add it to the new Security Strategy's MappedCredential collection property
  83:         #Bug if create instance result is not assigned to variable
  84:         $SimpleCredentials = [DataWorks.MI.Core.Item]::CreateInstance([string] $($SecurityPath + "SimpleCredentials"), "Credentials", $ValueBag, $MappedCredentialsProperty)
  85:  
  86:     
  87:         [DataWorks.MI.Core.Persistence]::CommitTransaction()
  88:         [DataWorks.MI.Core.Persistence]::CloseTransaction()
  89:         
  90:         
  91:     
  92:         return $CredentialsStrategy
  93:     }
  94: }
  95:  
  96:  
  97: function New-InSQLConnector([string] $InSqlConnectorName,[string] $InSqlServerName, $SecurityToken = $(Get-InSqlwwAdminToken), [string] $TimeZone = "Pacific Standard Time" )
  98: {
  99:     $InSQLConnectorTypeItem =  [DataWorks.MI.Core.Item]::GetInstance("System.Sources.InSQL")
 100:     $InSQLConnector = $InSQLConnectorTypeItem.Invoke("CreateInstance", $InSqlConnectorName, $InSqlServerName, $SecurityToken , $TimeZone)
 101:     return $InSQLConnector
 102: }
 103:  
 104:  
 105: function Get-EMIFolder([string] $FolderName = "MyInSqlNamespace", [string] $ParentFolder = "NotUsed")
 106: {
 107:     # Get MyEnterprise logical Model folder it is of type Core.LogicalModelRoot
 108:     $LogicalModelFQN = [DataWorks.MI.Core.Namespace.NamespaceProvider]::FQNLogicalModel
 109:     
 110:     # Append new Foldername to create new FQN (Fully qualified name)
 111:     $TargetFolderFQN = [DataWorks.MI.Core.Namespace.FQN]::AppendNamePart($LogicalModelFQN , $FolderName)
 112:     
 113:     # Query the new FQN and see whether this folder already exists
 114:     [DataWorks.MI.Core.Namespace.IItemNsElementInfo] $ElementInfo = [DataWorks.MI.Core.Namespace.NamespaceProvider]::Instance.ResolveFQN($TargetFolderFQN)
 115:     
 116:     # If folder item doesn't exist create new one
 117:     if ( $ElementInfo -eq $null)
 118:     {
 119:         $NewFolderItem = New-EMIFolder -FolderName $FolderName
 120:         return $NewFolderItem
 121:     }
 122:     else
 123:     {
 124:         if ( $ElementInfo.ItemType.IsA("Core.Folder"))
 125:         {
 126:             $TargetFolderItem = $ElementInfo.Item
 127:             return $TargetFolderItem
 128:         }
 129:         else
 130:         {
 131:             throw "Specified FQN exists already, but is not a folder!"
 132:         }
 133:     }
 134: }
 135:  
 136: function New-EMIFolder([string] $FolderName = "MyInSqlNamespace", [string] $ParentFolder = "NotUsed")
 137: {
 138:     # Another way to get the MyEnterprise root folder item of the logical model
 139:     $RootFolderItem = [DataWorks.MI.Core.Namespace.NamespaceProvider]::Instance[[DataWorks.MI.Core.WellKnownItem]::LogicalModel]
 140:     $ValueBag = New-Object -TypeName "DataWorks.MI.Core.Collections.NamedValueBag"
 141:     [DataWorks.MI.Core.IProperty] $ChildrenProperty = $RootFolderItem.Properties["Children"]
 142:     [DataWorks.MI.Core.IItem] $FolderItem = [DataWorks.MI.Core.Item]::CreateInstance("Core.Folder", $FolderName, $ValueBag, $ChildrenProperty)
 143:         
 144:     return $FolderItem
 145: }
 146:  
 147:  
 148: function Import-AllInSQLTags([string] $EMIFolderPath, [DataWorks.MI.Core.IItem] $InSqlConnector)
 149: {
 150:     $ValueBag = New-Object -TypeName "DataWorks.MI.Core.Collections.NamedValueBag"
 151:     $ValueBag.Add("SourceFolder", [String]::Empty)
 152:     $ValueBag.Add("ImportPublic", $True)
 153:     $ValueBag.Add("ExcludeSystem", $False)
 154:     $ValueBag.Add("ImportPrivate", $True)
 155:     $ValueBag.Add("TargetFolder", [string] $EMIFolderPath)
 156:     $InSqlConnector.InvokeWithNamedParams("ImportItems", $ValueBag)
 157: }
 158:  
 159: function Wait-ForSyncImportOperationToComplete([int] $PollInterval, [DataWorks.MI.Core.IItem] $InSqlConnector)
 160: {
 161:     While ($True)
 162:     {
 163:         [System.Threading.Thread]::Sleep($PollInterval)
 164:         [string] $LastProgress = $InSqlConnector.Invoke("GetLastSynImportProgress")
 165:  
 166:          If ($LastProgress.StartsWith("Error: "))
 167:          {
 168:             Write-Output $LastProgress
 169:             return $False
 170:          }
 171:          elseif ($LastProgress.EndsWith("Done."))
 172:          {
 173:             Write-Output "Import completed successfully."
 174:             return $True
 175:          }
 176:     }
 177: }
 178:  
 179: Test-EMIClientInstall
 180: Load-EMIClientAssemblies
 181: Get-EMIVersion
 182: Initialize-EMIClient
 183: $NewConnectorItem = New-InSQLConnector -InSqlConnectorName "wwHistorian1" -InSqlServerName "InSql80"
 184: $TargetFolderItem = Get-EMIFolder -FolderName "NSwwHistorian1"
 185: #$FolderPath = $FolderItem.Properties["FullyQualifiedName"].Value
 186: # This is another way to do it
 187: #$FolderPath = $FolderItem["FullyQualifiedName"]
 188: $FolderPath = "MyEnterprise.NSwwHistorian1"
 189: Import-AllInSQLTags -EMIFolderPath $FolderPath -InSQLConnector $NewConnectorItem
 190: Wait-ForSyncImportOperationToComplete -PollInterval 1000 -InSqlConnector $NewConnectorItem
 191:  
 192:  

Download

The script can be downloaded here: HelloConnector.zip

Ausblick

The script that is featured in this article is quite advanced and includes many different aspects of the client API. On the other side it is a real world example that can be used out of the box to automate the import of an InSql data source. In future articles I would like to go into more details about the different client API patterns.

Tags: , , , ,

Incuity | PowerShell | Wonderware

Comments

7/22/2012 1:38:43 PM #

pingback

Pingback from bangkoksightse.yoursexualaids.net

Models emi | Bangkoksightse

bangkoksightse.yoursexualaids.net |

Comments are closed

About Klaus Graefensteiner

I like the programming of machines.

Add to Google Reader or Homepage

LinkedIn FacebookTwitter View Klaus Graefensteiner's profile on Technorati
Klaus Graefensteiner

Klaus Graefensteiner
works as Developer In Test and is founder of the PowerShell Unit Testing Framework PSUnit. More...

Open Source Projects

PSUnit is a Unit Testing framwork for PowerShell. It is designed for simplicity and hosted by Codeplex.
BlogShell is The tool for lazy developers who like to automate the composition of blog content during the writing of a blog post. It is hosted by CodePlex.

Administration

About

Powered by:
BlogEngine.Net
Version: 1.6.1.0

License:
Creative Commons License

Copyright:
© Copyright 2014, Klaus Graefensteiner.

Disclaimer:
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Theme design:
This blog theme was designed and is copyrighted 2014 by Klaus Graefensteiner

Rendertime:
Page rendered at 8/23/2014 2:25:39 AM (PST Pacific Standard Time UTC DST -7)