As of the time of writing this, there are only a few ways I can think of to make sure that a connector is running and healthy.

 

  1. Checking the tags that it is writing to and making sure they are updating.
  2. Checking the administration page to ensure that all lights are green.

 

The purpose of this is to show you how it is possible to monitor the connectors at your organization using Powershell and AF SDK.

 

When you first saw this post you might be thinking that the only way you could check if your connector was working was by checking the administration page, but that is only partially true! The items on the administration page can be retrieved by making a REST type call to the connector webpage. So, all of the information that you can view on the connector administration site can be extracted and written to PI tags, offering an easy solution for monitoring the health of your connectors.

 

I have included a script, which is attached to this webpage. If you'd like to skip straight to the part where I talk about the Powershell script and what it can do, please use the link in the table of contents to skip to that section. The attachments can be found at the bottom of this post.

 

Table of Contents

 

 

What types of information can we pull from the connector webpage?

First, let's cover where this information is stored. Pull up the administration page for your favorite connector. I'll be using the PI Connector for OPC UA. In the screenshot you see below, each of these fields can be queried by making a REST call to the connector. So, let's work on finding how to query for the status of the Connector, Data sources, and Servers configured to receive data from the connector.

 

I am using Chrome for this, but you can also perform similar actions in other web browsers. When on the Connector Administration page, hit F12. You should see the Chrome Developer Tools window pop up. From there, let's browse to the Network tab. The Network tab will allow us to see the requests being made as well as the responses being provided by the connector. Let's take a look at the Data Source Status (this shows up as Datasource%20Status). Expanding the object allows us to see the properties underneath it. For my data source, we can see that it is named OPCServer1, it has a status of Connected, and a message stating that I have No Data Filter set.

 

We can also see the URL that was used to retrieve this information from the Headers section.

 

Information on the Connector State, PI Data Archive, and AF connections can be found in a similar manner under the Network tab by looking at ConnectorState, PI%20Data%20Archive%20Connections, and PI%20AF%20Connections respectively.

 

How can we obtain this information using Powershell?

Now that we know what types of information we can get, let's go through how Powershell can query for and store this information.

 

Because we want this script to run periodically, we will need stored the credentials on the machine. But, we don't want to just store credentials in plain text on the machine running the script, so we will encrypt them. Let's set the username variable first:

#username for logging into the PI Connector Administration Page.

$user = "domain\user"

 

Next, let's store the password and encrypt it. We will then set the password to the encrypted file that contains the password:

#Convert password for user account to a secure string in a text file. It can only be decrypted by the user account it was encrypted with.

"password" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "file location for the stored password file"

$pass = "file location for the stored password file"

 

Finally, we will decrypt the credentials when running the script using the command below. These credentials can only be decrypted by the user that encrypted them, so make sure to encrypt the credentials with the same user that will be running this script.

#Credentials that will be used to login to the PI Connector Administration Page.

$cred = New-Object -TypeName System.Management.Automation.PSCredential `

-ArgumentList $user, (Get-Content $pass | ConvertTo-SecureString)

 

The connector's also use self-signed certificates, so you may get an error when attempting the GET request. To get around this, we will include the following code to ignore the certificate errors:

#Ignore invalid certificate errors when connecting to the PI Connector Administration Page. This is because the connector uses a self-signed certificate, but Powershell wants to use a validated certificate.

Add-Type @"

    using System;

    using System.Net;

    using System.Net.Security;

    using System.Security.Cryptography.X509Certificates;

    public class ServerCertificateValidationCallback

    {

        public static void Ignore()

        {

            ServicePointManager.ServerCertificateValidationCallback +=

                delegate

                (

                    Object obj,

                    X509Certificate certificate,

                    X509Chain chain,

                    SslPolicyErrors errors

                )

                {

                    return true;

                };

        }

    }

"@

 

 

[ServerCertificateValidationCallback]::Ignore();

 

Now that all of that is out of the way, let's get to the part where we pull the information from the webpage. For this, we will be using the Invoke-WebRequest function. If we wanted to query for the data source status shown above, our function would look like this:

$DataSourceStatusResponse = Invoke-WebRequest -Method GET  "https://nlewis-iis:5460/admin/api/instrumentation/Datasource%20Status" -Credential $cred | ConvertFrom-Json

We are using the GET method which we can see for the Request Method in the Headers. The login to the connector webpage uses basic authentication, so we are passing it credentials that we have stored in the variable $cred. Finally, we pass this to the ConvertFrom-Json function in order to store the information retrieved from Invoke-WebRequest in a Powershell object under the variable $DataSourceStatusResponse.

 

For our data source status, we can then take a look at the variable to see what information we now have. We can see that under the variable we can see our data source OPCServer1. If we had additional data sources, they would show up here.

 

If we browse further into the variable, we can then find the Message and Status fields we were looking for:

 

If we wanted to store the status in a variable ($OPCServer1_Status), we could then achieve this as follows:

$OPCServer1_Status = $DataSourceStatusResponse.OPCServer1.Object.Status

 

Now we just need to retrieve the other information we want in a similar fashion and we are ready to write the values to PI tags!

 

 

Writing the values to PI

For this, we will be using AF SDK in Powershell to achieve this. There are also native Powershell functions for the PI System that come with PI System Management Tools that could be used instead of using AF SDK.

 

There are a few steps in order to this this.

 

1. We need to load the AF SDK assemblies.

# Load AFSDK

[System.Reflection.Assembly]::LoadWithPartialName("OSIsoft.AFSDKCommon") | Out-Null

[System.Reflection.Assembly]::LoadWithPartialName("OSIsoft.AFSDK") | Out-Null

 

2. We need an object that can store the point attributes for the tags we will be creating. The script I created will automatically create the PI tags if it cannot find them.

#Create an object with point attributes for the points you are creating

$myattributes = New-Object 'System.Collections.Generic.Dictionary[[String], [Object]]'

 

3. Store the tag attributes in the tag attribute object. For myself, I am making these string tags with a point source of CM.

<#Add the attributes to your point. I am making the points that will be created string tags, which corresponds to a value of 105.

Different point types can be found here: https://techsupport.osisoft.com/Documentation/PI-AF-SDK/html/T_OSIsoft_AF_PI_PIPointType.htm

#>

$myattributes.Add("pointtype", 105)

$myattributes.Add("pointsource","CM")

 

4. Next, we will need to initialize the PI Data Archive, AF Server, buffering options, and instantyiate our new values we will be using. We are using the default PI Data Archive and AF Server for this.

# Create AF Object

$PISystems=New-object 'OSIsoft.AF.PISystems'

$PISystem=$PISystems.DefaultPISystem

$myAFDB=$PISystem.Databases.DefaultDatabase

 

# Create PI Object

$PIDataArchives=New-object 'OSIsoft.AF.PI.PIServers'

$PIDataArchive=$PIDataArchives.DefaultPIServer

 

# Create AF UpdateOption

$AFUpdateOption = New-Object 'OSISoft.AF.Data.AFUpdateOption'

 

#Set AF Update Option to Replace

$AFUpdateOption.value__ = "0"

 

# Create AF BufferOption

$AFBufferOption = New-Object 'OSISoft.AF.Data.AFBufferOption'

 

#Set AF Buffer Option to Buffer if Possible

$AFBufferOption.value__ = "1"

 

# Instantiate a new 'AFValue' object to persist...

$newValueX = New-Object 'OSIsoft.AF.Asset.AFValue'

 

# Apply timestamp

$newValueX.Timestamp = New-object 'OSIsoft.AF.Time.AFTime'(Get-Date)

 

With that all out of the way, we just need to create our PI tag, assign it a value and timestamp, and send it on its way.

 

5. Assign a name to the PI tag.

# Assign Tag Name to the PI Point. Here I denote that this is for the data source OPCServer1 and I am retrieving the status.

$tagNameX = "OPCUAConnector.DataSource.OPCServer1.Status"

 

6. Find the tag, and create it if it does not exist. This finds the tag based off of the PI Data Archive we specified earlier, as well as the tag name

#initiate the PI Point

$piPointX = $null

 

#Find the PI Point, and create it if it does not exist

 

 

if([OSIsoft.AF.PI.PIPoint]::TryFindPIPoint($PIDataArchive,$tagNameX,[ref]$piPointX) -eq $false) 

{  

     $piPointX = $piDataArchive.CreatePIPoint($tagNameX, $myattributes) 

#Set the PI tag for $newValueX to $piPointX

$newValueX.pipoint = $piPointX

 

7. Lastly, we can apply the value to $newValueX and write this value to PI! We set the value equal to the call we made earlier for the Data Source Response where we retrieved the status of the server. We then user $newValueX.PIPoint.UpdateValue in order to write the new value to the tag.

    $newValueX.Value = "$DataSourceStatusResponse.OPCServer1.Object.Status"

    $newValueX.PIPoint.UpdateValue($newValueX.Value,$AFUpdateOption)

 

And that's it! That is all the code required in order to pull the information from the connector page and write it to a PI tag.

 

 

The Connector Monitoring Script

If you were wondering while reading this whether or not someone built out a script that already pulls in some of the relevant information, then you're in the right place. While writing this I also developed a script that will write the data from the connector pages you supply it with to PI tags. Let's go over how it works.

 

How the script works:

  1. You supply it credentials based off of the method we discussed earlier, where we encrypt the password.
  2. You provide it a list of connectors. In this list there is the name of the connector (which will be used in the tag naming convention), as well as the URL to the admin page. Make sure to exclude the /ui at the end of the URL. These are then stored in an object called $Connectors.

#Create an object called Connectors. This will hold the different connectors you want to gather information from.

$Connectors = @{}

#When adding a connector, give it a name, followed by the link to the admin page like below.

$Connectors.add("OPCUA_nlewis-iis","https://nlewis-iis:5460/admin")

$Connectors.add("PING_nlewis-iis","https://nlewis-iis:8001/admin")

 

    3. A connector object is then generated and the items in the list are added to this object.

    4. We query the web pages and then write the values to PI for each of the objects in the connector object.

 

What the script does

  • Tags are based on the naming convention of: <Provided Connector Name>.<Type>.<Server>.Status, where the type can be DataSource, AFServer, or PIServer
    • For the status of the AF Server (AF Server is named nlewis-af1) for a connector I named OPCUA_nlewis-iis, the tag would be named OPCUA_nlewis-iis.AFServer.nlewis-af1.Status.
  • If the script cannot connect to the admin page, it writes an error message to the connector state tag.
  • If the service is running but the connector is stopped via the webpage, the script writes to all tags for that connector that the connector is stopped.

 

There are two parts to the script. The first part generates the encrypted password file. The second part you run to pull the information, create the tags if they do not exist, and write to them.

 

Please edit the code to include the connectors used in your environment. The scripts can be found attached to this post.

 

PI Connectors and PI Interfaces   All Things PI - Ask, Discuss, Connect