Powershell — если оператор выводит 2 значения

Я пытаюсь написать сценарий, чтобы уведомить, имеет ли пользовательский атрибут VMware VM значение или значение равно null. Мне нужно имя виртуальной машины и выходное значение (либо Null, либо Not Null). Вот что у меня есть, но не возвращает точную информацию

$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"
    }
}

person Omar    schedule 09.03.2021    source источник


Ответы (3)


Если вы специально не ищете буквальное строковое значение '$null', вы, вероятно, захотите изменить сравнение на $null -eq $tag.value

Вы можете создать новый объект с двумя свойствами:

$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
    }
}

Другой, возможно, более идиоматический подход PowerShell — создать аналогичный объект с помощью командлета Select-Object:

Get-VM |Select-Object Name,@{Name='HasBackupAttribute';Expression={ $null -eq ($_ | Get-Annotation -CustomAttribute "Backup").Value }}
person Mathias R. Jessen    schedule 09.03.2021
comment
Спасибо, Матиас, но это не работает. Вывод показывает, что каждая виртуальная машина с атрибутом имеет назначенное значение. По крайней мере, половина из них не имеет назначенного значения. - person Omar; 09.03.2021

При рассмотрении работы со сравнениями $null см. этот SO Q&A:
Почему в PowerShell $null -lt 0 = $true? Это надежно?

В данный момент у меня нет VMware, но в моей небольшой лаборатории Hyper-V выполнение следующего дает показанные результаты:

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
#>

Результаты такие же, используя их.

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'}

В вашем случае использования попробуйте этот рефакторинг:

(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"}
}
person postanote    schedule 09.03.2021
comment
Привет, я пытался запустить, но они оба выдают следующее исключение Get-VM : Не удается найти параметр, соответствующий имени параметра «Сущность». В строке: 3 символа: 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 - person Omar; 09.03.2021
comment
Удалите -Entity. Опять же, у меня нет VMware в моей лаборатории, поэтому я обратился к документации VMWare за командой. vdc-repo.vmware.com/vmwb-repository/dcr-public/ - person postanote; 09.03.2021

Значения аннотаций являются строками. Когда значение отсутствует, строка считается пустой, а не нулевой. Таким образом, тест $null -eq value не даст желаемых результатов. Вы можете просто выполнить неявное логическое преобразование значения, чтобы определить, пусто ли оно.

$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"
    }
}

Вы обнаружите, что $tag.value | Get-Member возвращает тип System.String. Таким образом, когда value, казалось бы, не имеет значения, на самом деле это пустая строка. Вы можете выполнить различные тесты, чтобы определить, является ли значение пустым. Пустое строковое значение внутри оператора if оценивается как False. Ниже приведены некоторые примеры, которые можно использовать внутри операторов if.

$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
person AdminOfThings    schedule 09.03.2021