由于某些奇怪的原因跳过了迭代

iteration being skipped over for some weird reason

我有以下代码...

Function PrintArrayAsGrid
{
    param([string[]]$Array,[ValidateRange(1,24)][int]$ColumnCount)

    $GridSplat = @{
        InputObject = $Array|ForEach-Object {
            New-Object psobject -Property @{'Value' = $_}
        }
        Property    = 'Value'
    }

    if(-not $PSBoundParameters.ContainsKey('ColumnCount'))
    {
        $GridSplat['AutoSize'] = $true
    }
    else
    {
        $GridSplat['Column'] = $ColumnCount
    }

    Format-Wide @GridSplat
}

Function UserInputAdSearchPropertyName
{
    $userInputNotYetValidated = $true
    $userInput = Read-Host "
    Enter AD property name you wish to search with (e.g.: employeeNumber)"

    $userInput = $userInput.Trim()
    Write-Host "you input $userInput"
    Write-Host ""

    [String[]]$validAdProperties = @('SamAccountName', 'msRTCSIP-UserEnabled', 'msRTCSIP-OptionFlags', 'msRTCSIP-PrimaryUserAddress', 'msRTCSIP-PrimaryHomeServer', 
    'mail', 'msExchMasterAccountSid', 'homeMDB', 'proxyaddresses', 'legacyExchangeDN', 
    'lastLogonTimestamp', 'logonCount', 'lastLogoff', 'lastLogon', 'pwdLastSet', 'userAccountControl', 'whenCreated', 'whenChanged', 'accountExpires', 
    'sn', 'givenName', 'displayName', 'distinguishedName', 'initials', 'l', 'st', 'street', 'title', 'description', 'postalCode', 'physicalDeliveryOfficeName', 'telephoneNumber', 'facsimileTelephoneNumber', 'info', 'memberOf', 'co', 'department', 'company', 'streetAddress', 'employeeNumber', 'employeeType', 'objectGUID', 'employeeID', 'homeDirectory', 'homeDrive', 'scriptPath', 'objectSid', 'userPrincipalName', 'url', 'msDS-SourceObjectDN', 'manager', 'extensionattribute8')

    while ($userInputNotYetValidated)
    {
        If ($validAdProperties -notcontains $userInput)
        {
            Write-Error "Invalid AD Property Name: $userInput"

            PrintArrayAsGrid $validAdProperties 4

            $userInput = Read-Host "    Enter one property name from list above to search with"
            Write-Host "you input $userInput"
            Write-Host ""
        } Else {
            $userInputNotYetValidated = $false
        }
    }
    Write-Output $userInput
}

# Ask user to enter property name in AD to search with
$searchAdPropertyName = UserInputAdSearchPropertyName

输出:

        Enter AD property name you wish to search with (e.g.: employeeNumber): asdf
you input asdf

UserInputAdSearchPropertyName : Invalid AD Property Name: asdf
At C:\Scripts\Tests\temp2.ps1:59 char:26
+     $searchAdPropertyName = UserInputAdSearchPropertyName
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,UserInputAdSearchPropertyName

        Enter one property name from list above to search with:

这里的问题是它没有打印属性列表并跳过使用 PrintArrayAsGrid $validAdProperties 4

调用函数的迭代

这是如果我添加以下行会发生什么...

            Write-Host 'Found'
            PrintArrayAsGrid $validAdProperties 4
            Write-Host 'Found'

输出:

            Enter AD property name you wish to search with (e.g.: employeeNumber): asdf
you input asdf

UserInputAdSearchPropertyName : Invalid AD Property Name: asdf
At C:\Scripts\Tests\temp2.ps1:60 char:26
+     $searchAdPropertyName = UserInputAdSearchPropertyName
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,UserInputAdSearchPropertyName

Found
Found
        Enter one property name from list above to search with:

现在,如果我按如下方式添加出口,我实际上会打印出 table...

            Write-Host 'Found'
            PrintArrayAsGrid $validAdProperties 4
            Write-Host 'Found'
            Exit

输出:

PS C:\Tests> .\test1.ps1

                Enter AD property name you wish to search with (e.g.: employeeNumber): asdf
you input asdf

UserInputAdSearchPropertyName : Invalid AD Property Name: asdf
At C:\Tests\test1.ps1:61 char:26
+     $searchAdPropertyName = UserInputAdSearchPropertyName
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,UserInputAdSearchPropertyName

Found
Found


SamAccountName                msRTCSIP-UserEnabled          msRTCSIP-OptionFlags          msRTCSIP-PrimaryUserAddress
msRTCSIP-PrimaryHomeServer    mail                          msExchMasterAccountSid        homeMDB
proxyaddresses                legacyExchangeDN              lastLogonTimestamp            logonCount
lastLogoff                    lastLogon                     pwdLastSet                    userAccountControl
whenCreated                   whenChanged                   accountExpires                sn
givenName                     displayName                   distinguishedName             initials
l                             st                            street                        title
description                   postalCode                    physicalDeliveryOfficeName    telephoneNumber
facsimileTelephoneNumber      info                          memberOf                      co
department                    company                       streetAddress                 employeeNumber
employeeType                  objectGUID                    employeeID                    homeDirectory
homeDrive                     scriptPath                    objectSid                     userPrincipalName
url                           msDS-SourceObjectDN           manager                       extensionattribute8


PS C:\Tests>

期望的输出:

PS C:\Tests> .\test1.ps1

                Enter AD property name you wish to search with (e.g.: employeeNumber): asdf
you input asdf

UserInputAdSearchPropertyName : Invalid AD Property Name: asdf
At C:\Tests\test1.ps1:61 char:26
+     $searchAdPropertyName = UserInputAdSearchPropertyName
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,UserInputAdSearchPropertyName


SamAccountName                msRTCSIP-UserEnabled          msRTCSIP-OptionFlags          msRTCSIP-PrimaryUserAddress
msRTCSIP-PrimaryHomeServer    mail                          msExchMasterAccountSid        homeMDB
proxyaddresses                legacyExchangeDN              lastLogonTimestamp            logonCount
lastLogoff                    lastLogon                     pwdLastSet                    userAccountControl
whenCreated                   whenChanged                   accountExpires                sn
givenName                     displayName                   distinguishedName             initials
l                             st                            street                        title
description                   postalCode                    physicalDeliveryOfficeName    telephoneNumber
facsimileTelephoneNumber      info                          memberOf                      co
department                    company                       streetAddress                 employeeNumber
employeeType                  objectGUID                    employeeID                    homeDirectory
homeDrive                     scriptPath                    objectSid                     userPrincipalName
url                           msDS-SourceObjectDN           manager                       extensionattribute8


        Enter one property name from list above to search with:

有人知道为什么会这样吗?

当您将一些文本显式写回主机 (Write-Host) 并且将其他文本作为函数输出返回时,就会发生这种情况。

当您通过直接调用该函数(而不是将输出分配给变量或管道传递给后续命令)来调用 returns 文本(例如)的命令或表达式时,将发送到 "output" 流,就像使用 Write-Outputreturn 时得到的一样。在您的情况下,格式化的属性列表包含在函数的输出中,而不是在您希望显示时准确写出。

如果您检查 $searchAdPropertyName 的值,您将看到它包括格式化的属性列表 在提示符下输入的一个属性名称。

由于 PrintArrayAsGrid 的输出是您从 Format-Wide cmdlet 得到的,它不是一个您可以像其他人一样写出来的常规字符串,这使得这有点棘手。我不会尝试在这个答案中解决这个问题,因为我的目标是回答 "why is this happening" 问题!

顺便说一句,当有人输入错误的属性名称时,您可能希望使用 Write-Warning 而不是 Write-Error;这将抑制你因完全成熟的错误而导致的一些混乱。

您尝试执行的另一种方法是弹出一个对话框,供用户 select 正确的属性。为此,您可以通过 Out-GridView cmdlet 传递有效属性数组并将结果分配给 $userInput 变量。下面的片段:

...
Write-Warning "Invalid AD Property Name: $userInput"

$userInput = $validAdProperties | Out-GridView -Passthru
...

如果您不介意属性列表出现在另一个 window 中,那么这至少可以确保当属性被 selected 时,它肯定是您有效列表中的内容!

另一种方法是将 $userInput 变量定义为参数并使用 ValidateSet 属性来确保用户只能输入正确的 AD 属性 名称。

function UserInputAdSearchPropertyName 
{
    param(
        [ValidateSet('SamAccountName', 'msRTCSIP-UserEnabled', 'msRTCSIP-OptionFlags', 'msRTCSIP-PrimaryUserAddress', 'msRTCSIP-PrimaryHomeServer', 
            'mail', 'msExchMasterAccountSid', 'homeMDB', 'proxyaddresses', 'legacyExchangeDN', 
            'lastLogonTimestamp', 'logonCount', 'lastLogoff', 'lastLogon', 'pwdLastSet', 'userAccountControl', 'whenCreated', 'whenChanged', 'accountExpires', 
            'sn', 'givenName', 'displayName', 'distinguishedName', 'initials', 'l', 'st', 'street', 'title', 'description', 'postalCode', 'physicalDeliveryOfficeName', 'telephoneNumber', 'facsimileTelephoneNumber', 'info', 'memberOf', 'co', 'department', 'company', 'streetAddress', 'employeeNumber', 'employeeType', 'objectGUID', 'employeeID', 'homeDirectory', 'homeDrive', 'scriptPath', 'objectSid', 'userPrincipalName', 'url', 'msDS-SourceObjectDN', 'manager', 'extensionattribute8'
            )]
        [string]$userInput
    )

    # rest of function here
}

这将允许用户使用制表符完成有效的输入字符串:

基本上,正如 Charlie Joynt 所提到的,Format-Wide 被写入一个单独的流,直到脚本即将退出,或者 returnWrite-Output 才会被转储打电话。

由于父函数有意使用 Write-Output,因此 Format-Wide 会卡在流线中,并为其赋值通过父函数传递的任何变量值(也是)。

首先要做的是不要让 Format-Wide 在流中输入任何内容。为此,我们将其分配给一个变量。在将其分配给变量时,我们希望该值保持字符串格式。完成后,我们只需将值写入主机即可。

要完成所有这些,我只需更改此行:

Format-Wide @GridSplat

为此:

$table = Format-Wide @GridSplat | Out-String
Write-Host $table