0

I'm not sure what to search for to solve this one. I have a scope/persistence of data issue, where a variable used to populate my data structure is over-writing other items in the data structure (ImageFileName). This is my code:

###Functions...first two are just for info

#method to get messages for mdb files 
#dependency-Need to download accessDatabaseEngine(64 bit) redestributable: https://www.microsoft.com/en-us/download/details.aspx?id=54920
Function ProcessHelpMDB{
[cmdletbinding()]
  Param ([string]$mdbLookupError, [string]$mdbFilePath, [string]$mdbDeviceSeries) #$mdbLookupError = error number, like 701. $mdbDeviceSeries is 1000
  Process
  {

    #Write-Host "mdbLookupString: $mdbLookupString" -ForegroundColor Cyan
    $adOpenStatic = 3
    $adLockOptimistic = 3
    #Write-Host "In ProcessMDB" -ForegroundColor darkRed
    #$pathViewBase = 'C:\me\EndToEnd_view\' #View dir. Maybe param later

    #$pathToMdb = Join-Path -Path $pathViewBase -ChildPath $mdbFileName

    $deviceTable = $mdbDeviceSeries + "PP"
    $mdbLookupError -Match '[0-9]*-([0-9]*)'
    $errLookup = $Matches[1]

    #Write-Host "dps" -ForegroundColor DarkMagenta

    $selectQuery = “SELECT [$($deviceTable)].[HelpCode],
    [$($deviceTable)].[ScreenNumber],
    [$($deviceTable)].[TextID],
    [$($deviceTable)].[PictureID]
        FROM [$($deviceTable)]
        WHERE 
            [$($deviceTable)].[HelpCode] = $($errLookup)"


    $cn = new-object -comobject ADODB.Connection
    $rs = new-object -comobject ADODB.Recordset

    $cn.Open("Provider = Microsoft.ACE.OLEDB.16.0;Data Source = $mdbFilePath") 
    $rs.Open($selectQuery,
        $cn, $adOpenStatic, $adLockOptimistic)

    $i=0
    $ret = [System.Collections.Generic.List[psobject]]::new() 

    if($rs.EOF)
    {
        Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
    }#if
    else
    {  
        while($rs.EOF -ne $True)
        {
            $result = [ordered]@{}
            #$hash = @{}
            foreach ($field in $rs.Fields)
            {
                $result[$field.name] = $field.Value
            }#result
            $newObject = [PSCustomObject]$result
            $ret.Add($newObject) #
            $rs.MoveNext()
        } #while
    }#else
    Write-Host "retArr[0] $($ret[0])" #prints retArr[0] @{PictureID=HELP_...; TextID=HELP_...; HelpCode=9; ScreenNumber=1}
    $i=0
    foreach($row in $ret) #goes thru all rows
    {
        Write-Host "retArr[0] $($ret[$i,"TextID"])" #prints retArr[0] @{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_...}
        ####
        Write-Host "retArr[] $($row)" #prints retArr[] @{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_7000_POWER_COVER_RIBBON}
        Write-Host "retArr[0] $($row[$i])" #prints retArr[0] @{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_...}
        $i++
    }

    foreach($row in $ret.GetEnumerator()) #this is working for each row
    {
        Write-Host $row.TextID #prints HELP_...
        Write-Host $row.'TextID' #prints HELP_...
    }

    $ret | ForEach-Object {
        Write-Host TextID= $($_.TextID) #prints TextID= HELP_...
        Write-Host TextID= $($_.'TextID') #prints TextID= HELP_...
    } #
       
    $cn.Close()
    return $ret #Items queried from db ################################################# need to put them in excel file in order next
  } #end Process
}# End of Function process mdb's

    
#This function gets mdb info out and returns English-US message found
Function ProcessK_MDB{
    [cmdletbinding()]
      Param ([string]$mdbLookupstring) #$mdbLookupString like HELP_...
      Process
      {
        $adOpenStatic = 3
        $adLockOptimistic = 3

        $pathViewBase = 'C:\me\\EndToEnd_view\' #View dir. Maybe param later
        $mdbFileNamePath = 'KAppText.mdb'
    
        $pathToMdb = Join-Path -Path $pathViewBase -ChildPath $mdbFileNamePath

        if(Test-Path $pathToMdb)
        {
            $selectQuery = “SELECT [Messages].[Message Description],
            [Messages].[English - Us]
                FROM [Messages]
                WHERE [Messages].[Message Description] = '$($mdbLookupString)'”
   
            $cn = new-object -comobject ADODB.Connection
            $rs = new-object -comobject ADODB.Recordset
            $cn.Open("Provider = Microsoft.ACE.OLEDB.16.0;Data Source = $pathToMdb")
           
            $rs.Open($selectQuery,
                $cn, $adOpenStatic, $adLockOptimistic)
        
            if($rs.EOF) #empty
            {
                Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
                $ret = ""
            }#if
            else #got results
            {  
                $returnArr = $rs.GetRows()
                #$ret = $returnArr[0,1]
                #$ret2 = $returnArr[1,1]
                $ret = $returnArr[1,0] #has long text
                #$ret4 = $returnArr[0,0] #has short text
                #Write-Host $ret

            }#else got results    
            
            $cn.Close()
        } #testPath
        else {
            Write-Host "$pathToMdb does not exist"
        }
        return $ret #Message English-US for parameter/Message Description given
      } #end Process
    }# End of Function process mdb's

Function Get-ImageName{
    [cmdletbinding()]
      Param ([string]$imageName, [string]$fileNamePath) 
      Process
      {
        #find image file name to look for
        [System.String] $pictureName = ""
        if($imageName -Match "HELP")
        {
            #remove "HELP" part of file name
            $($row.PictureID) -Match "HELP_(.*)" #get the part after HELP_
            Write-Host $Matches[0]
            Write-Host $Matches[1]
            $pictureName = $Matches[1]
        }
        else {
            $pictureName = $imageName
        }

        $imageFile2 = Get-ChildItem -Recurse -Path $ImageFullBasePath -Include @("*.bmp","*.jpg","*.png") | Where-Object {$_.Name -match "$($pictureName)"}  #$imageFile | Select-String -Pattern '$($pictureName)' -AllMatches
        Write-Host "ImageFile2: $($imageFile2)"
        $imgFile = ""
        foreach($imgFile in $imageFile2) #there may be more than one...just get last one...there are multiple telephone images
        {
            if($imgFile.Exists) #if($imageFile2.Exists)
            {
                #$image = [System.Drawing.Image]::FromFile($imgFile) #may not need this step
                #need to figure out which is correct if there's multiple images
                return $imgFile
            }
            else {
                Write-Host "$($imgFile) does not exist"
                return $null
            }
        } #foreach imageFile2
        return $null
      } #end Process
    }# End of Function process mdb's

###main####

          $resultHelp = ProcessHelpMDB -mdbLookupError $errCode -mdbFilePath $basePathFull -mdbDeviceSeries $deviceVer #######
          $result = foreach($row in $resultHelp.GetEnumerator()) #this is working for each row
          {
              if($row -ne $True) #not sure why it adds true at the top
              {
                Write-Host $row.TextID #prints HELP_...
                #lookup value from kapptext.mdb
                Write-Host $($row.TextID) #prints nothing but looks ok in next function
                $longText = ProcessK_MDB -mdbLookupstring $($row.TextID) #gives English-US message from device for parameter given
                #insert images######################
                #I can see that these are assigned correctly and returned from Function:
                [System.Drawing.Image] $image = New-Object System.Drawing.Image  #error...see Update2
                [System.String] $imageNamePath = New-Object System.String  #error...see Update2
                [System.String] $imageNamePath = Get-ImageName -imageName $($row.PictureID) -fileNamePath $ImageFullBasePath
                if($null -ne $imageNamePath)
                {
                    $image = Get-Image -imageFileName $imageNamePath
                }
                else 
                {
                    Write-Host "Did not find an image file for $($row.PictureID) in $ImageFullBasePath"
                }
                #get the data ready to put in spreadsheet
                 New-Object psobject -Property $([ordered]@{
                    ScreenNumber = $($row.ScreenNumber)
                    KPMKey = $($row.TextID)
                    EnglishUS = $($longText)
                    PictureID = $($row.PictureID)
                    ImageFound = ""
                    ImageFileName = $($imageNamePath) ###???this is over-written...all same in $result after done with loop
                })
              } #if not true
          } #foreach row $resultHelp

##note: $image gets inserted in the spreadsheet later, but since the names aren't showing correctly when use $results, I'm not sharing that part.

I can see after this runs for the 9 rows, that each ImageFileName is the same in $result. How do I do this so it maintains what is returned from the method? Right now I am trying New-Object, but it didn't fix the issue.

This is what $resultHelp looks like:

[0] $true (I'm not sure why it puts true at the top) [1] @(HelpCode=9;ScreenNumber=1;TextID=HELP_...JA;PictureID=HELP_...RIB) [2] @(HelpCode=9;ScreenNumber=2;TextID=HELP_...ROLL;PictureID=HELP_...ROLL) [3] @(HelpCode=9;ScreenNumber=3;TextID=HELP_...EDGE;PictureID=HELP_...UT) ...

I am using Powershell 5.1 and VSCode.

Update:

I checked again, and in Get-ImageName, it's returning a file name like "Contact_Service"...bmp and it looks like it's getting put in the psObject ImageFileName...($imageNamePath), and the same thing for the other images found. When I look in the end, $result has all the same values for that ImageFileName. and the one that used to say "Contact_Service"..bmp is something else now, matching the other ones in $result.

Update2:

There are a couple errors:

New-Object : A constructor was not found. Cannot find an appropriate constructor for type System.Drawing.Image

and

New-Object : A constructor was not found. Cannot find an appropriate constructor for type System.String.

for where I tried dealing with the object over-write issue in the main code

Update3:

After I get the psobject in good shape, I put it in a spreadsheet with Export-Excel. I just wanted to give this info so you know why I'm putting it in the psobject like that:

$xlsx = $result | Export-Excel -Path $outFilePath -WorksheetName $errCode -Autosize -AutoFilter -FreezeTopRow -BoldTopRow  -PassThru # -ClearSheet can't ClearSheet every time or it clears previous data  
  
Michele
  • 3,617
  • 12
  • 47
  • 81
  • 3
    There are too many things we need to guess here, what is `Get-ImageName` ? Why is `$image = ` being assigned but never used ? What is `$resultHelp` and why are you using `.GetEnumerator()` ? Is it a hashtable ? If so, what does `$row -ne $True` mean ? – Santiago Squarzon Jan 28 '22 at 18:34
  • I will add more info – Michele Jan 28 '22 at 18:59
  • @SantiagoSquarzon - see 2 methods added, and Update. Thanks for the help! :) – Michele Jan 28 '22 at 19:26
  • 3
    the `true` is coming from something [your code is REALLY difficult to read] that is outputting a boolean to the success stream. i can't figure out where that is happening ... but you are getting an array with `true` and your new object. – Lee_Dailey Jan 28 '22 at 19:32
  • @Lee_Dailey I get rid of the $true when I'm looping thru the data, so it's not a bit deal. I'm more concerned with the over-written ImageFileName. – Michele Jan 28 '22 at 19:35
  • 1
    @Michele - you will likely need to use the trace commands or the debugger to track whatever is modifying the $Var. my 1st suspicion is that the $Var is getting passed by reference instead of by value ... but i still can't follow your code well enuf to track that $Var. [*blush*] – Lee_Dailey Jan 28 '22 at 20:08
  • @Lee_Dailey thanks. I am using the debugger, that's how I know it's getting overwritten somehow. I don't know enough about powershell objects to figure it out though. – Michele Jan 28 '22 at 20:10
  • It looks like this to me. I'm trying to figure it out. https://stackoverflow.com/questions/70664741/powershell-object-properties-get-overwritten-when-new-objects-added-to-an-array – Michele Jan 28 '22 at 20:16
  • 2
    The `$true` comes from this statement in `ProcessHelpMDB`: `$mdbLookupError -Match '[0-9]*-([0-9]*)'`. You have a similar problem with `Get-ImageName`: `$($row.PictureID) -Match "HELP_(.*)" #get the part after HELP_` – Mathias R. Jessen Jan 28 '22 at 20:17
  • @MathiasR.Jessen and mclayton, when I look at $ret returned from ProcessHelpMDB, it doesn't have the $true preceding the query results. but when I look at $resultsHelp in my main code, it does have the $true at the list. I'm not sure how to remove that. But, the overwritten ImageFileName is most important and holding up the works. – Michele Jan 28 '22 at 20:28
  • 2
    @michele - “I get rid of the $true when I'm looping thru the data,”… if you’ve got unexpected behaviour (or a bug) it’s better (imho) to tackle it head on rather than fudge it - you’re just kicking the pain further down the road otherwise, and who knows what other unexpected behaviour is lurking as well… – mclayton Jan 28 '22 at 20:28
  • 1
    @michele - comment out the line mathias r Jessel referred to - it contributes nothing to the logic of the function but does generate noise in the return value. – mclayton Jan 28 '22 at 20:31
  • @mclayton if I remove the match for $mdbLookupError, it will not return anything from the query. It would look for 12-9 instead of 9. That would create a bigger problem. Sorry, and thanks for the help. – Michele Jan 28 '22 at 20:34
  • 1
    @Michele don't _remove_ it - simply suppress the _output_ from it: `$mdbLookupError -Match '[0-9]*-([0-9]*)' |Out-Null` – Mathias R. Jessen Jan 28 '22 at 20:50
  • 1
    It's still very unclear why you think the `ImageFileName` property is getting overwritten. What's the actual output from your code? – Mathias R. Jessen Jan 28 '22 at 20:51

1 Answers1

1

I figured it out.

the problem was that even though I was finding different $imageNamePaths for to assign to the Property as ImageFileName for each PictureID, and assigning those properties in the psobject in the foreach loop, I wound up with the same thing for each ImageFileName property (overwritten). This fixed it.

New-Object psobject -Property $([ordered]@{
   ScreenNumber = $($row.ScreenNumber)
   KPMKey = $($row.TextID)
   EnglishUS = $($longText)
   PictureID = $($row.PictureID)
   ImageFound = ""
   ImageFileName = "$($imageNamePath)"    ####added double quotes
})

The double quotes let the different $imageNamePath values remain instead of being over-written. I'm not exactly sure why.

And thank you @Mathias, I will suppress output from my -Match to see if the $true is removed at the top of my data returned from the Function. :)

Michele
  • 3,617
  • 12
  • 47
  • 81