SteveC
SteveC

Reputation: 16743

How can you test if an object has a specific property?

How can you test if an object has a specific property?

Appreciate I can do ...

$members = Get-Member -InputObject $myobject 

and then foreach through the $members, but is there a function to test if the object has a specific property?

Additional Info: The issue is I'm importing two different sorts of CSV file, one with two columns, the other with three. I couldn't get the check to work with "Property", only with "NoteProperty" ... whatever the difference is

if ( ($member.MemberType -eq "NoteProperty" ) -and ($member.Name -eq $propertyName) ) 

Upvotes: 150

Views: 199376

Answers (18)

Paul
Paul

Reputation: 5861

You can use Get-Member

if (Get-Member -inputobject $var -name "Property" -Membertype Properties) {
    #Property exists
}

Upvotes: 115

Dave F
Dave F

Reputation: 1985

There are a number of solutions to this question that work in strict mode, but some are better than others.

Solutions that do not appear to iterate through every property are the fastest solutions.

  1. Bernie White's solution and
  2. esskar's solution (modified)

Solutions that look as though they iterate through every property are slower.

  1. sebke CCU's solution and
  2. dan-gph's solution

The solution that appears to iterate through every property and uses a regular expression is a little slower than the previous two solutions (because compiling and executing the regular expression takes more time)

  1. CB.'s solution

The solution that uses GetMethod appears to iterate through every property, but its use of GetMethod makes it significantly slower.

  1. Paul's GetMethod solution

The following script was used to compare the previously mentioned solutions in strict mode:

# Tested in PowerShell core 7.2.0

Set-StrictMode -Version Latest

$propertyExistsMethods = New-Object System.Collections.Generic.Dictionary'[string,scriptblock]'

# Fastest
$propertyExistsMethods.Add(
 "PSObject.Properties (Bernie White's solution)",
{
  Param( [PSObject] $Object, [string] $Property )
  [bool]$Object.PSObject.Properties[$Property]
})
$propertyExistsMethods.Add(
 "PSObject.Properties.Item (esskar's solution (modified))",
{
  Param( [PSObject] $Object, [string] $Property )
  [bool]$Object.PSObject.Properties.Item($property)
})

# Not as fast
$propertyExistsMethods.Add(
 "Contains (sebke CCU's solution)",
{
  Param( [PSObject] $Object, [string] $Property )
  $Object.PSobject.Properties.Name.Contains($Property)
})
$propertyExistsMethods.Add(
 "-in (dan-gph's solution)",
{
  Param( [PSObject] $Object, [string] $Property )
  $Property -in $Object.PSobject.Properties.Name
})

# Slower than the previously mentioned solutions
$propertyExistsMethods.Add(
 "-match (CB.'s solution)",
{
  Param( [PSObject] $Object, [string] $Property )
  [bool]($Object.PSobject.Properties.name -match $Property)
})

# Slowest
$propertyExistsMethods.Add(
 "GetMember (Paul's solution)",
{
  Param( [PSObject] $Object, [string] $Property )
  Get-Member -inputobject $Object -name $Property -Membertype Properties
})

foreach ($method in $propertyExistsMethods.Keys) {
  $propertyExists = $propertyExistsMethods[$method]

  $o = @{}
  foreach ($i in 1..100000) {
    $o[$i] = "p$i"
  }

  Write-Host $method
  $measure = Measure-Command {
    foreach ($i in 1..100000) {
      # Always check for a property that does NOT exist
      & $propertyExists -Object $o -Property 'p'
    }
  }
  Write-Host $measure | % { $_.Milliseconds }
  Write-Host ''
}

The output is as follows:

PSObject.Properties (Bernie White's solution)
00:00:03.1437587

PSObject.Properties.Item (esskar's solution)
00:00:03.5833642

Contains (sebke CCU's solution)
00:00:04.4812702

-in (dan-gph's solution)
00:00:04.6507811

-match (CB.'s solution)
00:00:05.1107066

GetMember (Paul's solution)
00:00:14.5305115

Upvotes: 17

Shaun Luttin
Shaun Luttin

Reputation: 141492

Just check against null.

($myObject.MyProperty -ne $null)

If you have not set PowerShell to StrictMode, this works even if the property does not exist:

$obj = New-Object PSObject;                                                   
Add-Member -InputObject $obj -MemberType NoteProperty -Name Foo -Value "Bar";
$obj.Foo; # Bar                                                                  
($obj.MyProperty -ne $null);  # False, no exception

Upvotes: 7

esskar
esskar

Reputation: 10940

I find this method more strict and faster when checking multiple properties

$null -ne $myobject.PSObject.Properties.Item("myPropertyNameToTest")

Upvotes: 3

Jon Grey
Jon Grey

Reputation: 11

for me this work

Set-StrictMode -Version Latest
$TMP = ...

$HAS_SERVERS=($TMP | Select-Object Servers)
if (-not $HAS_SERVERS.Servers){
    echo "No servers. Abort."
} else {
    ...
}
 

Upvotes: 0

Bernie White
Bernie White

Reputation: 5075

Try this for a one liner that is strict safe.

[bool]$myobject.PSObject.Properties[$propertyName]

For example:

Set-StrictMode -Version latest;
$propertyName = 'Property1';
$myobject = [PSCustomObject]@{ Property0 = 'Value0' };

if ([bool]$myobject.PSObject.Properties[$propertyName]) {
    $value = $myobject.$propertyName;
}

Upvotes: 12

sebke CCU
sebke CCU

Reputation: 183

For me MyProperty" -in $MyObject.PSobject.Properties.Name didn't work, however

$MyObject.PSobject.Properties.Name.Contains("MyProperty")

works

Upvotes: 13

corky
corky

Reputation: 185

For identifying which of the objects in an array have a property

$HasProperty = $ArrayOfObjects | Where-Object {$_.MyProperty}

Upvotes: -1

Tom Stryhn
Tom Stryhn

Reputation: 1

You could check with:

($Member.PropertyNames -contains "Name") this will check for the Named property

Upvotes: -1

Steve Pritchard
Steve Pritchard

Reputation: 257

I recently switch to set strict-mode -version 2.0 and my null tests failed.

I added a function:

#use in strict mode to validate property exists before using
function exists {
  param($obj,$prop)
  try {
    if ($null -ne $obj[$prop]) {return $true}
    return $false
  } catch {
    return $false
  }
  return $false
}

Now I code

if (exists $run main) { ...

rather than

if ($run.main -ne $null) { ...

and we are on our way. Seems to work on objects and hashtables

As an unintended benefit it is less typing.

Upvotes: 0

user2864740
user2864740

Reputation: 61875

I've been using the following which returns the property value, as it would be accessed via $thing.$prop, if the "property" would be to exist and not throw a random exception. If the property "doesn't exist" (or has a null value) then $null is returned: this approach functions in/is useful for strict mode, because, well, Gonna Catch 'em All.

I find this approach useful because it allows PS Custom Objects, normal .NET objects, PS HashTables, and .NET collections like Dictionary to be treated as "duck-typed equivalent", which I find is a fairly good fit for PowerShell.

Of course, this does not meet the strict definition of "has a property".. which this question may be explicitly limited to. If accepting the larger definition of "property" assumed here, the method can be trivially modified to return a boolean.

Function Get-PropOrNull {
    param($thing, [string]$prop)
    Try {
        $thing.$prop
    } Catch {
    }
}

Examples:

Get-PropOrNull (Get-Date) "Date"                   # => Monday, February 05, 2018 12:00:00 AM
Get-PropOrNull (Get-Date) "flub"                   # => $null
Get-PropOrNull (@{x="HashTable"}) "x"              # => "HashTable"
Get-PropOrNull ([PSCustomObject]@{x="Custom"}) "x" # => "Custom"
$oldDict = New-Object "System.Collections.HashTable"
$oldDict["x"] = "OldDict"
Get-PropOrNull $d "x"                              # => "OldDict"

And, this behavior might not [always] be desired.. ie. it's not possible to distinguish between x.Count and x["Count"].

Upvotes: 5

dan-gph
dan-gph

Reputation: 16909

This is succinct and readable:

"MyProperty" -in $MyObject.PSobject.Properties.Name

We can put it in a function:

function HasProperty($object, $propertyName)
{
    $propertyName -in $object.PSobject.Properties.Name
}

Upvotes: 35

hshib
hshib

Reputation: 1750

I just started using PowerShell with PowerShell Core 6.0 (beta) and following simply works:

if ($members.NoteProperty) {
   # NoteProperty exist
}

or

if (-not $members.NoteProperty) {
   # NoteProperty does not exist
}

Upvotes: -1

If you are using StrictMode and the psobject might be empty, it will give you an error.

For all purposes this will do:

    if (($json.PSobject.Properties | Foreach {$_.Name}) -contains $variable)

Upvotes: 3

John Mello
John Mello

Reputation: 31

Just to clarify given the following object

$Object

With the following properties

type        : message
user        : [email protected]
text        : 
ts          : 11/21/2016 8:59:30 PM

The following are true

$Object.text -eq $NULL
$Object.NotPresent -eq $NULL

-not $Object.text
-not $Object.NotPresent

So the earlier answers that explicitly check for the property by name is the most correct way to verify that that property is not present.

Upvotes: 1

SteveC
SteveC

Reputation: 16743

I ended up with the following function ...

function HasNoteProperty(
    [object]$testObject,
    [string]$propertyName
)
{
    $members = Get-Member -InputObject $testObject 
    if ($members -ne $null -and $members.count -gt 0) 
    { 
        foreach($member in $members) 
        { 
            if ( ($member.MemberType -eq "NoteProperty" )  -and `
                 ($member.Name       -eq $propertyName) ) 
            { 
                return $true 
            } 
        } 
        return $false 
    } 
    else 
    { 
        return $false; 
    }
}

Upvotes: 0

CB.
CB.

Reputation: 60908

Like this?

 [bool]($myObject.PSobject.Properties.name -match "myPropertyNameToTest")

Upvotes: 142

YtramX
YtramX

Reputation: 180

Real similar to a javascript check:

foreach($member in $members)
{
    if($member.PropertyName)
    {
        Write $member.PropertyName
    }
    else
    {
        Write "Nope!"
    }
}

Upvotes: 2

Related Questions