Powershell:否定 -like 和 -match 条件的意外行为

Powershell: unexpected behavior of negated -like and -match conditionals

我的 windows 文件夹中有 2 个文件夹,software 和 softwaretest。 所以我有主文件夹 "software" if 语句,然后跳转到 elseif - 这里我有备份文件夹,所以跳转到 else...

我的问题是我正在从 elseif 获取写入主机,并且我有一个备份文件夹,我正在调用 softwaretest,所以不明白为什么它给我那个输出而不是其他的。

希望有人可以 guide/help 我 :-)

    If ($SoftwarePathBackup = Get-ChildItem -Path "$Env:SystemRoot" | Where-Object { (!$_.Name -like 'software') }) {
        Write-Host ( 'There are no folder named \software\ on this machine - You cant clean/clear/empty the folder!' ) -ForegroundColor Red;
    } elseif ($SoftwarePathBackup = Get-ChildItem -Path "$Env:SystemRoot" | Where-Object { ($_.Name -match '.+software$|^software.+') } | Sort-Object) {
        Write-Host ( 'There are none folder-backups of \software\ on this machine - You need to make a folder-backup of \software\ before you can clean/clear/empty the folder!' ) -ForegroundColor Red;
    } else {
        Remove-Item
    }

我觉得在右边甚至在 RegEx 中都有否定非常令人困惑。我认为在开始时用 !-not 否定会更明显。

要测试,如果文件夹存在,您可以使用Test-PathTest-Path 还有一个 -Filter 参数,您可以使用它来代替 Where-Object。但我认为你甚至不必过滤。

$SoftwarePath = "$($Env:SystemRoot)\Software", "$($Env:SystemRoot)\SoftwareBackup"

foreach ($Path in $SoftwarePath) {
    if (Test-Path -Path $Path) {
        Remove-Item -Path $Path -Force -Verbose
    }
    else {
        Write-Output "$Path not found."
    }
}   

这对你有用吗?

您的主要问题运算符优先级之一:

  • !$_.Name -like 'software' 应该是 ! ($_.Name -like 'software') 或者,最好是
    $_.Name -notlike 'software' - 使用 PowerShell 的 not 前缀运算符进行取反。

  • 同样,您可能想否定 $_.Name -match '.+software$|^software.+',这是最容易实现的 $_.Name -notmatch '.+software$|^software.+'

Get-Help about_Operator_Precedence所述,!(a.k.a。-not)的优先级高于-like,因此 !$_.Name -like 'software' 被评估为 (!$_.Name) -like 'software',这意味着 !$_.Name 的结果 - 布尔值 - 与通配符进行(字符串)比较模式 'software'总是 returns $False,因此永远不会进入 If 分支。


就是说,您可以完全不用 -like-match 并使用 Get-Item-Include 参数支持的隐式通配符匹配(代码段需要 PSv3+ ):

# Get folders whose name either starts with or ends with 'software', including
# just 'software' itself.
$folders = Get-Item -Path $env:SystemRoot\* -Include 'software*', '*software' | 
             Where-Object PSIsContainer

# See if a folder named exactly 'software' is among the matches.
$haveOriginal = $folders.Name -contains 'software'

# See if there are backup folders among the matches (too).
# Note that [int] $haveOriginal evaluates to 1 if $haveOriginal is $True,
# and to 0 otherwise.
$haveBackups = ($folders.Count - [int] $haveOriginal) -gt 0

# Now act on $folders as desired, based on flags $haveOriginal and $haveBackups.
  • 注意如何使用 Get-Item -Path $env:SystemRoot\* 显式预选 所有 项(添加 -Force if hidden 项目也应该包括在内),然后通过 -Include 过滤掉。

  • 由于 Get-Item - 与 Get-ChildItem 不同 - 不支持 -Directory| Where-Object PSIsContainer 用于进一步限制对目录的匹配(文件夹).

  • 注:Get-ChildItem使用,因为-Include只对child[=89有效=] (后代)项目(也)当 -Recurse 也被指定时;虽然 -Recurse 可以与 -Depth 0 (PSv3+) 结合使用以限制对直接子目录的匹配,但 Get-ChildItem 显然仍在尝试读取 条目 所有 个子目录,这可能会导致甚至不感兴趣的目录出现不需要的拒绝访问错误。
    换句话说:Get-ChildItem -Recurse -Depth 0 -Directory $env:SystemRoot -include 'software*', '*software' 仅当您(至少)具有对 $env:SystemRoot.

    [=88 的 all 子目录的读取权限时才等效=]