Объект сравнения, возвращающий неверные результаты - PullRequest
1 голос
/ 23 апреля 2020

Первая публикация в stackoverflow, поэтому заранее прошу прощения, если я пропустил социальную норму.

У меня есть массив в PowerShell, в котором содержатся тысячи объектов. Стандартный материал, в котором каждый объект имеет такие свойства, как имя пользователя, время входа в систему, компьютер, на котором они зарегистрированы, и т. Д. c. Затем я отделил небольшое количество объектов из первого массива от пользователей, чье имя начинается с A:

$Array2 = $Array1 | where-object Username -like '*\a*'

Это работает, как и ожидалось.

Я хочу создать третий массив, который только содержит объекты из $ Array1, которых нет в $ Array2. Или, другими словами, массив только с пользователями, чьи имена не начинаются с A. Это похоже на go:

$Array3 = compare-object $Array1 $Array2 | select-object -expandproperty InputObject

Ожидание:

$Array3 | where-object Username -like '*\a*'

приводит к ничего не вернулось

Я получаю много результатов. Странно, если я смотрю на .count каждого массива, математика работает. Array1 минус Array2 равно Array3. Таким образом, он удаляет правильное количество объектов, но не ожидаемые объекты. Что я здесь не так делаю? Так как я делаю выборку из точного массива, с которым сравниваю, я не могу придумать никаких других критериев, поиск которых привел бы к неожиданному совпадению. Я также пытался отсортировать каждый массив по одному и тому же свойству перед сравнением, потому что я захватывал, но, как и ожидалось, это не исправило.

Заранее спасибо!

Ответы [ 5 ]

2 голосов
/ 23 апреля 2020

Сравнить объект работает забавным образом. С объектами вам обычно нужно указывать свойства. Я удивлен, что в документах нет такого примера. К сожалению, -property не принимает групповые символы. Я думаю, что без «-property», если нет специального метода compareto () или equals (), он будет сравнивать строковые версии объектов. Я думаю, что с выводом get-aduser, он будет сравнивать строки (отличительные имена).

$a = @([pscustomobject]@{name='joe'})              
$b = @([pscustomobject]@{name='joey'})

compare-object $a $b  # no output, they're equal!


compare-object $a $b -property name

name SideIndicator
---- -------------
joey =>
joe  <=

Испытание даты и времени. Для сравнения он использует что-то кроме строк.

$a = get-date; sleep -Milli 500; $b = get-date
$a.tostring(); $b.tostring()
4/23/2020 6:33:56 PM
4/23/2020 6:33:56 PM

$a -eq $b
False

compare-object $a $b

InputObject          SideIndicator
-----------          -------------
4/23/2020 6:33:56 PM =>
4/23/2020 6:33:56 PM <=
2 голосов
/ 23 апреля 2020

Вы можете решить эту проблему, отрицая операнд Where-Object (-notlike вместо -like):

$Array2 = $Array1 |Where-Object Username -like *\a*
$Array3 = $Array1 |Where-Object Username -notlike *\a*

... или вы можете воспользоваться преимуществами метода расширения .Where() Режим «Сплит», и сделать это в одном назначении:

$Array2,$Array3 = $Array1.Where({$_.Username -like '*\a*'}, 'Split')
2 голосов
/ 23 апреля 2020

Простой способ - выполнить то же назначение -like, но с противоположным оператором -notlike, например:

$Array2 = $Array1 | where-object Username -like 'a*'
$Array3 = $Array1 | where-object Username -notlike 'a*'

Примечание:

(не уверен, что это опечатка) в вопросе к совпадению: '*\a*'), совпадение должно быть a* с единственной звездочкой после символа "a". Вы хотите сопоставить все , начиная с , с "a" и "*" для чего-либо после (например, совпадение только с "Алекс", а не с "Брэдом").

0 голосов
/ 25 апреля 2020

Мой вывод состоит в том, что некоторые командлеты создают массивы таким образом, что это нарушает объект сравнения. Я до сих пор не уверен, что это за таинственный «путь», но проблема возникает при использовании Getrix-сессии Citrix, а не при использовании Get-AdUser.

Длинный ответ Для тех, кто действительно хочет использовать сравнение -объект вот как я заставил его работать:

compare-object $Array1 $Array2 -Property Username -PassThru

С -PassThru для меня моментом эврики.

Мой вопрос был конкретно о том, как / почему объект сравнения не работает так, как я ожидал. Все ответы, по моей интерпретации, только предоставили различные способы обойти проблему и фактически не отвечали на вопрос. Особая благодарность @ js2010 за продолжение работы со мной через него.

0 голосов
/ 23 апреля 2020

Я думаю, Compare-Object внутренне использует метод ToString() для сравнения объектов.

class foo {
    [string]$str

    foo($str) {
        $this.str = $str
    }
}

class bar {
    [string]$str

    bar($str) {
        $this.str = $str
    }

    [string] ToString() { return $this.str }
}

"== Compare foo object =="
$fooA = [foo]::new("a")
$fooB = [foo]::new("b")
compare $fooA $fooB -IncludeEqual | ft

"== Compare bar object =="
$barA = [bar]::new("a")
$barB = [bar]::new("b")
compare $barA $barB -IncludeEqual | ft

вывод:

== Compare foo object ==

InputObject SideIndicator
----------- -------------
foo         ==           


== Compare bar object ==

InputObject SideIndicator
----------- -------------
b           =>           
a           <=  
...