Search code examples
powershellepplus

Powershell: Property stored in a variable


I would like to find all cells in a range based on a property value using EPPlus. Let's say I need to find all cells with bold text in an existing spreadsheet. I need to create a function that will accept a configurable properties parameter but I'm having trouble using a property stored in a variable:

$cellobject = $ws.cells[1,1,10,10]
$properties = 'Style.Font.Bold'

$cellobject.$properties
$cellobject.{$properties}
$cellobject.($properties)
$cellobject."$properties"

None of these work and cause a call depth overflow.

If this way wont work, is there something in the library I can use?

Edited: To show the final solution I updated the function with concepts provided by HanShotFirst...

function Get-CellObject($ExcelSheet,[string]$PropertyString,[regex]$Value){

    #First you have to get the last row with text, 
    #solution for that is not provided here...
    $Row = Get-LastUsedRow -ExcelSheet $ExcelSheet -Dimension $true

    while($Row -gt 0){
        $range = $ExcelSheet.Cells[$Row, 1, $Row, $ExcelSheet.Dimension.End.Column]

        foreach($cellObject in $range){

            if($PropertyString -like '*.*'){
                $PropertyArr = $PropertyString.Split('.')
                $thisObject = $cellObject

                foreach($Property in $PropertyArr){
                    $thisObject = $thisObject.$Property

                    if($thisObject -match $Value){
                        $cellObject
                    }
                }
            }
            else{
                if($cellObject.$PropertyString -match $Value){
                    $cellObject
                }
            }
        }
        $Row--
    }
}
#The ExcelSheet parameter takes a worksheet object
Get-CellObject -ExcelSheet $ws -Property 'Style.Font.Bold' -Value 'True'

Solution

  • Dot walking into properties does not really work with a string. You need to separate the layers of properties. Here is an example for an object with three layers of properties.

    # create object
    $props = @{
        first = @{
            second = @{
                third = 'test'
            }
        }
    }
    $obj = New-Object -TypeName psobject -Property $props
    
    # outputs "test"
    $obj.first.second.third
    
    # does not work
    $obj.'first.second.third'
    
    # outputs "test"
    $a = 'first'
    $b = 'second'
    $c = 'third'
    $obj.$a.$b.$c
    

    In your example this would be something like this:

    $cellobject = $ws.cells[1,1,10,10]
    $p1 = 'Style'
    $p2 = 'Font'
    $p3 = 'Bold'
    
    $cellobject.$p1.$p2.$p3
    

    Or you can do it a bit dynamic. This should produce the same result:

    $cellobject = $ws.cells[1,1,10,10]    
    $props = 'Style.Font.Bold'.Split('.')
    $result = $cellobject
    foreach ($prop in $props) {
        $result = $result.$prop
    }
    $result
    

    And since its Friday, here is a function for it :)

    function GetValue {
        param (
            [psobject]$InputObject,
            [string]$PropertyString
        )
    
        if ($PropertyString -like '*.*') {
            $props = $PropertyString.Split('.')
            $result = $InputObject
            foreach ($prop in $props) {
                $result = $result.$prop
            }
        } else {
            $result = $InputObject.$PropertyString
        }
    
        $result
    }
    
    # then call the function
    GetValue -InputObject $cellobject -PropertyString 'Style.Font.Bold'