由于某些奇怪的原因跳过了迭代
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-Output
或 return
时得到的一样。在您的情况下,格式化的属性列表包含在函数的输出中,而不是在您希望显示时准确写出。
如果您检查 $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 被写入一个单独的流,直到脚本即将退出,或者 return
或 Write-Output
才会被转储打电话。
由于父函数有意使用 Write-Output
,因此 Format-Wide
会卡在流线中,并为其赋值通过父函数传递的任何变量值(也是)。
首先要做的是不要让 Format-Wide 在流中输入任何内容。为此,我们将其分配给一个变量。在将其分配给变量时,我们希望该值保持字符串格式。完成后,我们只需将值写入主机即可。
要完成所有这些,我只需更改此行:
Format-Wide @GridSplat
为此:
$table = Format-Wide @GridSplat | Out-String
Write-Host $table
我有以下代码...
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-Output
或 return
时得到的一样。在您的情况下,格式化的属性列表包含在函数的输出中,而不是在您希望显示时准确写出。
如果您检查 $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 被写入一个单独的流,直到脚本即将退出,或者 return
或 Write-Output
才会被转储打电话。
由于父函数有意使用 Write-Output
,因此 Format-Wide
会卡在流线中,并为其赋值通过父函数传递的任何变量值(也是)。
首先要做的是不要让 Format-Wide 在流中输入任何内容。为此,我们将其分配给一个变量。在将其分配给变量时,我们希望该值保持字符串格式。完成后,我们只需将值写入主机即可。
要完成所有这些,我只需更改此行:
Format-Wide @GridSplat
为此:
$table = Format-Wide @GridSplat | Out-String
Write-Host $table