0

Iam trying to write a script to notify if a VMware VM Custom attribute has a value or if the value is null. I need the VM name and the Output Value (either Null or Not Null). Here is what I have but doesn't return the accurate information

$vms = Get-VM

foreach ($vm in $vms) {

    $tag = $vm | Get-Annotation -CustomAttribute "Backup"
   
    if ($tag.value -eq '$null'){
        Write-Output "$vm Attribute doesnt have a value"
    }
    else {
        Write-Output "$vm Attribute has a value assigned"
    }
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
Omar
  • 25
  • 2
  • 6

3 Answers3

2

Unless you're specifically looking for the literal string value '$null', you probably want to change the comparison to $null -eq $tag.value

You could create a new object with 2 properties:

$vms = Get-VM

foreach ($vm in $vms) {

    $tag = $vm | Get-Annotation -CustomAttribute "Backup"
   
    if ($null -eq $tag.value){
        $result = "$vm Attribute doesnt have a value"
    }
    else {
        $result = Write-Output "$vm Attribute has a value assigned"
    }

    # output object with Name + result
    [pscustomobject]@{
        Name = $vm.Name
        Result = $result
    }
}

Another, perhaps more PowerShell-idiomatic approach would be to create a similar object with the Select-Object cmdlet:

Get-VM |Select-Object Name,@{Name='HasBackupAttribute';Expression={ $null -eq ($_ | Get-Annotation -CustomAttribute "Backup").Value }}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • Thanks Mathias but this does not work. The output is lisiting every vm with "Attribute has a value assigned " At least half of them do not have a value assigned – Omar Mar 09 '21 at 02:22
0

When looking at dealing with $null comparisons, see this SO Q&A:
In PowerShell, why is $null -lt 0 = $true? Is that reliable?

I do not have VMware at the moment, but in my small Hyper-V lab, running the following delivers the shown results:

Try
{
    (
        Get-VM | 
        Where-Object -Property FloppyDrive -eq $null | 
        Select Name, FloppyDrive -ErrorAction SilentlyContinue
    ).Count
}
Catch { Write-Warning -Message 'No no records returned'}
# Results
<#
4
#>

Try
{
    (
        Get-VM | 
        Where-Object -Property FloppyDrive -ne $null | 
        Select Name, FloppyDrive -ErrorAction SilentlyContinue
    ).Count
}
Catch { Write-Warning -Message 'No no records returned'}
# Results
<#
WARNING: No no records returned
#>

The results are the same using these as well.

Try
{
    (
        Get-VM | 
        Where-Object -Property FloppyDrive -Match $null | 
        Select Name, FloppyDrive -ErrorAction SilentlyContinue
    ).Count
}
Catch { Write-Warning -Message 'No no records returned'}

Try
{
    (
        Get-VM | 
        Where-Object -Property FloppyDrive -NotMatch $null | 
        Select Name, FloppyDrive -ErrorAction SilentlyContinue
    ).Count
}
Catch { Write-Warning -Message 'No no records returned'}

In your use case, try this refactor:

(Get-VM).Name | 
foreach {
    if ((Get-VM -Entity $PSitem | Get-Annotation -CustomAttribute 'Backup') -eq $null)
    { "$PSItem - Attribute doesnt have a value"    }
    else {"$PSItem - Attribute has a value assigned"}
}

Or...

    (Get-VM).Name | 
foreach {
    if ((Get-VM -Entity $PSitem | Get-Annotation -CustomAttribute 'Backup') -Match $null)
    { "$PSItem - Attribute doesnt have a value"    }
    else {"$PSItem - Attribute has a value assigned"}
}
postanote
  • 15,138
  • 2
  • 14
  • 25
  • Hii, I've tried running but they both throw the following exception Get-VM : A parameter cannot be found that matches parameter name 'Entity'. At line:3 char:24 + if ((Get-VM -Entity <<<< $PSitem | Get-Annotation -CustomAttribute 'Backup') -eq $null) + CategoryInfo : InvalidArgument: (:) [Get-VM], ParameterBindingException + FullyQualifiedErrorId : NamedParameterNotFound,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVM – Omar Mar 09 '21 at 09:19
  • Remove the `-Entity`. Again I don't have VMware as part of my lab, so, I went to the VMWare docs, for the command. https://vdc-repo.vmware.com/vmwb-repository/dcr-public/6bd6daa3-08a8-4660-9159-23265b9d6c00/4d533cf0-f009-4fa0-8679-8d505fbe846b/doc/Get-Annotation.html – postanote Mar 09 '21 at 20:35
0

Annotation values are strings. When there is no value present, the string is considered empty rather than null. So the $null -eq value test will not yield the desired results. You can simply perform an implicit boolean conversion of the value to determine if it is empty.

$vms = Get-VM
foreach ($vm in $vms) {

    $tag = $vm | Get-Annotation -CustomAttribute "Backup"
    # Empty string returns false. Nonempty string returns true.
    if ($tag.value){
        Write-Output "$vm Attribute has a value assigned"
    }
    else {
        Write-Output "$vm Attribute doesn't have a value"
    }
}

You will discover that $tag.value | Get-Member returns a type System.String. So when value seemingly has no value, it actually is an empty string. You can perform a variety of tests to determine if the value is empty. An empty string value inside of an if statement evaluates to False. See below for some examples, which can all be used inside of if statements.

$Empty = [pscustomobject]@{value = ''}
$NotEmpty = [pscustomobject]@{value = 'My String'}

# Test 1 Using IsNullOrEmpty static method
[string]::IsNullOrEmpty($Empty.value)
True
[string]::IsNullOrEmpty($NotEmpty.value)
False

# Test 2 Using [bool] type accelerator
[bool]$Empty.value
False
[bool]$NotEmpty.value
True

# Test 3 Using length property. Empty string has length of 0.
$Empty.value.length -eq 0
True
$NotEmpty.value.length -eq 0
False

# Test 4 Using if statement. ! in front of an expression negates its boolean value
if ($Empty.value) { "Value is not empty" } else { "Value is empty" }
Value is empty
if ($NotEmpty.value) { "Value is not empty" } else { "Value is empty" }
Value is not empty
if (!$Empty.value) { "Value is empty" }
Value is empty
AdminOfThings
  • 23,946
  • 4
  • 17
  • 27