Skip navigation
All People > stuart.watson > Stuart Watson's Blog > 2018 > February
2018

Stuart Watson's Blog

February 2018 Previous month Next month

How often have you found that the data you want to capture is arriving after your Event Frame has closed.

In the case of lab quality data, it happens all the time.

 

This PowerShell script will find events based on search criteria, and does a recapture for all events active within the last day.

It will then populate an attribute with the timestamp of the capture.

We plan on setting up a Category called "Late Capture" and recapturing those Event Frames (i.e. set $eventSearch = "CategoryName:Late\ Capture"), running the script every hour.

 

param (
    [string]$server = $env:COMPUTERNAME,                      # AF or PI server
    [string]$dbName = $null,     #Specific Database
    [string]$lateCaptureTimestamp = "Late Capture Timestamp", # Event Frame Attribute holding Late Capture Timestamp
    [string]$eventSearch = 'Name:*', 
    [string]$startTime = '*-1d',
    [string]$endTime = '*'
)


# Load the OSIsoft AF SDK
$refToMyAssembly = [reflection.assembly]::loadwithpartialname("OSIsoft.AFSDK")


# All of the AF Servers
$afServers = New-Object OSIsoft.AF.PISystems
$afServer = $afServers[$server]




if ( $dbName ) {
    $dbSet = $afServer.Databases[$dbName]


} else {
    $dbset = $afServer.Databases
}


foreach ( $db in $dbset ) {


    
    $strSearch = $eventSearch + " Start:>='" + $StartTime + "' End:<='" + $endTime + "'"
    $AFSearch = New-Object OSIsoft.AF.Search.AFEventFrameSearch($db, "CaptureEvents", $strSearch )

    $AFSearch.CacheTimeout = New-TimeSpan -Minutes 10


    Try {
        $events = $AFSearch.FindEventFrames(0,$False,$pgSize)
    } Catch {


        Write-Host Failed to Pull Events
        exit 1


    }
    foreach ( $event in $events ) {
        $recapture = $false
        $checkOut = $false
        $checkIn = $false
        $updateTime = $false
        Try {
            $event.CheckOut()
            $checkout = $True
            $event.CaptureValues()
            $recapture = $True
            if ($lateCaptureTimestamp -ne $null ) {
                $AFNow =  New-Object OSIsoft.AF.Time.AFTime('*')
                $newCaptureTime = New-Object OSIsoft.AF.Asset.AFValue($AFnow.UtcTime,  $AFNow, $null, [OSIsoft.AF.Asset.AFValueStatus]::Good)
                $attr = $event.Attributes.Item($lateCaptureTimestamp) #Try and write the timestamp to the attribute
                if ( $attr -ne $null) { $attr.setValue($newCaptureTime) }
            }
            $event.CheckIn()
            $checkOut = $false
            Write-Host Recaptured Event : "'$event.Name'" at $newCaptureTime.Value.ToLocalTime()
        }
        Catch {
            if ( $checkOut ) { $event.UndoCheckOut() }
            $recapture = $false
            Write-Host Failed to Recapture for Event : "'$event.Name'"
        }


    }
}

 

This works with AF 2016 R2. Anything other than that, you are on your own.

 

Edit: Made a couple of changes after some terrific feedback from Rick, and a couple of days more understanding on paged collections.

We recently had an issue with some inadvertent deletions from our AF database.

Recovering was challenging - and it would have been so much easier if we had had a plain export of our database, that we could have imported into a new database and copied out the parts we needed.

 

This Powershell script will do just that.

It will export all databases on a server, to named and timestamped files.

We have scheduled a task to run this once a week, as a means of archiving changes.

 

param (
    [string]$server = $env:COMPUTERNAME,                      # AF or PI server
    [string]$dbName = $null,     #Specific Database
    [string]$outDirectory = $null, 
    [string]$outRoot = "AFDBExport"
)

# Load the OSIsoft AF SDK
$refToMyAssembly = [reflection.assembly]::loadwithpartialname("OSIsoft.AFSDK")

# All of the AF Servers
$afServers = New-Object OSIsoft.AF.PISystems
$afServer = $afServers[$server]


if ( $dbName ) {
    $dbSet = $afServer.Databases[$dbName]


} else {
    $dbset = $afServer.Databases
}


$expMode = [OSIsoft.AF.PIExportMode]::AllReferences
$expMode = $expMode -bor [OSIsoft.AF.PIExportMode]::Security
$expMode = $expMode -bor [OSIsoft.AF.PIExportMode]::Flat
$expMode = $expMode -bor [OSIsoft.AF.PIExportMode]::SimplifiedConfigStrings
$expMode = $expMode -bor [OSIsoft.AF.PIExportMode]::DefaultValues


if ( $outDir -eq $null ) {
    if ( $PSScriptRoot -eq $null ) {
        $outDir = split-path -parent $MyInvocation.MyCommand.Definition
    } else {
        $outDir = $PSScriptRoot
    }
}
# The Date Part is set once per run
$datePart = Get-Date -Format 'yyyyMMddhhmmss'


foreach ( $db in $dbset ) {
    $childPath = $outRoot + '-' + $db.Name + '-' + $datePart + '.xml'
    [System.IO.Path]::GetInvalidFileNameChars() | % {$childPath = $childPath.replace($_,'_')} # Clean up the filename
    $filename = join-path -Path $outDir -ChildPath $childPath
    Write-Host "Exporting ""$db"" to ""$filename"""
    #
    $afServer.ExportXML($db,  $expMode, $filename, $null, $null, $null)
}