Boolean NoteProperty становится массивом

В заголовке говорится, что все одно логическое значение становится массивом при назначении NoteProperty с помощью Add-Member или использования splatting.

PS Версия: 5.0.1xx

У меня есть то, что я считаю странной. Я создаю объект PSObject с одним из членов NoteProperty в качестве логического. Функция просматривает список, вызывает функцию для выполнения оценки, создает объект и затем добавляет его в массив. Кажется, это происходит только с первым созданным объектом, но я не тестировал это с 5 или более создаваемыми объектами.

Я подтвердил, что функции действительно возвращают bool и что переменная, присваиваемая свойству, является bool.

Мое обходное решение кажется надежным, но мне любопытно, почему это происходит.

Вот часть кода:

$clientCertsRequired = Get-Is-Client-Cert-Required -configFile $configFile -siteName $siteName

$httpsStatus = "Https is not enabled"
$clientCertStatus = "Client certs are not required"

if ($httpsEnabled -eq $true) {
    $httpsStatus = "Https is enabled"
}

if ($clientCertsRequired -eq $true){
    $clientCertStatus = "Client certs are required"
} 

$sc = New-Object PSObject -Property @{
    SiteName = $siteName;
    ConfigFilePath = $path;
    HttpsEnabled = $httpsStatus;
    ClientCertStatus =$clientCertStatus; 
    ClientCertRequired = $clientCertsRequired;
}

# clean up of some inexplicable problem where assignment to property 
# produces array with actual value in the last element.
if ($sc.ClientCertRequired.GetType().Name -eq "Object[]"){
    $sc.ClientCertRequired = $sc.ClientCertRequired[-1]
}

$si += $sc

Function Get-Is-Client-Cert-Required{
param(
    [xml]$configFile, 
    [string]$siteName
)
$functionName = $MyInvocation.MyCommand.Name  

$clientCertRequired = $false
try{
    # then read locations section (this will often not have any pages 
    $locationPath = "//configuration/location[@path='$siteName']"
    [system.xml.xmlelement]$location = $configFile.DocumentElement.SelectSingleNode($locationPath)

    if($location -ne $null){
        [system.xml.xmlelement]$accessNode = $location.SelectSingleNode("system.webServer/security/access")
        [system.xml.xmlelement]$authenticationNode = $location.SelectSingleNode("system.webServer/security/authentication")
        [system.xml.xmlelement]$clientCertMappingNode
        [system.xml.xmlelement]$iisClientCertMappingNode

        [int]$sslFlagMask = 0
        if($accessNode -ne $null){
            $sslFlags =  $accessNode.Attributes.GetNamedItem("sslFlags")
            # $sslFlags = $accessNode.Attributes["sslFlags"].Value
            if($sslFlagMask -ne $null){
                $sslFlagMask = Convert-Ssl-Flag-String-To-Int-Flag -sslFlag $sslFlags.Value
            }
        }

        if($authenticationNode -ne $null){
            [system.xml.xmlelement]$clientCertMappingNode = $authenticationNode.SelectSingleNode("clientCertificateMappingAuthentication[@enabled='true']")
            [system.xml.xmlelement]$iisClientCertMappingNode = $authenticationNode.SelectSingleNode("iisClientCertificateMappingAuthentication[@enabled='true']")
        }

        $clientCertAccepted = ($sslFlagMask -band $certAccepted) -eq $certAccepted
        $clientCertRequired = Check-IIS-Express-SSL-Config $sslFlagMask

        if($clientCertRequired -eq $false){
            if($clientCertAccepted -and ($clientCertMappingNode -ne $null -or $iisClientCertMappingNode -ne $null)){
                $clientCertRequired = $true
            }
        }
    }
}catch{
    $exceptionMessage = Get-Formatted-Exception-String -exceptionObject $_
    $message = "$functionName - Exception`: $exceptionMessage"
    Add-Exception -exception $message
    Log-Error -message $message 
}

$clientCertRequired

}


person kgjac    schedule 08.01.2017    source источник
comment
Вы можете показать нам определение Get-Is-Client-Cert-Required? Скорее всего, вызов какого-либо метода в этой функции выдает значение   -  person Mathias R. Jessen    schedule 09.01.2017
comment
@MatthewWetmore [bool]$var = Get-Stuff - опасный обходной путь - массив count ›1 всегда будет приводить к $true, даже если предполагаемое значение было $false   -  person Mathias R. Jessen    schedule 09.01.2017
comment
Вы знаете, это, вероятно, объясняет проблему, которая у меня возникла некоторое время назад. :) Лучшее предложение? Есть элементы, которые мне нравятся в PowerShell, и те, от которых выпадают мои и без того редкие волосы.   -  person Matthew Wetmore    schedule 09.01.2017
comment
Напишите тесты Pester для ваших функций, убедитесь, что они не выбрасывают бесполезный мусор :-)   -  person Mathias R. Jessen    schedule 09.01.2017
comment
@ MathiasR.Jessen, да, вот оно что. :) Тем не менее, я просто попробовал, и, похоже, получилось то, что я ожидал. функция foo {1; 2} [bool] $ r = foo - и я получаю ошибки преобразования, как я и ожидал.   -  person Matthew Wetmore    schedule 09.01.2017
comment
@MatthewWetmore да, мне плохо. Означает приведение неоднозначного выражения, например $r = [bool](foo), которое всегда будет $ true, если foo вернет ›1 элемент.   -  person Mathias R. Jessen    schedule 09.01.2017
comment
Спасибо за помощь. Я добавил к исходному вопросу функцию Get-Is-Client-Cert-Required.   -  person kgjac    schedule 09.01.2017
comment
Виноват. Мой первоначальный комментарий полностью обратный. Я ожидал логического значения, а функция возвращает логическое значение при назначении NoteProperty, которое преобразуется в массив. Ага!   -  person kgjac    schedule 09.01.2017
comment
Ничего очевидного - вы проверили, что Check-IIS-Express-SSL-Config $sslFlagMask возвращает ровно один [bool]   -  person Mathias R. Jessen    schedule 09.01.2017
comment
Также не пытайтесь объявлять переменные типа [System.Xml.XmlElement]$clientCertMappingNode - это один из самых безопасных способов попасть в вашу ситуацию.   -  person Mathias R. Jessen    schedule 09.01.2017
comment
Спасибо за совет! Да, я использую ISE. Я проверяю переменную $ clientCertsRequired до и после назначения, и она отображается как логическое значение с $ true или $ false. Я не вижу, что случилось. Вроде баг в PS, но в это сложно поверить.   -  person kgjac    schedule 09.01.2017
comment
Я возьму все объявления из функции Check-IIS-Express-SSL-Config и посмотрю, решит ли это проблему. Я думаю, что сейчас проблема заключается в том, что я не инициализирую эти две переменные, да! [system.xml.xmlelement] $ clientCertMappingNode [system.xml.xmlelement] $ iisClientCertMappingNode   -  person kgjac    schedule 09.01.2017
comment
@ MathiasR.Jessen, ваш комментарий об отказе от «объявления» объектов решил мою проблему. Если вы хотите добавить это в качестве ответа, я приму его   -  person kgjac    schedule 09.01.2017
comment
Думаю, теперь мы все на одной волне.   -  person Matthew Wetmore    schedule 09.01.2017


Ответы (1)


В теле функции Get-Is-Client-Cert-Required вы делаете:

[system.xml.xmlelement]$clientCertMappingNode
[system.xml.xmlelement]$iisClientCertMappingNode

Этот шаблон:

[type]$nonExistingVariable

Это ужасная идея в PowerShell - в отличие от C #, PowerShell не имеет концепции простых объявлений переменных, и приведенный выше шаблон просто приводит $null к указанному типу, генерируя новый экземпляр указанного типа в случае успеха - вероятно, это вызывает функция для вывода массива.


Если вам действительно нужно привязать переменную к определенному типу, приведите ее к назначению:

[type]$Variable = Get-Stuff

Дополнительный совет: идиоматическое соглашение PowerShell об именах для функций и командлетов - Noun-Verb, только с одним дефисом. Более подходящим названием для функции было бы:

Test-ClientCertRequirement
person Mathias R. Jessen    schedule 09.01.2017