Updating powerGate Customizations

How to update powerGate project implemantations to use the latest powerGate version features

This article describes the necessary changes when updating an ERP integration to be compatible with the latest powerGate update and use its latest features.

PG 21.0.13

Projects based on powerGateTemplate (b57451032) and older can make use of the Cmdlets default error behavior allowing the use of automatic variables like $? or $Error

Connecting to ERP:

  • Replace Write-Error in ConnectToConfiguredErpServer with throw and make sure to call Connect-ERP directly before checking the connection
    function ConnectToConfiguredErpServer {
        Log -Begin
        $powerGateServerErpPluginUrl = CreateUrlFromPGServerName
        if (-not $powerGateServerErpPluginUrl){
            Write-Error -Message "no ERP Server URL specified!"
            return
        }
        else {
            $connected = ConnectToErpServer -PowerGateServerErpPluginUrl $powerGateServerErpPluginUrl
            if (-not $connected) {
                $connectionError = ("Error on connecting to powerGateServer service! Check if powerGateServer is running on following host: '{0}' or try to access following link via your browser: '{1}'" -f (([Uri]$powerGateServerErpPluginUrl).Authority), $powerGateServerErpPluginUrl)
                Write-Error -Message $connectionError
            }
            return $connected
        }
        Log -End
    }

    to

    function ConnectToConfiguredErpServer {
        Log -Begin
        $powerGateServerErpPluginUrl = CreateUrlFromPGServerName
        if (-not $powerGateServerErpPluginUrl){
            throw "No ERP Server URL specified!"
        }

        $connected = Connect-ERP -Service $PowerGateServerErpPluginUrl
        if (-not $connected) {
            throw "Connection to ERP could not be established!! Reason: $($Error[0]) (Source: $($Error[0].Exception.Source))"
        }
        return $connected
        
        Log -End
    }
  • Remove the function ConnectToErpServer. Make sure that Connect-ERP is called one time during the OnLogOn event in Vault and one time in the InitializeWindow function in Inventor.

Until PowerShell 7, containing a statement within parentheses (...), subexpression syntax $(...) or array expression @(...) always reset $? to True, so that (Write-Error) shows $? as True. This has been changed in PowerShell 7, so that $? always reflects the actual success of the last command run in these expressions.

Error handling:

  • Remove the function Get-PgsErrorForLastResponse and replace all its usages with
    if(-not $?) {
        $result = @{
        Entity = $null
        ErrorMessage = $Error[0]
        }
    }
    else {
        $result = @{
        Entity = $erpEntity #Is different in different parts of the code
            ErrorMessage = $null
        }
    }

For example:

function CreateErpMaterial($erpMaterial) {
    Log -Begin
    #TODO: Numbering generation for material creation (only if needed)
    if ($null -eq $erpMaterial.Number -or $erpMaterial.Number -eq "") {
        $erpMaterial.Number = "*"
    }
    #TODO: Properties that need to be set on create
    $erpMaterial.ModifiedDate = [DateTime]::Now

    $erpMaterial = TransformErpMaterial -erpMaterial $erpMaterial
    $erpMaterial = Add-ErpObject -EntitySet $materialEntitySet -Properties $erpMaterial
    $result = Get-PgsErrorForLastResponse -Entity $erpMaterial -WriteOperation
    Log -End
    return $result
}

to

function CreateErpMaterial($erpMaterial) {
    Log -Begin
    #TODO: Numbering generation for material creation (only if needed)
    if ($null -eq $erpMaterial.Number -or $erpMaterial.Number -eq "") {
        $erpMaterial.Number = "*"
    }
    #TODO: Properties that need to be set on create
    $erpMaterial.ModifiedDate = [DateTime]::Now

  $erpMaterial = TransformErpMaterial -erpMaterial $erpMaterial
    $erpMaterial = Add-ErpObject -EntitySet $materialEntitySet -Properties $erpMaterial
    if(-not $?) {
        $result = @{
            Entity = $erpMaterial
            ErrorMessage = $Error[0]
        }
    }
    else {
        $result = @{
            Entity = $erpMaterial
            ErrorMessage = $null
        }
    }
    
    Log -End
    return $result
}

PG 22.0.1

Changes to powerGate Client implementation

Dissolve CRUD functions:

The CRUD functions make it hard to do the necessary further changes. To dissolve them we need to replace all calls to the CRUD functions with the powerGate cmdlet that is used within them. When dissolving the function the following things should be achieved.

  • Result object should be removed. As powerGate cmdlets are now called directly where they are needed the return value is the actual ERP object
  • The powerGate error handling should be used. This means after calling a powerGate cmdlet the $? object can be used to check for errors
  • Variable names should be updated to reflect that they now contain ERP objects instead of result objects

Example CreateErpBomHeader:

function CreateErpBomHeader($erpBomHeader) {
    Log -Begin
    #TODO: Property manipulation for bom header create
    $erpBomHeader.ModifiedDate = [DateTime]::Now

    $erpBomHeader = Add-ERPObject -EntitySet $bomHeaderEntitySet -Properties $erpBomHeader
    if(-not $?) {
        $result = @{
            Entity = $erpBomHeader
            ErrorMessage = $Error[0]
        }
    }
    else {
        $result = @{
            Entity = $erpBomHeader
            ErrorMessage = $null
        }
    }
    $result = Get-PgsErrorForLastResponse -Entity $erpBomHeader -WriteOperation
    Log -End
    return $result
}

In Transfer-Boms the call looks like this:

$createErpBomHeaderResult = CreateErpBomHeader -erpBomHeader $erpBomHeader
if($createErpBomHeaderResult.ErrorMessage) {
    Update-BomWindowEntity $vaultBom -Status "Error" -StatusDetails $createErpBomHeaderResult.ErrorMessage
    foreach ($vaultBomRow in $vaultBom.Children) {
        Update-BomWindowEntity $vaultBomRow -Status "Error" -StatusDetails $createErpBomHeaderResult.ErrorMessage
    }
}

As powerGate takes care of connection errors it is possible to simplify the code when moving it up.

  • The old function call is replaced by the Get-ERPObject call.
  • $? is now used to check for errors. 
  • Update-BomWindowEntity call for the BOM header is removed completely as powerGate will set errors by itself.
  • Update-BomWindowEntity call for the BOM row is updated to set -StatusDetails to the _StatusDetails property of the BOM header.
  • The function output is assigned to $null as it is not used in any other places
$null = Add-ERPObject -EntitySet "BomHeaders" -Properties $erpBomHeader
if ($? -eq $false) {
    foreach ($vaultBomRow in $vaultBom.Children) {
        Update-BomWindowEntity $vaultBomRow -Status "Error" -StatusDetails $vaultBom._StatusDetails
    }

    continue
}

Don't forget to replace other usages of $getErpMaterialResult!

Some Log calls might need to be removed or the .ErrorMessage property needs to be replaced by $Error[0] 

In CompareErpBom you can ignore the '$differences += New-Object' statements for the time being as they will be refactored in the BOM window section of this article

List of all CRUD functions:

BomFunctions.psm1

  • GetErpBomHeader
  • CreateErpBomHeader
  • UpdateErpBomHeader
  • GetErpBomRow
  • CreateErpBomRow
  • UpdateErpBomRow
  • RemoveErpBomRow
MaterialFunctions.psm1
  • GetErpMaterial
  • CreateErpMaterial
  • UpdateErpMaterial

Bom Window:

In order to prevent incorrect messages being shown during check or transfer operations within the BOM window the following changes should be made.

Communication errors are now automatically assigned to Bom Headers so the StatusDetails for BOM headers don't need to be updated manually in case of error. They still need to be handled for children.

If a BOM window entities state is updated before an error occurs it doesn't automatically display the error

  • In Check-Boms remove the "Unknown" -Status assignment loop of BOM headers and children.
    if ($vaultBom._Status -ne "Unknown") {
        Update-BomWindowEntity -InputObject $vaultBom -Status $vaultBom._Status -StatusDetails $vaultBom.Message
        foreach ($vaultBomRow in $vaultBom.Children) {
            Update-BomWindowEntity -InputObject $vaultBomRow -Status $vaultBomRow._Status -StatusDetails $vaultBomRow.Message
        }
        continue
    }
CompareErpBom should be merged into Check-Boms:
  • Merging the logic of CompareErpBOM with Check-Boms gives the BOM window the possibility to show the immediate status feedback on individual rows instead of assigning the states at once.
  • Connection errors are automatically displayed on the according rows.
  • It will handle a rare issue where positions are incorrectly marked as "New", that occurred because the $differences array could contain a BOM position multiple times
  • In CompareErpBom replace all the return statements with a continue statement. The last return statement should be removed completely.
  • In CompareErpBom refactor all assignments of the $differences array. Instead of collecting the state of the BOM in the array use the Update-BomWindowEntity cmdlet to update them immediately or remove them where appropriate
    • Errors that are the result of a powerGate cmdlet call on BOM headers should be removed as those are now handled by powerGate
    • Other errors on BOM headers like in the (-not $number) condition still need to be set as they are not the result of a powerGate cmdlet call
    • Errors on bom rows still need to be set in general. Their -StatusDetails can be set to the .StatusDetails property of their parent
    For example:
    $erpBomHeader = Get-ERPObject -EntitySet "BomHeaders" -Keys @{Number = $number } -Expand "BomRows" 
    if ($? -eq $false) {
        Log -Message "Error in GetErpBomHeader $($Error[0])"
        $differences += New-Object -Type PsObject -Property @{AffectedObject = $VaultBom; Status = "Error"; Message = $getErpBomHeaderResult.ErrorMessage; IsHeader = $true }
        foreach ($vaultBomRow in $VaultBom.Children) {
            $differences += New-Object -Type PsObject -Property @{AffectedObject = $vaultBomRow; Status = "Error"; Message = $getErpBomHeaderResult.ErrorMessage; IsHeader = $false }
        }

        Log -Message "Return differences error in GetERpBomHeader. $($Error[0])"
        continue
    }

     to

    $erpBomHeader = Get-ERPObject -EntitySet "BomHeaders" -Keys @{Number = $number } -Expand "BomRows" 
    if ($? -eq $false) {
    Log -Message "Error in GetErpBomHeader $($Error[0])"
        foreach ($vaultBomRow in $VaultBom.Children) {
          Update-BomWindowEntity -InputObject $vaultBomRow -Status Error -StatusDetails $vaultBOM._StatusDetails
        }
    Log -Message "Return differences error in GetERpBomHeader. $($Error[0])"
       
    continue
    }

If a BOM window entities' state is updated before an error occurs it doesn't automatically display the error

  • In Transfer-Boms replace the whole foreach loop
    foreach ($vaultBom in $VaultBoms) { ... }

    with the foreach loop from CompareErpBoms

    foreach ($vaultBom in $VaultBoms) {
    $number = GetEntityNumber -entity $VaultBom

    ...

    }

    Afterwards CompareErpBoms can be removed

Message boxes:

Message boxes might appear behind other windows and lock Vault or Inventor this way. Also multiple messages will be displayed per error if message boxes are used due to powerGate error handling. Therefore message boxes, displaying connection errors, should be removed altogether.

  • In ConnectToErpServerWithMessageBox remove
    if (-not $connected) {
        $connectionError = ("Error on connecting to powerGateServer service! Check if powerGateServer is running on following host: '{0}' or try to access following link via your browser: '{1}'" -f (([Uri]$powerGateServerErpPluginUrl).Authority), $powerGateServerErpPluginUrl)
        Write-Error -Message $connectionError
        ShowMessageBox -Message $connectionError -Icon Error
    }

Non terminating cmdlet errors are now displayed in PowerShell IDEs

  • In CAD.Custom\addins\powerGateMain.ps1/CreateOrUpdateErpMaterial and Vault.Custom\addinVault\powerGateMain.ps1/CreateOrUpdateErpMaterial remove the message boxes from the conditions containing "...ErpMaterialResult.ErrorMessage". 
    For example 
    $createErpMaterialResult = CreateErpMaterial -erpMaterial $materialTabContext.Entity
    if($createErpMaterialResult.ErrorMessage) {
        ShowMessageBox -Message $createErpMaterialResult.ErrorMessage -Icon "Error" -Title "powerGate ERP - Create Material" | Out-Null
    }
    else { 
        ShowMessageBox -Message "$($createErpMaterialResult.Entity.Number) successfully created" -Title "powerGate ERP - Create Material" -Icon "Information" | Out-Null
        $vaultEntity = GetSelectedObject
        SetEntityProperties -erpMaterial $createErpMaterialResult.Entity -vaultEntity $vaultEntity
    }

    to

    $createErpMaterialResult = CreateErpMaterial -erpMaterial $materialTabContext.Entity
    if($createErpMaterialResult.ErrorMessage) {
        return
    }
    ShowMessageBox -Message "$($createErpMaterialResult.Entity.Number) successfully created" -Title "powerGate ERP - Create Material" -Icon "Information" | Out-Null
    $vaultEntity = GetSelectedObject
    SetEntityProperties -erpMaterial $createErpMaterialResult.Entity -vaultEntity $vaultEntity
  • In ExecuteErpSearch remove
    if ($searchErpMaterialsResult.ErrorMessage) {
        ShowMessageBox -Message $searchErpMaterialsResult.ErrorMessage -Icon "Error" -Title "powerGate ERP - Search"
    }

Fix misleading errors on Vault tab context switch:

When changing the tab context in Vault a misleading error message could be displayed:

Error occurred while executing powershell function OnTabContextChanged ... The property 'UnitOfMeasure' cannot be found on this object. Verify that the property exists and can be set.

In Vault.Custom\addinVault\powerGateMain.ps1/OnTabContextChanged_powerGate change

function OnTabContextChanged_powerGate($xamlFile) {
    Open-VaultConnection
    if ($xamlFile -eq "ERP Item.xaml") {
        InitMaterialTab
    }
    elseif ($xamlFile -eq "erpBom.xaml") {
        InitBomTab
    }
}
to
function OnTabContextChanged_powerGate($xamlFile) {
    Open-VaultConnection

    $erpServices = Get-ERPServices -Available
    if (-not $erpServices -or $erpServices.Count -le 0) {
        $dswindow.FindName("lblStatusMessage").Content = "One or more services are not available!"
        $dswindow.FindName("lblStatusMessage").Foreground = "Red"
        $dsWindow.IsEnabled = $false
       
return
    }
    if ($xamlFile -eq "ERP Item.xaml") {
        InitMaterialTab
    }
    elseif ($xamlFile -eq "erpBom.xaml") {
        InitBomTab
    }
}

In Vault.Custom\Configuration\File\Erp Item.xaml and In Vault.Custom\Configuration\Item\Erp Item.xaml in line 77 add a name property to the label

<Label Margin="14,0,0,0" FontSize="14" FontWeight="Medium" VerticalAlignment="Center">
    <Label.Style>
        <Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type Label}}">
          <Setter Property="Content" Value="ERP: Create Material"/>
<Label x:Name="lblStatusMessage" Margin="14,0,0,0" FontSize="14" FontWeight="Medium" VerticalAlignment="Center">
    <Label.Style>
        <Style TargetType="{x:Type Label}" BasedOn="{StaticResource {x:Type Label}}">
          <Setter Property="Content" Value="ERP: Create Material"/>

In Vault.Custom\Configuration\File\erpBom.xaml and In Vault.Custom\Configuration\Item\erpBom.xaml in line 97 add a name property to the label

<Label Margin="14,0,0,0" FontSize="14" FontWeight="Medium" VerticalAlignment="Center">
    <Label.Style>
        <Style TargetType="{x:Type Label}">
            <Setter Property="Content" Value="ERP: Bill Of Material"/>
<Label x:Name="lblStatusMessage" Margin="14,0,0,0" FontSize="14" FontWeight="Medium" VerticalAlignment="Center">
    <Label.Style>
        <Style TargetType="{x:Type Label}">
            <Setter Property="Content" Value="ERP: Bill Of Material"/>

In Vault 2022 and newer the error

"You are not connected to an ERP system! ..."

shouldn't appear anymore due to changes in how the DataStandard "OnLogOn" and "onTabContextChanged" events work

 

powerEvents:

RestrictFileRelease and RestrictItemRelease functions contain try/catch/finally statements which can be removed. After connection errors arise, the registered _Restrictions events now become automatically restricted (see Errors)

Changes to powerGate Server

Requires at least powerGateServer 21.0.5

The webservice path needs to be prefixed with a 'PGS/' to ensure it can be distinguished in situations without any response.

[WebServiceData("PGS/{my_original_path}","{my_web_service_name}")]

Afterwards the url to the PGS plugin must be adapted within all custom ERP integrations: 'Connect-ERP 'http://{pgs-machine}:8080/PGS/{my_original_path}/{my_web_service_name}'

23.0.1

powerGate now requires Vault Professional Client to be installed on the same machine. Due to this we had to provide new setups that are not able to update Vault Workgroup or Vault Professional 2022 or older versions

Updating Download-Setups:

Projects based on powerGateTemplate (e913355 and earlier):

  • The name of the powerGate setup file changed and includes a '_Vault{Version}.exe' suffix. Change the powerGate setup name from
    "powerGate" = @{
        "2020" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerGate21.0.exe"
        "2021" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerGate21.0.exe"
        "2022" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerGate21.0.exe"
    }

    to

    "powerGate" = @{
        "2021" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerGate23.0_Vault2021.exe"
        "2022" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerGate23.0_Vault2022.exe"
        "2023" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerGate23.0_Vault2023.exe"
    }
  • PowerEvents is now installed by the powerGate installer. Remove the powerEvents setup download 
    "powerEvents" = @{
        "2020" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerEvents22.0_Vault2020.exe"
        "2021" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerEvents22.0_Vault2021.exe"
        "2022" = "https://coolorangedownloads.blob.core.windows.net/downloads/cO_powerEvents22.0_Vault2022.exe"
    }

23.0.4

 

As CatalogService now automatically connects to all available services invalid connections to dummy services could happen. Make sure the dummy "ERP" service is not installed on any live system.

- Multiple `Connect-ERP` cmdlet usages within Vault Client and Inventor can slow down the application startup and lead to multiple error dialogs beeing displayed on connection problems. The ConnectToConfiguredErpServer usage during powerEvents import routines must therefore be removed. -> please verify the need for the Remove-Module usage. Only when DataStandard OnLogon functionalities are not used, the powerEvent scripts should instead invoke this function on its own. In DataStandard for Vault 2022 and earlier versions, the module becomes imported in several PowerShell Runspaces, so also when closing the Vault Client. Connection Error dialogs can than prevent the process from terminating.

- The InitializeWindow and OnLogOn functions cause multiple connections to powerGateServer or ERP again. In order to prevent performance problems with slow ERP systems and many Connection Error Dialogs beeing displayed at the start of the Vault Client, the function `ConnectToErpServerWithMessageBox` should be called by only one of these functions (if possible te OnLonOn).

 

24.0.13

In addition to the configurability of ERP list-values, there is also a new ERPCombobox control to display them.

Regular WPF ComboBoxes can be easily replaced with the ERPComboBox using the following steps.

The behavior for Vault users remains largely unchanged, except that data problems can immediately be recognized.

In earlier versions, values not present in the ItemSource were unfortunately not displayed, but still transferred.

1. In the xaml code, the ComboBox control can be replaced as follows:

2024-02-22_11-01-08

 

2. in the powershell script code can be reduced, especially in the Create area (including sorting and blank-value display)

2024-02-22_11-30-34

 

3. A Vault administrator must now manually transfer the list-values from the original powerGateConfiguration.xml file to the Configuration Dialog:

To achieve this, add all <Entry Key="..." Value="..." /> entries to the Possible Values list for the respective ERP field (e.g. SparePartIndicators). Entries for empty values can be ignored.

Note: If there are a lot of entries involved, take a look at these programming examples for possible automations: Retrieve values for drop-down lists live from ERP.

 

4. Finally you can remove all switch and if statements that translate specific Vault values to corresponding ERP values from PowerShell scripts.

Configure a Vault Property mapping for these ERP fields. Then simply use the List-Values dialog to map the previously programmed Vault values to the corresponding ERP values.

 

Within the BOM Window:

To ensure only configured ERP values beeing transferred for automatic Item creations, consider extending the New-ERPObject -VaultEntity line with the following validation:

$erpItem = $file | New-ERPObject -EntityType 'Item'

if($erpItem.psobject.Error) {
   $file | Update-BomWindowEntity -Status Error -StatusDetails $erpItem.psobject.Error
   continue
}
...