我知道您可以在 ForEach 循环中嵌套 IfElse 语句,但反之亦然吗?

I know you can nest an IfElse statement in a ForEach loop, but is the opposite also possible?

提问人:Alyxander VanHelsing 提问时间:5/16/2023 最后编辑:mklement0Alyxander VanHelsing 更新时间:5/16/2023 访问量:63

问:

多年来一直断断续续地使用 Powershell,但直到现在还没有真正进入那么多的自动化领域。我试图完成的是运行一个基于变量输入的语句。每个语句都会自行运行良好。测试的 ELSE 部分将在变量的输入下正常运行。然而。。。问题出在尝试基于变量的默认输入运行第一条语句时。这用于根据计算机名称验证用户的代理设置。我想使用相同的脚本来搜索/输出单台机器或从列表中搜索/输出,具体取决于收到的输入。

我已经尝试了我能想到的一切,以及我在互联网上能找到的一切。我怀疑我错过了一些简单的东西。当我在没有 ErrorAction 的情况下运行整个过程时,如果我在提示符中输入一个值,它将毫无问题地运行 ELSE 语句。然而。。。如果我接受默认值(我在那里放了什么并不重要,并且尝试了值的多次迭代),它只是直接跳到 ELSE 语句并出错,因为没有输入(没有要搜索的计算机名称)。

以下是编写的代码:

$ErrorActionPreference = "SilentlyContinue"

$pathHKU = 'HKU:\.Default\Environment\'
$pathExists = Test-Path -Path $pathHKU

If(!($pathExists))
{ 
New-PSDrive -PSProvider Registry -Name HKU -Root HKEY_Users
}

$defaultValue = ""

$preSID = "Get-ItemPropertyValue 'registry::HKU\"
$postSID = "\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -Name ProxyServer"
$promptOutput = Read-Host "Press enter to search by list or type in the name of a single machine [$($defaultValue)]"
IF($null -eq $promptOutput) {
    $sysName | Add-Content -Path ".\testlist.txt"
ForEach ($sys in $sysName)
    {
        $SID = Invoke-Command -ComputerName $sys -ScriptBlock {Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Username | ForEach-Object { ([System.Security.Principal.NTAccount]$_).Translate([System.Security.Principal.SecurityIdentifier]).Value}}
        $searchProxy = $preSID+$SID+$postSID
        $scriptBlock = [Scriptblock]::Create($searchProxy)
            ForEach ($script in $scriptBlock) {
                $userProxy = Invoke-Command -ComputerName $sys -ScriptBlock $scriptBlock
            }
        $sys+" - "+$userProxy | Out-File -Path ".\TestProxySettings.csv" -Append
    }
}else{
    $nameComp = $promptOutput
    $SID = Invoke-Command -ComputerName $nameComp -ScriptBlock {Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Username | ForEach-Object { ([System.Security.Principal.NTAccount]$_).Translate([System.Security.Principal.SecurityIdentifier]).Value}}
    $searchProxy = $preSID+$SID+$postSID
    $scriptBlock = [Scriptblock]::Create($searchProxy)
        ForEach ($script in $scriptBlock) {
            $userProxy = Invoke-Command -ComputerName $nameComp -ScriptBlock $scriptBlock
$nameComp+" - "+$userProxy
        }
}

任何帮助将不胜感激。谢谢。

字符串 PowerShell null is-empty

评论

1赞 Mathias R. Jessen 5/16/2023
一旦您输入任何内容(包括仅按 [ENTER] 而不写入任何字符),将返回一个字符串,并将计算为 false(空字符串与 不同)。如果您尝试捕获字符串,请执行Read-Host$null -eq $promptOutput$nullif([string]::IsNullOrEmpty($promptOutput)) { ... }
0赞 Alyxander VanHelsing 5/16/2023
这解决了它,谢谢。我还将我的 .txt 文件作为添加内容,并且必须将其更改为 Get-Content 并删除管道才能正确读取,但现在脚本运行良好。

答:

3赞 mklement0 5/16/2023 #1

给定包含 Read-Host 调用的输出:$promptOutput

if ($null -eq $promptOutput) { ... }

never ,因为当用户只需按 Enter 键时,Read-Host 将返回空字符串,而不是 $null$true

因此,请使用:

if ('' -eq $promptOutput) { ... }

或者,假设空字符串隐式位于布尔上下文(如条件)中,则可以使用:$falseif

  • if (-not $promptOutput) { ... }
    如果您还想将空白(全空格)输出视为与空输入相同的内容:
  • if (-not $promptOutput.Trim()) { ... }

如果值的类型事先不知道,实际上可能是或不同的类型,只需将值括起来,首先将其强制转换为字符串:$null"..."

  • if (-not "$unknownValue") { ... }匹配或空字符串(相当于$null[string]::IsNullOrEmpty())
  • if (-not "$unknownValue".Trim()) { ... }匹配 ,空字符串或空白(全空格)字符串(相当于 )。$null[string]::IsNullOrWhiteSpace()

请注意,PowerShell 的设计通常不会将$null存储在 [string] 类型的变量中:即使显式分配它也会存储(空字符串):$null''

# Despite assigning $null, it is '' (empty string) that is stored.
[string] $str = $null; $null -eq $str # !! $false 

虽然有一种使用单例存储实际 的变通方法,但最好避免使用它,但除了它的设计目的:将 true 传递给类型化的 .NET 方法参数$null[NullString]::Value$null[string]