14 Replies Latest reply on Sep 27, 2016 10:18 PM by JDiaz

    Programmatic data dumps from PI

    JDiaz

      Hello all,

       

      I have about 600 rows of 25 tags in a CSV file that I want to pull from PI. I would like to do this through a program as I will be pulling 1 week worth of data each set of tags for auditing purposes. Is it possible to do this in

       

      Is it possible to do this in PowerShell (I would like to use this tool interface, so I can read the CSV file that contains the sets of tags on a separate line), or can this be accomplished in Excel VBA through the DataLink and PIDSK (is there a data limit size that will create an issue)?

       

      I am a seasoned developer in VBA, JAVA, PowerShell, among other languages. I am new to PI and through my looking found ipisql command, but do not know how to implement it, where do I get the table names from? 

       

      Sorry looking for guidance more than anything else, I imagine I am not the first person to run into massive data dumps for auditing, because this will be performed a couple of times, and the number of queries (600); we want to automate the dumping process as much as possible.

       

      Jaime

        • Re: Programmatic data dumps from PI
          Rick Davin

          Hi Jaime,

           

          The short answer to your question is "Yes".  That would be yes to PowerShell, VBA, and Java.  The long answer would really revolve around the technology of choice.

           

          I will assume that each row will have 26 columns: one with a timestamp and one for each of the 25 tag values. 

           

          Some of our PowerShell applets may be wrappers to PI SDK, but PowerShell may also use AF SDK calls as well.  VBA would rely on our COM-heavy PI SDK, which is an obsolete platform.  I really haven't worked with PI JDBC but it should work.  Since you're familiar with VBA, you might consider VB.NET and AF SDK.  Then again, if your familiar with managed { } code with Java, then C# and AF SDK should not scare you away.

           

          With 600 rows and 25 PIPoints, that would be 15000 values.  What you don't want to do is make 15000 update calls.  You want to bulk the calls.

           

          One difference in processing between PI SDK and AF SDK (besides COM) is with bulk processing.  With PI SDK, bulk updates are for an individual PIPoint only, whereas AF SDK can update multiple PIPoints with multiple values in one call.  With PI SDK, your fewest possible calls would be 25, one bulk call per PIPoint.

          3 of 3 people found this helpful
            • Re: Programmatic data dumps from PI
              JDiaz

              Rick, thanks for the quick answer, you have opened up the path to additional questions, let's start by focusing on PowerShell or VBA, how would I proceed, are there white papers on this?

               

              I will be only extracting (dumping data) so there is no need for updates or inserts simple Selects with output redirected to text files (CSV, TSV).

               

              Are there code snippets, I think in VBA or PowerShell I will be looking at something along the lines of working with ADO so let's use VBA as a starting point.

               

              Assume I have access to PI DataLink in Excel, as well as the PISDK and the AFSDK. Can we use this as a starting point and go from there.

               

              A quick google search turned up the following:

              PowerShell Tools for the PI System

              I believe this is a good starting point, but as I stated I am not a PI user, very new and no previous exposure, I see a simple

              Get-PIValue -PointName sinusoid -Connection $myPI -StartTime "19-Jul-2015 8:00:00" -EndTime "19-Jul-2015 17:00:00" | Select TimeStamp, Value

               

              I see no table names, which leads me to believe that PI does not exactly use tables to store data. If so fetching the data is a matter of issuing this command with a list of PI Tags, is this correct, is there more to it.

                • Re: Programmatic data dumps from PI
                  Rick Davin

                  I could work something up with VBA for working with a CSV file.  It won't need DataLink as it will just read the file and use PI SDK to write.  I'm working on some other cases so it may be a day or 2 before I can get something to you. 

                   

                  Although I invite others to beat me to it ...

                  1 of 1 people found this helpful
                    • Re: Programmatic data dumps from PI
                      JDiaz

                      Thank you I will be waiting, I am looking to perhaps start full steam on this sometime Monday or Tuesday of next week, also I added some information to my last reply, which I append here:

                       

                      A quick google search turned up the following:

                      PowerShell Tools for the PI System

                      I believe this is a good starting point, but as I stated I am not a PI user, very new and no previous exposure, I see a simple

                      Get-PIValue -PointName sinusoid -Connection $myPI -StartTime "19-Jul-2015 8:00:00" -EndTime "19-Jul-2015 17:00:00" | Select TimeStamp, Value

                       

                      I see no table names, which leads me to believe that PI does not exactly use tables to store data. If so fetching the data is a matter of issuing this command with a list of PI Tags, is this correct, is there more to it ...

                       

                      and this one as well:

                      Getting started with the new PowerShell Tools for the PI System

                        • Re: Programmatic data dumps from PI
                          mtippett

                          One important thing that hasn't been mentioned in this thread is interpolated vs raw (or compressed) data calls.  As you correctly point out data is not stored in tables in the PI system, and importantly data typically goes through exception and compression testing when being sent to PI.  If you're not familiar with exception and compression, and its implications then the following video provides a very good introduction OSIsoft: Exception and Compression Quick Summary - YouTube .

                           

                          Essentially the raw data stored in PI is not evenly spaced and different tags may also have different scan rates.  It sounds like you would like the output to be formatted as:

                           

                          timestamp1,tag1,tag2,tag3...

                          timestamp2,tag1,tag2,tag3...

                          timestamp3,tag1,tag2,tag3...

                          etc...

                           

                          In which case you will need to use an interpolated value call to get the PI data archive to interpolate values to give you evenly spaced values for each tag that you can use.  I'm not very familiar with powershell, but in the AF SDK the methods to use are the PIPointList.InterpolatedValues Method or PIPoint.InterpolatedValues Method for a list of points or and individual PI point, respectively.  I believe that the Get-PIValue cmdlet will not interpolate values but only give you the raw values stored in the archive.  I have attached some C# sample code that outputs data in the above format using the AF SDK that I wrote when working with a customer on a similar issue.  You should take this code as only a sample just to give you ideas, however, as I haven't tested it.

                  • Re: Programmatic data dumps from PI
                    Jerome Lefebvre

                    I can't help but to also point out that the PI Integrator for Business also has the ability to periodically write PI data to a text file.

                    https://livelibrary.osisoft.com/LiveLibrary/content/en/bi-v2/GUID-0C1F572E-87EC-4C1C-9A18-39CE5E8CE02E

                    You may find that it is much easier to configure the integrator, than to develop a new solution to this problem, as it already has built in various ways to filter the data that comes out of PI.

                    3 of 3 people found this helpful
                    • Re: Programmatic data dumps from PI
                      Rick Davin

                      Time for a major correction ... I misread the question and thought you were wanting code samples for reading a CSV file and then writing it to a Data Archive.  But you want to do is read from the Data Archive and write to a CSV file. 

                       

                      You could investigate Jerome's suggestion, or since you have DataLink, you could create a sheet to import the PI data in the layout you prefer.  While you could write custom VBA, it would not need PISDK.  It would just read the Excel columns and rows and output to a CSV file.  But even that isn't necessary if you already have an Excel sheet laid out, you could simply Save As a CSV.

                      • Re: Programmatic data dumps from PI
                        JDiaz

                        My biggest issue is the sheer quantity of queries, if I have to sit through and pull all 600 data sets, it will be days, and by that time I will probably be expected to provide the next snapshot, which is why I want hopefully a threaded or asynchronous way of pulling 3 or 3 dumps at a time, moving on.

                        On a side note to Michael Tippett, is it possible to simply repeat the last value until the next change, someone mentioned the compressed (RAW data) issue and mentioned, that scan rates can be different and the data is actually recorded on change, there surely must be an interpolation setting to get the last value repeated vs calculated (perhaps I am reading into interpolation literally and not truly understanding)

                          • Re: Programmatic data dumps from PI
                            Marcos Vainer Loeff

                            Hi Jaime,

                             

                            I have written a code in C# using PI AF SDK. I am taking advantage of the PIPointList.RecordedValue Method since it will retrieve values from many PI Points for a given timestamp, which makes the process more efficient. If this is something that works for you, I can convert it to Windows Power Shell script.

                             

                            using OSIsoft.AF;
                            using OSIsoft.AF.Asset;
                            using OSIsoft.AF.PI;
                            using OSIsoft.AF.Time;
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            
                            
                            namespace ConsoleApplication5
                            {
                                class Program
                                {
                                    static PIServer piServer = null;
                                    static void Main(string[] args)
                                    {
                            
                            
                                        piServer = new PIServers()["MARC-PI2016"];
                                        List<string> names = new List<string>() { "sinusoid", "cdt158", "cdt160" };
                                        IList<PIPoint> piPoints = PIPoint.FindPIPoints(piServer, names, null);
                                        PIPointList piPointList = new PIPointList(piPoints);
                                        DataStorage dataStorage = new DataStorage();
                                        DateTime[] dateTimes = GenerateDateTimeArray();
                                        for (int i = 0; i < dateTimes.Count(); i++)
                                        {
                                            TimeStorage timeStorage = GetRecordedValuesAtTime(piPointList, dateTimes[i]);
                                            dataStorage.Add(timeStorage);
                                        }
                                        int a = 1;
                            
                            
                                    }
                            
                            
                                    static DateTime[] GenerateDateTimeArray()
                                    {
                                        DateTime[] times = new DateTime[100];
                                        for (int i = 0; i < times.Count(); i++)
                                        {
                                            times[i] = DateTime.Now.AddDays(i);
                                        }
                                        return times;
                                    }
                            
                            
                                    static TimeStorage GetRecordedValuesAtTime(PIPointList piPointList, DateTime time)
                                    {
                                        AFTime afTime = new AFTime(time);
                                        AFListResults<PIPoint, AFValue> result = piPointList.RecordedValue(afTime);
                                        IEnumerable<CustomValue> values = result.Select(m => new CustomValue(m.Value, m.PIPoint.Name));
                                        return new TimeStorage(time, values);
                            
                            
                                    }
                                }
                            
                            
                                class DataStorage : List<TimeStorage>
                                {
                            
                            
                                }
                            
                            
                                class TimeStorage : List<CustomValue>
                                {
                            
                            
                                    public DateTime Time{ get; set; }
                                    public TimeStorage(DateTime time, IEnumerable<CustomValue> values)
                                    {
                                        this.AddRange(values);
                                    }
                                }
                            
                            
                            
                            
                                class CustomValue
                                {
                                    public object Value { get; set; }
                                    public string PIPointName { get; set; }
                            
                            
                            
                            
                                    public CustomValue(object value, string piPointName)
                                    {
                                        Value = value;
                                        PIPointName = piPointName;
                                    }
                                }
                            }
                            

                             

                             

                            Hope it helps!

                              • Re: Programmatic data dumps from PI
                                JDiaz

                                Sorry for the late reply, I went off the grid for the weekend and this is definitely what I need (a very good start), I can fill in the blanks and go from there, if I have any additional questions, I will return to ask for additional guidance.

                                 

                                Unfortunately the desktop I have been assigned with access to the server, does not have nor do they want to install a C# compiler, so Powershell will definitely be the way to go.

                                 

                                Thanks for your trouble.

                                 

                                -Jaime

                                  • Re: Programmatic data dumps from PI
                                    Marcos Vainer Loeff

                                    Hello,

                                     

                                    Here is a PowerShell code snippet for you to get started!!

                                     

                                    clear
                                    [System.Reflection.Assembly]::LoadWithPartialName('OSIsoft.AFSDK')
                                    
                                    
                                    
                                    
                                    $piServers = New-Object OSIsoft.AF.PI.PIServers;
                                    [OSIsoft.AF.PI.PIServer]$piServer = $piServers["MARC-PI2016"]
                                    
                                    
                                    [string[]]$namesArray =  "sinusoid", "cdt158", "cdt160";
                                    [Collections.Generic.List[String]]$names = $namesArray
                                    #$piPoints = [OSIsoft.AF.PI.PIPoint]::FindPIPoints([OSIsoft.AF.PI.PIServer]$piServer, [Collections.Generic.List[String]]$names, $null)
                                    
                                    
                                    [System.Type[]]$types = @('OSIsoft.AF.PI.PIServer', 'System.Collections.Generic.IEnumerable[String]','System.Collections.Generic.IEnumerable[String]')
                                    $m = [OSIsoft.AF.PI.PIPoint].GetMethod('FindPIPoints', $types)
                                    $params = @([OSIsoft.AF.PI.PIServer]$piServer, [Collections.Generic.List[String]]$namesArray, $null)
                                    [System.Collections.Generic.IList[OSIsoft.AF.PI.PIPoint]]$tagList = $m.Invoke($null, $params) 
                                    
                                    
                                    
                                    
                                    [OSIsoft.AF.PI.PIPointList]$piPointList = New-Object OSIsoft.AF.PI.PIPointList
                                    $piPointList.AddRange($tagList);
                                    
                                    
                                    $times = New-Object System.Collections.ArrayList
                                    for ($i=0;$i -le 100; $i++)  
                                    {  
                                      $time = [System.DateTime]::Now.AddDays($i);
                                      $times.Add($time) > $null  
                                      $afTime = New-Object OSIsoft.AF.Time.AFTime($time);
                                        $result = $piPointList.RecordedValue($afTime);
                                    }  
                                    

                                     

                                     

                                     

                                    Let me know if this helps you!

                                    1 of 1 people found this helpful
                                      • Re: Programmatic data dumps from PI
                                        JDiaz

                                        Marcos,

                                         

                                        Thanks, I have been stumbling and pulling code together, from a myriad of sources, but your codes (the last couple of lines) brought it all home.

                                         

                                        I am posting my code (not tested) as I have yet to be granted rights on the network but hopefully, this will help others that are seeking to perform this task.

                                         

                                        One thing I like to do is comment code I share, so others can benefit from it by understanding and simplifying the process of owning and modifying the code to their purpose.

                                         

                                        #Variables used in the program
                                        $delimiter = ","
                                        $path = "C:\CSV files\"
                                        $file = "Lines.csv"
                                        $exportFile = "expLines.csv"
                                        $startDate = "9/25/2016 6:00am"
                                        
                                        
                                        #Load the PI AF SDK
                                        [System.Reflection.Assembly]::LoadWithPartialName("OSIsoft.AFSDK") | Out-Null
                                        #Create the PI Server object
                                        $piSrvs = New-Object OSIsoft.AF.PI.PIServers  
                                        #Select one of the following 2 lines, either go with the default server configured on the machine, or use one by name
                                        #[OSIsoft.AF.PI.PIServer]$piSrv = $piSrvs.DefaultPIServer   #Default Server
                                        [OSIsoft.AF.PI.PIServer]$piSrv = $piSrvs["MY-SERVER"]  #Named Server
                                        
                                        
                                        #Define a data type for to pass information in the required structure to FindPIPoint
                                        [Type[]]$types = [OSIsoft.AF.PI.PIServer], [System.Collections.Generic.IEnumerable[OSIsoft.AF.PI.PIPointQuery]], [System.Collections.Generic.IEnumerable[string]]  
                                        
                                        
                                        #Get a handle to the method FindPIPoint
                                        $FindPIPointMethod = [OSIsoft.AF.PI.PIPoint].GetMethod("FindPIPoints",$types)
                                        
                                        
                                        #Get the number of columns used in the file, each line is different, select the highest column count
                                        $numberOfColumns = Get-Content ($path+$file) | 
                                            ForEach-Object{($_.split($delimiter)).Count} | 
                                            Measure-Object -Maximum | 
                                            Select-Object -ExpandProperty Maximum
                                        
                                        
                                        #Import the CSV file so that the headerless file now has numbered columns for easy reference
                                        $Lines = Import-Csv ($path+$file) -Header (1..$numberOfColumns) -Delimiter $delimiter
                                        $firstLine = true
                                        
                                        
                                        #iterate throught each line
                                        ForEach($Line in $Lines){
                                            #First Column of each line identifies the set of tags to be quieried, use it as the dump file name
                                            $dumpFileName = $Line.1
                                            #initialize the Column List String
                                            $ColList = $null
                                            #Initialize the Query List
                                            $queryList = New-Object System.Collections.Generic.List[OSIsoft.AF.PI.PIPointQuery]  
                                            #Iterate trhough the columns
                                            for($i=1; $i -le $numberOfColumns; $i++){
                                                if($Line.$i){
                                                    if($ColList){
                                                        $ColList += ","
                                                    }
                                                    #Build a comma separated list of tags, ignore if the value of the column is empty or null
                                                    $ColList += $Line.$i
                                                    #Initialize a PI Point Query object
                                                    $piPointQuery = New-Object OSIsoft.AF.PI.PIPointQuery([OSIsoft.AF.PI.PICommonPointAttributes]::Tag, [OSIsoft.AF.Search.AFSearchOperator]::Equal, $Line.$i)  
                                                    #Add it to the Query List
                                                    $queryList.Add($piPointQuery)  
                                                }
                                            }
                                            #Validate the list of points passed
                                            $points = $FindPIPointMethod.Invoke($null,@($piSrv,[System.Collections.Generic.List[OSIsoft.AF.PI.PIPointQuery]]$queryList,$null))  
                                        
                                        
                                            #Create a PI Point List
                                            [OSIsoft.AF.PI.PIPointList]$piPointList = New-Object OSIsoft.AF.PI.PIPointList  
                                        
                                        
                                            #Use the retrieved identifiers from the FindPIPoint method
                                            $piPointList.AddRange($points);  
                                        
                                        
                                            #Create the file and add the headers, I will figure out later how to adjust the date retrieved to match tags
                                            if($firstLine) {
                                                Add-Content ($path+$dumpFileName) $ColList
                                                $firstLine=False
                                            }
                                            #Create and populate an array with the desired query times, it will extract points between 6:00am to 8:00am (+1 day).
                                            $times = New-Object System.Collections.ArrayList
                                            for ($i=0;$i -le 1560; $i++)    #1560 = 26 hours * 60 minutes, query begines 6:00AM ends 8:00AM next day, this captures a full gas day
                                            {    
                                                #Time stamp used as index in retrieval file, it is increased by 1 minute at each iteration
                                                $time = ([System.DateTime]$startDate).AddMinutes($i)
                                                #Not sure why we are building an array with date time stamps
                                                $times.Add($time) > $null    
                                                #Prepare the PI Server date time variable by casting the Powershell date time object to a PI Server date time object
                                                $afTime = New-Object OSIsoft.AF.Time.AFTime($time);  
                                                #Query foer the list and dump
                                                #Return a recorded value at the passed time or if no value exists at that time, the previous recorded value.
                                                $result = $piPointList.RecordedValue($afTime,[OSIsoft.AF.Data.AFRetrievalMode]::AtOrBefore);  
                                                
                                                #The following line creates a clean CSV file without any empty columns (succession of commas)
                                                Add-Content ($path+$dumpFileName) $result
                                            }
                                        }
                                        

                                         

                                         

                                        Used C# Syntax Highlighting, it is Powershell

                                          • Re: Programmatic data dumps from PI
                                            JDiaz

                                            The SDK is pretty extensive and just started looking into the PIPointList.InterpolatedValues Method , I believe this to be a better way of doing it since it is a single call, instead of iterating though many single calls.

                                             

                                            // Holds the results keyed on the associated point
                                            Dictionary<PIPoint, AFValues> resultsMap = new Dictionary<PIPoint, AFValues>();
                                            
                                            // Results should be sent back for 100 tags in each page.
                                            PIPagingConfiguration config = new PIPagingConfiguration(PIPageType.TagCount, 100);
                                            
                                            try
                                            {
                                                IEnumerable<AFValues> listResults = pointList.InterpolatedValues(
                                                timeRange, span, null, false, config);
                                            
                                                  foreach (AFValues pointResults in listResults)
                                                {
                                                      // Map the results back to the point
                                                      resultsMap[pointResults.PIPoint] = pointResults;
                                                }
                                            }
                                            catch (OperationCanceledException)
                                            {
                                                  // Errors that occur during bulk calls get trapped here
                                                  // The actual error is stored on the PIPagingConfiguration object
                                                Console.WriteLine(config.Error.Message);
                                            }
                                            catch (Exception otherEx)
                                            {
                                                  // Errors that occur in an iterative fallback method get trapped here
                                                  Console.WriteLine(otherEx.Message);
                                            }
                                            

                                             

                                            Just have to figure out how to do the appropriate casting and point to the methods in PowerShell, help greatly appreciated. We already have the PIPointList, just need to get the handler to the InterpolatedValues method.

                                              • Re: Programmatic data dumps from PI
                                                JDiaz

                                                Here is my full code so far, still have to add job handling with multithreading to increase performance. But if I am right, it should not be so complicated, and I will easily be able to add 10 concurrent jobs. I will then see how it is taxing the server, and if not affecting adversely I will step it up to 20 concurrent jobs, this will cut my 600 queries to about 30 concurrent operations, which should run through it pretty quick without tying a machine for hours on end.

                                                 

                                                #Variables used in the program
                                                $delimiter = ","
                                                $path = "C:\CSV files\"
                                                $file = "Lines.csv"
                                                $exportFile = "expLines.csv"
                                                $startDate = "9/25/2016 6:00am"
                                                
                                                
                                                #Load the PI AF SDK
                                                [System.Reflection.Assembly]::LoadWithPartialName("OSIsoft.AFSDK") | Out-Null
                                                #Create the PI Server object
                                                $piSrvs = New-Object OSIsoft.AF.PI.PIServers 
                                                #Select one of the following 2 lines, either go with the default server configured on the machine, or use one by name
                                                #[OSIsoft.AF.PI.PIServer]$piSrv = $piSrvs.DefaultPIServer  #Default Server
                                                [OSIsoft.AF.PI.PIServer]$piSrv = $piSrvs["MY-SERVER"]  #Named Server
                                                
                                                
                                                #Define data types needed to pass information in the required structure to the invoked methods
                                                [Type[]]$types = [OSIsoft.AF.PI.PIServer], [System.Collections.Generic.IEnumerable[OSIsoft.AF.PI.PIPointQuery]], [System.Collections.Generic.IEnumerable[string]] 
                                                [Type[]]$interpolatedValuesTypes = [OSIsoft.AF.Time.AFTimeRange], [OSIsoft.AF.Time.AFTimeSpan],[System.String], [System.Boolean], [OSIsoft.AF.PI.PIPagingConfiguration]
                                                
                                                
                                                #Holds the results keyed on the associated point 
                                                $resultsMap = @{}  #New-Object system.collections.generic.dictionary[[OSIsoft.AF.PI.PIPoint],[OSIsoft.AF.Asset.AFValues]]
                                                
                                                
                                                #Results should be sent back for 100 tags in each page.
                                                $config = New-Object OSIsoft.AF.PI.PIPagingConfiguration([OSIsoft.AF.PI.PIPageType]::TagCount, 100)
                                                
                                                
                                                
                                                
                                                #Get a handle to the method FindPIPoint
                                                $FindPIPointMethod = [OSIsoft.AF.PI.PIPoint].GetMethod("FindPIPoints",$types)
                                                
                                                
                                                #Get a handle to the method InterpolatedValues
                                                $InterpolatedValuesMethod = [OSIsoft.AF.PI.PIPointList].GetMethod("InterpolatedValues",$interpolatedValuesTypes)
                                                
                                                
                                                
                                                
                                                #Get the number of columns used in the file, each line is different, select the highest column count
                                                $numberOfColumns = Get-Content ($path+$file) |
                                                    ForEach-Object{($_.split($delimiter)).Count} |
                                                    Measure-Object -Maximum |
                                                    Select-Object -ExpandProperty Maximum
                                                
                                                
                                                #Import the CSV file so that the headerless file now has numbered columns for easy reference
                                                $Lines = Import-Csv ($path+$file) -Header (1..$numberOfColumns) -Delimiter $delimiter
                                                $firstLine = $true
                                                
                                                
                                                #iterate throught each line
                                                ForEach($Line in $Lines){
                                                    #First Column of each line identifies the set of tags to be quieried, use it as the dump file name
                                                    $dumpFileName = $Line.1
                                                    #initialize the Column List String
                                                    $ColList = $null
                                                    #Initialize the Query List
                                                    $queryList = New-Object System.Collections.Generic.List[OSIsoft.AF.PI.PIPointQuery] 
                                                    #Iterate trhough the columns
                                                    for($i=1; $i -le $numberOfColumns; $i++){
                                                        if($Line.$i){
                                                            if($ColList){
                                                                $ColList += ","
                                                            }
                                                            #Build a comma separated list of tags, ignore if the value of the column is empty or null
                                                            $ColList += $Line.$i
                                                            #Initialize a PI Point Query object
                                                            $piPointQuery = New-Object OSIsoft.AF.PI.PIPointQuery([OSIsoft.AF.PI.PICommonPointAttributes]::Tag, [OSIsoft.AF.Search.AFSearchOperator]::Equal, $Line.$i) 
                                                            #Add it to the Query List
                                                            $queryList.Add($piPointQuery) 
                                                        }
                                                    }
                                                    #Validate the list of points passed
                                                    $points = $FindPIPointMethod.Invoke($null,@($piSrv,[System.Collections.Generic.List[OSIsoft.AF.PI.PIPointQuery]]$queryList,$null)) 
                                                
                                                
                                                    #Create a PI Point List
                                                    [OSIsoft.AF.PI.PIPointList]$piPointList = New-Object OSIsoft.AF.PI.PIPointList
                                                
                                                
                                                    #Use the retrieved identifiers from the FindPIPoint method
                                                    $piPointList.AddRange($points); 
                                                
                                                
                                                    #Create the file and add the headers, I will figure out later how to adjust the date retrieved to match tags
                                                    if($firstLine) {
                                                        Add-Content ($path+$dumpFileName) $ColList
                                                        $firstLine=$false
                                                    }
                                                   
                                                    #Define the neccesary objects for the InterpolatedValues Method Call
                                                    $listResults = New-Object OSIsoft.AF.Asset.AFValues
                                                    $startDateTime = [System.DateTime]$startDate
                                                    $EndDateTime = $startDateTime.AddHours(26)
                                                    $afStartTime = New-Object OSIsoft.AF.Time.AFTime($startDateTime.ToUniversalTime())
                                                    $afEndTime = New-Object OSIsoft.AF.Time.AFTime($EndDateTime.ToUniversalTime())
                                                    $timeRange = New-Object OSIsoft.AF.Time.AFTimeRange($afStartTime, $afEndTime)
                                                
                                                
                                                    #Create a Time Span (Days, Hours, Minutes, Seconds, Miliseconds
                                                    $timeSpan = New-TimeSpan -days 1 -hours 2
                                                    $span = new-object OSIsoft.AF.Time.AFTimeSpan($timeSpan)
                                                
                                                
                                                    #Retrieve the requested data
                                                    $listResults = $InterpolatedValuesMethod.Invoke($piPointList,@($timeRange,$span,$null,$false, [OSIsoft.AF.PI.PIPagingConfiguration]$config))
                                                    Add-Content ($path+$dumpFileName) $listResults
                                                
                                                
                                                    #Terminate code prematurlly in order to avoid going through the 60 lines.
                                                    break
                                                
                                                
                                                #    #Create and populate an array with the desired query times, it will extract points between 6:00am to 8:00am (+1 day).
                                                #    $times = New-Object System.Collections.ArrayList
                                                #    for ($i=0;$i -le 1560; $i++)    #1560 = 26 hours * 60 minutes, query begines 6:00AM ends 8:00AM next day, this captures a full gas day
                                                #    {   
                                                #        #Time stamp used as index in retrieval file, it is increased by 1 minute at each iteration
                                                #        $time = ([System.DateTime]$startDate).AddMinutes($i)
                                                #        #Not sure why we are building an array with date time stamps
                                                #        $times.Add($time) > $null   
                                                #        #Prepare the PI Server date time variable by casting the Powershell date time object to a PI Server date time object
                                                #        $afTime = New-Object OSIsoft.AF.Time.AFTime($time); 
                                                #        #Query for the list and dump
                                                #        #Return a recorded value at the passed time or if no value exists at that time, the previous recorded value.
                                                #        $result = $piPointList.RecordedValue($afTime,[OSIsoft.AF.Data.AFRetrievalMode]::AtOrBefore); 
                                                #       
                                                #        #The following line creates a clean CSV file without any empty columns (succession of commas)
                                                #        Add-Content ($path+$dumpFileName) $result
                                                #    }
                                                }