Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagepowershell
titlewsl_workflow_export_objects_example Powershell Script
collapsetrue
# ScriptVersion:001002 MinVersion:10400 MaxVersion:* TargetType:Common ModelType:* ScriptType:PowerShell (64-bit)
# --    (c) Wherescape Inc 2025. WhereScape Inc permits you to copy this Module solely for use with the RED software, and to modify this Module            -- #
# --    for the purposes of using that modified Module with the RED software, but does not permit copying or modification for any other purpose.           -- #
#==============================================================================
# Script Name      :    wsl_workflow_export_objects_example.ps1
# Description      :    Sample Workflow script to export object metadata.
#                  :    Designed to be called by a separate Workflow Script, see the user-guide section 'Workflow Script Samples' for details.
# Author           :    WhereScape Inc
#==============================================================================
# Notes / History
# 001 : Initial release.
# 002 : Include Jobs.
#==============================================================================
 
Function Execute-Command ($commandTitle, $commandPath, $commandArguments)
{
    Try {
        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = $commandPath
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
        $pinfo.UseShellExecute = $false
        $pinfo.WindowStyle = 'Hidden'
        $pinfo.CreateNoWindow = $True
        $pinfo.Arguments = $commandArguments
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null
        $stdout = $p.StandardOutput.ReadToEnd()
        $stderr = $p.StandardError.ReadToEnd()
        $p.WaitForExit()
        $p | Add-Member "commandTitle" $commandTitle
        $p | Add-Member "stdout" $stdout
        $p | Add-Member "stderr" $stderr
    }
    Catch {
      throw
    }
    $p
}
 
function WriteAudit($message, $type="audit", $statusCode="I") {
  $msg = "$type : $message"
  if ($statusCode -in ('E')) {
    Write-Host $msg -ForegroundColor Red
  }
  else {
    Write-Host $msg -ForegroundColor Green
  }
}
 
function Exit-Script([int]$scrResCode=0, $scrResMsg="Success") {
  $scriptExitCode = $scrResCode
  if ($scrResCode -ne 0) {
    WriteAudit $scrResMsg "result" "E"
  }
  else {
    WriteAudit $scrResMsg "result" "S"
  }
  Exit $scriptExitCode
}
 
Function Start-RedMetadataService {
    # Returns System.Diagnostics.Process - this process relies on RED Script Environment variables
 
    $StartInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{
                    FileName = "${ENV:WSL_BINDIR}WslMetadataService.exe"
                    Arguments = ' --meta-dsn "WSENV~WSL_META_DSN~" --meta-user "WSENV~WSL_META_USER~" --meta-password "WSENV~WSL_META_PWD~" --meta-schema "WSENV~WSL_META_SCHEMA~" --meta-db-type 14 --ws-user "REST_API" --log-level 4 --meta-dsn-arch WSENV~WSL_META_DSN_ARCH~ --meta-con-string "WSENV~WSL_META_CONSTRING~"'
                    UseShellExecute = $false
                    RedirectStandardOutput = $true
                    RedirectStandardError = $true
                    RedirectStandardInput = $true # WslMetadataService requires stdin to be open while in use, once closed the service will stop.
                    CreateNoWindow = $false
                }
 
    #Create process Object
    $RedMdsProcess = New-Object System.Diagnostics.Process
 
    #Assign the process parameters and custom members
    $RedMdsProcess.StartInfo = $StartInfo
    $RedMdsProcess | Add-Member "RedMdsReadyForInput" $false
    $RedMdsProcess | Add-Member "RedMdsUrl" ""
    $RedMdsProcess | Add-Member "RedMdsToken" ""
    $RedMdsProcess | Add-Member "RedMdsErrorLog" ""
    $RedMdsProcess | Add-Member "RedMdsDataLog" ""
 
    # Add wait method
    $waitScript = {
        $timeoutMinutes = @($args[0], 5 -ne $null)[0]
        $startDate = Get-Date
        while (-not $this.RedMdsReadyForInput -and ($startDate.AddMinutes($timeoutMinutes) -gt (Get-Date) -or $timeoutMinutes -eq 0) ) {       
            # Wait briefly before rechecking
            Start-Sleep -Milliseconds 100
        }
    }
    $addMemberSplat = @{
        MemberType = 'ScriptMethod'
        Name = 'WaitForRedMdsReadyForInput'
        Value = $waitScript
    }
    $RedMdsProcess | Add-Member @addMemberSplat
 
    # Add startup command method
    $startRedMdsScript = {
        if($this.Start()){
            # Register Process Object Events
            $OutEvent = Register-ObjectEvent -Action {
                $Sender.RedMdsDataLog += $Event.SourceEventArgs.Data
                # Write-Host $Event.SourceEventArgs.Data
                if($Event.SourceEventArgs.Data -match '^{"message":"http://localhost:\d\d\d\d/","success":true,"token":".*"}') {
                    $Sender.RedMdsReadyForInput = $true   
                    $tokenJson = ConvertFrom-Json $Event.SourceEventArgs.Data
                    $Sender.RedMdsToken = $tokenJson.token # set the access token
                    $Sender.RedMdsUrl = $tokenJson.message # set the URL    
                }
            } -InputObject $this -EventName OutputDataReceived
 
            $ErrEvent = Register-ObjectEvent -Action {
                if($Event.SourceEventArgs.Data -ne $null){
                    $Sender.RedMdsErrorLog += "`n"+$Event.SourceEventArgs.Data
                }
            } -InputObject $this -EventName ErrorDataReceived
 
            $ExitEvent = Register-ObjectEvent -Action {
                # Unregister events
                $OutEvent.Name, $ExitEvent.Name, $ErrEvent.Name |
                    ForEach-Object {Unregister-Event -SourceIdentifier $_}
            } -InputObject $this -EventName Exited
 
            # Begin output redirection
            $this.BeginOutputReadLine()
            $this.BeginErrorReadLine()
            $this.WaitForRedMdsReadyForInput()
        }
    }
    $addMemberSplat = @{
        MemberType = 'ScriptMethod'
        Name = 'StartRedMds'
        Value = $startRedMdsScript
    }
    $RedMdsProcess | Add-Member @addMemberSplat
 
    # Add stop command method
    $stopRedMdsScript = {
        $this.StandardInput.Close()
        $this.WaitForExit()
        $this.Dispose()
    }
    $addMemberSplat = @{
        MemberType = 'ScriptMethod'
        Name = 'StopRedMds'
        Value = $stopRedMdsScript
    }
    $RedMdsProcess | Add-Member @addMemberSplat
 
    # Start process
    $RedMdsProcess.StartRedMds()
 
    return $RedMdsProcess
 
}
 
Add-Type -Path "${ENV:WSLBINDIR}Newtonsoft.Json.dll"
 
# MAIN
# Check for the expected context file otherwise exit
if ( -not (Test-Path -path "$PSScriptRoot\wsla${ENV:WSL_SEQUENCE}.objects") ) {
  Exit-Script 2 "*** Error: Objects file doesn't exist as there were no objects in the current context. ***"
}
 
try {
 
  # initialise common vars
  $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
  $baseExportDir = join-path "${ENV:WSL_WORKDIR}" "EXPORT__${ENV:WSL_META_DSN}" # root directory for the export objects, change this to suit your needs
  $redMetadataServiceProcess = Start-RedMetadataService
  $redMetadataServiceUri = $redMetadataServiceProcess.RedMdsUrl
  $redMetadataServiceHeaders = @{"Authorization"= "Bearer $($redMetadataServiceProcess.RedMdsToken)"}
  $redCliLogFile = "${ENV:WSL_WORKDIR}\redCliBatchCmds_${env:WSL_SEQUENCE}.log"
    $resultExitCode = 0
  $resultMsg = "`n`n Exported Objects to: $baseExportDir `n`nLogs are located in the work directory of the script and have a sequence ID of ${ENV:WSL_SEQUENCE}: `n${ENV:WSL_WORKDIR}`n`nYou can now close this Powershell window."  
 
  # Parse json .objects file
  $contextJson = Get-Content "$PSScriptRoot\wsla${ENV:WSL_SEQUENCE}.objects" | Out-String | ConvertFrom-Json
   
  # Initial RedCli batch json hash-table
  $batchHt = [ordered]@{
     "Common Options" = @{
      "exit-on-error" = $false
      "log-level" = 4
      "output-mode" = "json"   
     }
    "Metadata Repository" = @{
      "meta-database" = ""
      "meta-dsn" = ""
      "meta-dsn-arch" = "64"
      "meta-password" = ""
      "meta-user-name" = ""
    }
  }
  
  # Initialise Obj Hash Table
  $htRedObjects = [ordered]@{}
  
  # Get Objects in Context
  if ($contextJson.objectsByName -ne $null) {
    $htRedObjects = [ordered]@{}
    # Populates a hastable with obj-name as Key and obj-type as Value from RED formatted json
    $contextJson.objectsByName | get-member -type properties | %{ $htRedObjects[$_.name] = $contextJson.objectsByName."$($_.name)".objectType.name }
  }
  else {
    # This script can't work on Jobs and Paramters alone so exit if there are no Objects in the context
       # Exit-Script 2 "*** Error: The current context doesn't conatin any Objects. ***"
  }
  
  # initialiseGet RedCliJobs Commandsin arrayContext
  $batchRedCliCmds = @() # array of redcli commandsif ($contextJson.jobsByName -ne $null) {   
   
  # Export Host ScriptsPopulates a hastable with obj-name as Key and obj-type as Value from RED formatted json
  $scrNames = $htRedObjects$contextJson.KeysjobsByName | Where-Object%{ {$htRedObjects[$_] -eq "Host Script"}
  if ($scrNames = 'Job' }
  }
 
  # Get Parameters in Context
  if ($contextJson.parametersByName -ne $null) {   
    # createPopulates outputa directory
hastable    $scrDir= Join-Path $baseExportDir "Host Script"
    if (-not (Test-Path $scrDir)) {
      $null = New-Item -ItemType Directory -Path $scrDir | Out-Null
    }
    # create cmds
    $scrCmdswith obj-name as Key and obj-type as Value from RED formatted json
    $contextJson.parametersByName | %{ $htRedObjects[$_] = 'Parameter' }
  }
  
  # initialise RedCli Commands array
  $batchRedCliCmds = @()
 # array of $scrNames | %{redcli commands
    
  # buildExport RedCliHost cmdsScripts
  $scrNames    $scrCmds += 'script export --name "'+ $_ +'" -d "'+ $scrDir +'" --file-name auto_name --force'
 
  $htRedObjects.Keys | Where-Object {$htRedObjects[$_] -eq "Host Script"}
  if ($scrNames -ne $null) {
    # exportcreate metadataoutput fordirectory
 object via metadata service
      $uri = [URI]::EscapeUriString("$($redMetadataServiceUri)objectsExportByName/$_")$scrDir= Join-Path $baseExportDir "Host Script"
    if (-not (Test-Path $scrDir)) {
      $createResponse$null = InvokeNew-WebRequestItem -UriItemType $uriDirectory -UseBasicParsingPath -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders$scrDir | Out-Null
    }
  $outFile = Join-Path# $scrDir "$_.metadata"create cmds
    $scrCmds = @()
    $scrNames | %{
      # build RedCli cmds
      $scrCmds += 'script export --name "'+ $_ +'" -d "'+ $scrDir +'" --file-name auto_name --force'
 
      # export metadata for object via metadata service
      $uri = [URI]::EscapeUriString("$($redMetadataServiceUri)objectsExportByName/$_")
      $createResponse = Invoke-WebRequest -Uri $uri -UseBasicParsing -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders
      $outFile = Join-Path $scrDir "$_.metadata"
      # Convert JSON to JObject
      $jObject = [Newtonsoft.Json.Linq.JObject]::Parse($createResponse.Content)
      $prettyJson = $jObject.ToString([Newtonsoft.Json.Formatting]::Indented)
      [System.IO.File]::WriteAllLines($outFile, $prettyJson, $Utf8NoBomEncoding)       
    }
    # add RedCli cmds
    $batchRedCliCmds += $scrCmds
  }
 
  # Export Procedures
  $procNames = $htRedObjects.Keys | Where-Object {$htRedObjects[$_] -eq "Procedure"}
  if ($procNames -ne $null) {
    # create output directory
    $procDir= Join-Path $baseExportDir "Procedure"
    if (-not (Test-Path $procDir)) {
      New-Item -ItemType Directory -Path $procDir | Out-Null
    }
    # create cmds
    $procCmds = @()
    $procNames | %{
      # build RedCli cmds
      $procCmds += 'procedure export --name "'+ $_ +'" -d "'+ $procDir +'" --file-name auto_name --force'
     
      # export metadata for object via metadata service
            $uri = [URI]::EscapeUriString("$($redMetadataServiceUri)objectsExportByName/$_")
      $createResponse = Invoke-WebRequest -Uri $uri -UseBasicParsing -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders
      $outFile = Join-Path $procDir "$_.metadata"
      # Convert JSON to JObject
      $jObject = [Newtonsoft.Json.Linq.JObject]::Parse($createResponse.Content)
      $prettyJson = $jObject.ToString([Newtonsoft.Json.Formatting]::Indented)
      [System.IO.File]::WriteAllLines($outFile, $prettyJson, $Utf8NoBomEncoding)
       }
    }
    # add RedCli cmds
    $batchRedCliCmds += $scrCmds$procCmds  
  }
 
  # Export ProceduresTemplates
  $procNames$temNames = $htRedObjects.Keys | Where-Object {$htRedObjects[$_] -eq "ProcedureTemplate"}
  if ($procNames$temNames -ne $null) {
    # create output directory
    $procDir$temDir= Join-Path $baseExportDir "ProcedureTemplate"
    if (-not (Test-Path $procDir$temDir)) {
      New-Item -ItemType Directory -Path $procDir$temDir | Out-Null
    }
    # create cmds
    $procCmds$temCmds = @()
    $procNames$temNames | %{
      # build RedCli cmds
      $procCmds$temCmds += 'proceduretemplate export --name "'+ $_ +'" -d "'+ $procDir$temDir +'" --file-name auto_name --force'  
     
      # export metadata for object via metadata service
            $uri = [URI]::EscapeUriString("$($redMetadataServiceUri)objectsExportByName/$_")
      $createResponse = Invoke-WebRequest -Uri $uri -UseBasicParsing -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders
      $outFile = Join-Path $procDir$temDir "$_.metadata"
      # Convert JSON to JObject
      $jObject = [Newtonsoft.Json.Linq.JObject]::Parse($createResponse.Content)
      $prettyJson = $jObject.ToString([Newtonsoft.Json.Formatting]::Indented)
      [System.IO.File]::WriteAllLines($outFile, $prettyJson, $Utf8NoBomEncoding)
    }
        # add RedCli cmds
    $batchRedCliCmds += $procCmds  
  }
 
  # Export Templates
  $temNames = $htRedObjects.Keys | Where-Object {$htRedObjects[$_] -eq "Template"})
  if ($temNames -ne}
 $null) {
  $batchRedCliCmds += #$temCmds create output directory
  }
 
 $temDir= Join-Path# $baseExportDirExport "Template"DDL
  $objNames = if (-not (Test-Path $temDir)) {
      New-Item -ItemType Directory -Path $temDir | Out-Null
    }$htRedObjects.Keys | Where-Object {$htRedObjects[$_] -notin ("Host Script","Procedure","Template","Connection","Job","Parameter")}
  if ($objNames -ne $null) {
    # create cmds
    $temCmds$objCmds = @()
    $temNames$objNames | %{
      # buildcreate RedClioutput cmdsdirectory
      $temCmds +$objDir= 'template export --name "'+ $_ +'" -d "'+ $temDir +'" --file-name auto_name --force'  Join-Path $baseExportDir $htRedObjects[$_]
      if (-not (Test-Path $objDir)) {
     
   New-Item -ItemType Directory #-Path export$objDir metadata for object via metadata service
  | Out-Null
      }
      elseif (Test-Path (Join-Path  $uri = [URI]::EscapeUriString("$($redMetadataServiceUri)objectsExportByName/$_")
      $createResponse = Invoke-WebRequest -Uri $uri -UseBasicParsing -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders
$objDir "$_.ddl")) { # currently 'Redcli object export-ddl' doesn't support overwrite so remove the file first.
        $outFile = Remove-Item -path (Join-Path $temDir$objDir "$_.metadata"ddl") -force
      }
      # Convert JSON to JObject
      $jObject = [Newtonsoft.Json.Linq.JObject]::Parse($createResponse.Content)$objCmds += 'object export-ddl --name "'+ $_ +'" -d "'+ $objDir +'"'
       
      $prettyJson = $jObject.ToString([Newtonsoft.Json.Formatting]::Indented)# export metadata for object via metadata service
      $uri = [System.IO.FileURI]::WriteAllLines($outFile, $prettyJson, $Utf8NoBomEncoding)
 EscapeUriString("$($redMetadataServiceUri)objectsExportByName/$_")
   }
   $createResponse $batchRedCliCmds += $temCmdsInvoke-WebRequest -Uri $uri 
  }
 
  # Export DDL-UseBasicParsing -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders
  $objNames = $htRedObjects.Keys | Where-Object {$htRedObjects[$_] -notin ("Host Script","Procedure","Template","Connection")}
  if ($objNames -ne $null) {
$outFile = Join-Path $objDir "$_.metadata"
          # create cmds
# Convert JSON  $objCmds = @()to JObject
    $objNames | %{
      # create$jObject output directory= [Newtonsoft.Json.Linq.JObject]::Parse($createResponse.Content)
      $objDir$prettyJson = Join-Path $baseExportDir $htRedObjects[$_]$jObject.ToString([Newtonsoft.Json.Formatting]::Indented)
      if (-not (Test-Path $objDir)) {[System.IO.File]::WriteAllLines($outFile, $prettyJson, $Utf8NoBomEncoding)
    }
    New-Item -ItemType Directory -Path $objDir | Out-Null
      }
      elseif (Test-Path (Join-Path $objDir "$_.ddl")) { # currently 'Redcli object export-ddl' doesn't support overwrite so remove the file first.
        Remove-Item -path (Join-Path $objDir "$_.ddl") -force
      }$batchRedCliCmds += $objCmds
  }
 
  # Export Connection metadata
  $conNames = $htRedObjects.Keys | Where-Object {$htRedObjects[$_] -eq "Connection"}
  if ($conNames -ne $null) {
    $conNames | %{
      # create output directory
      $conDir= Join-Path $baseExportDir $htRedObjects[$_]
      if (-not (Test-Path $conDir)) {
      $objCmds += 'object export-ddl --name "'+ $_ +'" -d "'+ $objDir +'"' New-Item -ItemType Directory -Path $conDir | Out-Null
      }
       
      # export metadata for object via metadata service
            $uri = [URI]::EscapeUriString("$($redMetadataServiceUri)objectsExportByName/$_")
      $createResponse = Invoke-WebRequest -Uri $uri -UseBasicParsing -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders
      $outFile = Join-Path $objDir$conDir "$_.metadata"
            # Convert JSON to JObject
            $jObject = [Newtonsoft.Json.Linq.JObject]::Parse($createResponse.Content)
      $prettyJson = $jObject.ToString([Newtonsoft.Json.Formatting]::Indented)
      [System.IO.File]::WriteAllLines($outFile, $prettyJson, $Utf8NoBomEncoding)
    })
    $batchRedCliCmds += $objCmds}
  }
 
  # Export Connection metadataJobs
  $conNames$jobNames = $htRedObjects.Keys | Where-Object {$htRedObjects[$_] -eq "ConnectionJob"}
  if ($conNames$jobNames -ne $null) {
    $conNames | %{
      # create output directory
      $conDir$jobDir= Join-Path $baseExportDir $htRedObjects[$_]
  "Job"
    if (-not (Test-Path $conDir$jobDir)) {
      $null = New-Item -ItemType Directory -Path $conDir$jobDir | Out-Null
      }
    $jobNames | %{ 
      # export metadata for object via metadata service
            $uri = [URI]::EscapeUriString("$($redMetadataServiceUri)objectsExportByNamejobsExportByName/$_")
      $createResponse = Invoke-WebRequest -Uri $uri -UseBasicParsing -Method 'GET' -MaximumRedirection 0 -Headers $redMetadataServiceHeaders
      $outFile = Join-Path $conDir$jobDir "$_.metadata"
            # Convert JSON to JObject
            $jObject = [Newtonsoft.Json.Linq.JObject]::Parse($createResponse.Content)
      $prettyJson = $jObject.ToString([Newtonsoft.Json.Formatting]::Indented)
      [System.IO.File]::WriteAllLines($outFile, $prettyJson, $Utf8NoBomEncoding)       
    }
  }
  
  Write-Progress -Activity "RedCli batch operation in progress..." -Status "Running.."
  # add the built up commands array to the RedCli batch json hash-table
  $batchHt["Commands"] = $batchRedCliCmds
  $fileRedCliBatchJson = join-path "${ENV:WSL_WORKDIR}" "redCliBatchCmds_${ENV:WSL_SEQUENCE}.json" 
 
  # Export the RedCli batch json hash-table to a json file with utf8 no-bom
  [System.IO.File]::WriteAllLines($fileRedCliBatchJson, ($batchHt | ConvertTo-Json), $Utf8NoBomEncoding)
   
  # setup and run the RedCli batch script
  $commandArguments = @"
  batch execute -f "$fileRedCliBatchJson" --meta-con-string "${ENV:WSL_META_CONSTRING}"
"@
  $cmdReturn = Execute-Command 'RedCli' "${ENV:WSL_BINDIR}RedCli.exe" $commandArguments
  $cmdReturn.stdout | Out-File -FilePath $redCliLogFile -Append
  $cmdResultJsonLines = ($cmdReturn.stdout -split '\r\n|\n' | Select-String -Pattern '\{"MessageType":"Result","MessageBody":\{"Outcome":"Failure"').Line
  if ($cmdResultJsonLines.Length -ne $null -and $cmdResultJsonLines.Length -gt 0) {
    WriteAudit "There were $($cmdResultJsonLines.Length) RedCli Failures reported - please view the following log for details:" "E"
    WriteAudit "$redCliLogFile" "E"
  }
 
}
catch {
  Write-Error $_.InvocationInfo.PositionMessage
  Write-Error $_.Exception.Message
  $resultExitCode = 2
  $resultMsg = "Export Objects Failed" 
}
finally {
  try {
    # stop the metadata service
    $redMetadataServiceProcess.StopRedMds()
  }
  catch {}
}
 
# exit the script
Exit-Script $resultExitCode $resultMsg