无法从有序字典中获取数据

Can't get data out of ordered dictionary

我正在尝试从我订购的字典中获取数据,但由于某种原因它没有打印其中的数据。我可以到达数据结构中的第一项,但我无法遍历所有行。我正在使用 PowerShell 5.1 和 visual studio 代码。

代码查询一个mdb文件,returns多行。

Function ProcessHelpMDB{
[cmdletbinding()]
  Param ([string]$mdbLookupError, [string]$mdbFilePath, [string]$mdbPrinterSeries) 
  Process
  {
   $adOpenStatic = 3
   $adLockOptimistic = 3
   $deviceTable = $mdbPrinterSeries + "PP"
   $mdbLookupError -Match '[0-9]*-([0-9]*)'
   $errLookup = $Matches[1]

    $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 = [ordered]@{}
        if($rs.EOF)
        {
            Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
        }#if
        else
        {  
            while($rs.EOF -ne $True)
            {

                $result = [ordered]@{}
                foreach ($field in $rs.Fields)
                {
                    $result[$field.name] = $field.Value
                }#result
                $newObject = [PSCustomObject]$result
                $ret.Add($i,$newObject) ###ordered dictionary needs key to add values
                $i++ 
                $rs.MoveNext()
            } #while
 
            Write-Host "retArr[] $($ret)" #prints retArr[] System.Collections.Specialized.OrderedDictionary
            Write-Host "retArr[0] $($ret[0,"TextID"])" #prints retArr[0]
            Write-Host "retArr[0] $($ret[0])" #prints retArr[0] @{PictureID=HELP_BLAH; TextID=HELP_INFO; HelpCode=9; ScreenNumber=1}
            foreach($row in $ret)
            {
                foreach($item in $row.value) #it's skipping these
                {
                    Write-Host $item #
                    Write-Host $item[0] #
                    Write-Host $item[0].'TextID' #
                    Write-Host $item.'TextID' #
                }#foreach
            }

            $cn.Close()
            return $ret
      } #end Process
    }# End of Function process mdb's

mdb 中的数据看起来像这样 table:

HelpCode   ScreenNumber    TextID                PictureID
1000           1           HELP_INFO             HELP_BLAH
1000           2           HELP_INFO2            HELP_BLAH2
...

我的问题是,如何从数据结构中打印出table中的数据?稍后我需要访问它以将其与其他数据重新组合成一个字符串。我的问题是我不知道如何访问每一行。在数据结构中,每行中的每个项目都是单独的。我似乎知道如何访问第一行,但不知道如何访问其他行。

我最近一直在看这个:looping over hash table

更新: 我得到 TextID 来打印 ret 的每一行,如下面的评论..谢谢!!:

foreach($row in $ret.GetEnumerator()) #this is working for each row, using 
{
    Write-Host $row.TextID #prints nothing
    Write-Host $row.'TextID' #prints nothing
    Write-Host $($row.TextID) #prints nothing
    Write-Host $($row.'TextID') #prints nothing
    Write-Host $($row[0].TextID) #prints nothing
    Write-Host $($row[0].'TextID') #prints nothing
    Write-Host $($row[0].Value.TextID) #prints TextID value of current row
    Write-Host $($row[0].Value.'TextID') #prints TextID value of current row
}

更新2: 我正在尝试改进以下答案中建议的数据结构。谢谢!!这是一个很好的简化。

$ret = [System.Collections.Generic.List[psobject]]::new() #different data struc
if($rs.EOF)
{
    Write-Host "$mdbLookupString not in $mdbFileName...record set returned emtpy for query"
}#if
else
{  
    while($rs.EOF -ne $True)
    {
        $result = [ordered]@{}
        foreach ($field in $rs.Fields)
        {
            $result[$field.name] = $field.Value
        }#result
        $newObject = [PSCustomObject]$result
        $ret.Add($newObject) ###
        $rs.MoveNext()
    } #while
}#else
Write-Host "retArr[] $($ret)" #prints retArr[] 
Write-Host "retArr[0] $($ret[0,"TextID"])" #prints retArr[0]
Write-Host "retArr[0] $($ret[0])" #prints retArr[0] @{PictureID=...; TextID=...; HelpCode=9; ScreenNumber=1}
$i=0
foreach($row in $ret) #goes thru all rows
{
    Write-Host "retArr[] $($ret)" #prints retArr[] 
    Write-Host "retArr[0] $($ret[$i,"TextID"])" #prints retArr[0] @{HelpCode=9; ScreenNumber=1; TextID=...; PictureID=...}
    Write-Host "retArr[0] $($ret[$i].TextID)" #prints retArr[0] HELP_...
    Write-Host "retArr[0] $($ret[$i].'TextID')" #retArr[0] HELP_...
    ####
    Write-Host "retArr[] $($row)" #prints retArr[] @{HelpCode=9; ScreenNumber=1; TextID=...; PictureID=HELP_...}
    Write-Host "retArr[0] $($row[$i,"TextID"])" #prints retArr[0]
    Write-Host "retArr[0] $($row[$i])" #prints retArr[0] @{HelpCode=9; ScreenNumber=1; TextID=HELP_...; PictureID=HELP_...}
    Write-Host "retArr[0] $($row[$i].TextID)" #prints retArr[0] HELP_...
    Write-Host "retArr[0] $($row[$i].'TextID')" #retArr[0] 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_...
    Write-Host $($row.TextID) #prints HELP_...
    Write-Host $($row.'TextID') #prints HELP_...
    Write-Host $($row[0].TextID) #HELP_...
    Write-Host $($row[0].'TextID') #HELP_...
    Write-Host $($row[0].Value.TextID) #prints nothing
    Write-Host $($row[0].Value.'TextID') #prints nothing
}

效果很好。感谢@mathias 的帮助!

更新3: 我正在尝试@iRon 评论中的管道想法,使用 update2(优化的数据结构):

$ret | ForEach-Object {
        Write-Host TextID= $($_.TextID) #prints TextID= HELP_...
        Write-Host TextID= $($_.'TextID') #prints TextID= HELP_...
        Write-Host TextID= $($_.Value.TextID) #prints TextID=
        Write-Host TextID= $($_.Value.'TextID') #prints TextID=
    }

谢谢艾伦!这是访问数据结构中数据的好方法。 :)

您可以通过显式调用 GetEnumerator() 并将生成的枚举器传递给 foreach 或 pipeline-enabled cmdlet 来遍历字典中的每个 key-value 条目:

foreach($kvp in $ret.GetEnumerator())
{
  Write-Host "Key: $($kvp.Key) - Value: $($kvp.Value)"
}

也就是说,只要您使用连续的整数作为键,您也可以使用 list 而不是字典:

# create a list instead of a dictionary
$ret = [System.Collections.Generic.List[psobject]]::new()

# ...
while($rs.EOF -ne $True)
{
    $result = [ordered]@{}
    foreach ($field in $rs.Fields)
    {
        $result[$field.name] = $field.Value
    }

    $newObject = [PSCustomObject]$result
    $ret.Add($newObject) # add object to list, no need to keep track of `$i` here.
    $rs.MoveNext()
} 

# ...

列表与数组一样可索引,因此您可以:

$ret[4] # this will get you the 5th row