【问题标题】:PowerShell 'if' conditionPowerShell“如果”条件
【发布时间】:2017-08-11 14:35:16
【问题描述】:

这是一个快速的小 PowerShell blurp,它应该获取设备的 IP 地址、服务标签和设备上任何活动 MAC 地址的 MAC 地址(活动意味着存在连接)。

无论如何,如果我不使用if 语句,这将完美运行,但如果我这样做,它只会执行第一行:

Test-Connection $computername -count 1 | select @{Name="Computername";Expression={$_.Address}},Ipv4Address

如果设备处于开启状态...并且设备的最后一行处于关闭状态。

Write-Host "Device is offline"

这是我的小 PowerShell '脚本':

$computername = Read-Host 'Enter Computer Name'
$online = Test-Connection -Computername $computername -BufferSize 16 -Count 1 -Quiet
IF ($online -eq "True") {
    Test-Connection $computername -count 1 | select @{Name="Computername";Expression={$_.Address}},Ipv4Address
    Get-WmiObject win32_SystemEnclosure -computername $computername | select serialnumber
    Get-wmiobject -class "Win32_NetworkAdapterConfiguration" -computername $computername |Where{$_.IpEnabled -Match "True"}
} Else {
    Write-Host "Device is offline"
}

为什么会这样?我可能做错了什么?

【问题讨论】:

  • 注意:使用$true 而不是"True";第一个是布尔值;第二个字符串。
  • 如果我理解了您的问题,您是说当计算机在线时,您看不到序列号或网络适配器信息;对吗?
  • 如果是这样,可能存在针对远程计算机运行这些 WMI 查询的权限问题?如果你自己运行这些语句会发生什么?另外,您的$ErrorActionPreference 设置为什么(即可能设置为SilentlyContinue,这样就不会显示异常)?
  • @JasonSnell 不,我不这么认为...@{Name="Computername"... 只需将“地址”一词更改为“计算机名”,如该行其余部分所述
  • If 声明是有道理的;我在问如果没有该声明来理解问题,它是如何工作的;即if 语句是否导致问题,或者它是否无关(这似乎更有可能)/只是调用get-wmiobject 的代码没有产生任何输出;很可能是因为我们没有看到一些错误。

标签: powershell if-statement


【解决方案1】:

PowerShell 中的布尔变量是$true$falseIf 应该是:

if ($online -eq $true) {

或者

if($online)

【讨论】:

  • 在 Powershell 中 $true -eq "true" 也是有效的。无论出于何种原因,字符串 true 或 false 都可以与 bool 进行比较。
  • "True" 是一个truthy 值(stackoverflow.com/a/38831795/361842),但"false" 也是真实的(例如运行:$true -eq "false" ),所以最好始终使用定义的值/be运行此类检查时要小心。
  • 是的。奇怪的是,“假”也是真的。
  • @JasonSnell;因为“假”这个词只对我们人类有意义;从 PowerShell 比较的角度来看,它将 this 转换为布尔值以执行比较,并且根据定义将非零长度字符串转换为 true。 "false" -eq $true 给出 false,因为它将 $true 转换为字符串 "true",因此 "false" -eq "true" 的计算结果为 false。为避免此类混淆,请在进行比较时始终使用正确的类型。
【解决方案2】:

试试这个:

$computername = Read-Host 'Enter Computer Name'
$online = Test-Connection -Computername $computername -BufferSize 16 -Count 1 -Quiet
IF ($online -eq $true) {

    Write-Host "Device is online"
    Test-Connection $computername -count 1 | select @{Name="Computername";Expression={$_.Address}},Ipv4Address

    try {
        [PSObject[]]$systemEnclosures = Get-WmiObject win32_SystemEnclosure -computername $computername -ErrorAction Stop
        Write-Host "Found $($systemEnclosures.Count) System Enclosures"
        $systemEnclosures | select serialnumber
        [PSObject[]]$NetworkAdapterConfiguration = Get-wmiobject -class "Win32_NetworkAdapterConfiguration" -computername $computername -ErrorAction Stop
        Write-Host "Found $($NetworkAdapterConfiguration.Count) Network Adapter Configurations"
        $NetworkAdapterConfiguration = $NetworkAdapterConfiguration | Where{$_.IpEnabled}
        Write-Host "Found $($NetworkAdapterConfiguration.Count) IP Enabled Network Adapter Configurations"
        $NetworkAdapterConfiguration
    } catch {
        Write-Host "An Error Occurred"
        Write-Host $_.ToString() #show exception info
    }
} Else {
    Write-Host "Device is offline"
}

注意:我并不是建议您将此代码保留在最终脚本中;只需使用它来了解幕后发生的事情。

每厘米;使用$true 而不是"true",好像两者都是真实的,使用错误的类型会导致对语言的错误理解/一些非常奇怪的错误,你发现像if($true -eq "false") {write-output "Well, this is unusual"} 这样的行会导致一些奇怪行为。

此外,您可能希望考虑将 Write-Host 替换为 Write-Output 以获取任何逻辑返回值,或将 Write-Verbose/Write-Debug 替换为任何信息/调查输出;然后使用适当的开关/首选项调用代码......但这与您的问题无关。 Write-Host Considered Harmful 了解更多信息。


更新

每个 cmets,您看到的问题是一个 错误 陷阱:https://github.com/PowerShell/PowerShell/issues/4552

如果这段代码输出的数据只是在控制台中显示,你可以通过显式调用Format-Table命令来避免这个问题:

$computername = Read-Host 'Enter Computer Name'
IF (Test-Connection -Computername $computername -BufferSize 16 -Count 1 -Quiet) {
    Test-Connection $computername -count 1 | select @{Name="Computername";Expression={$_.Address}}, 'Ipv4Address' | Format-Table
    Get-WmiObject win32_SystemEnclosure -computername $computername | select serialnumber | Format-Table
    Get-wmiobject -class "Win32_NetworkAdapterConfiguration" -computername $computername | Where{$_.IpEnabled} | Format-Table
} Else {
    Write-Host "Device is offline"
}

如果您需要输出到管道以供其他地方使用,一切都很好(即没有format-table 块);对象被正确写入管道;问题很简单,当涉及到一起显示所有结果时,第一个对象导致 PowerShell 创建列 ComputerNameIpv4Address,并且 PowerShell 随后尝试显示以下对象的这些属性,尽管那些没有这样的对象特性。也就是说,可以通过将不同的对象类型放入自定义对象的不同属性中以便于参考来改进这一点。例如,

$computername = Read-Host 'Enter Computer Name'
If (Test-Connection -Computername $computername -BufferSize 16 -Count 1 -Quiet) {
    (new-object -TypeName PSObject -Property @{
        ConnectionTest = Test-Connection $computername -count 1 | select @{Name="Computername";Expression={$_.Address}}, 'Ipv4Address'
        SystemEnclosures = Get-WmiObject win32_SystemEnclosure -computername $computername | select serialnumber
        NetworkAdapterConfigs = Get-wmiobject -class "Win32_NetworkAdapterConfiguration" -computername $computername | Where{$_.IpEnabled}
    })
} Else {
    Write-Host "Device is offline"
}

【讨论】:

  • 这对你有用吗?你有服务标签和 Mac 地址吗?
  • @LukeZeimet;本来我没试过。我现在添加了类型定义以确保当返回 1 个对象时,这些对象仍然是数组,所以仍然有一个 Count 属性:例如[PSObject[]]$systemEnclosures.
  • John:我很抱歉一开始就让我们走错了路:我想你所描述的行为实际上是按设计的,正如我已经解释过的@987654323 @。 @PetSerAl 的回答中解释的隐式Format-Table 的异步行为也可能是个问题,但与这个问题无关。
  • 不用担心,谢谢@mklement0。将继续在 GitHub 上进行讨论,就好像我同意您的 cmets 一样,我认为这种行为确实存在一些问题(例如,粗心的人会遇到问题)。
  • @mklement0 好点;修改(左 bug 带有删除线以保留一些历史背景)
【解决方案3】:

Test-Connection -Quiet 返回布尔值,而不是字符串。如果你想明确一点,试试if ($online)if ($online -eq $true)

https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Management/Test-Connection?view=powershell-5.1

【讨论】:

    猜你喜欢
    • 2018-08-24
    • 2021-11-08
    • 2017-07-21
    • 1970-01-01
    • 1970-01-01
    • 2012-05-31
    • 2018-07-20
    • 1970-01-01
    • 2021-09-24
    相关资源
    最近更新 更多