Powershell:否定类似和匹配条件的意外行为

时间:2017-12-23 13:32:36

标签: regex powershell if-statement wildcard negation

我的Windows文件夹,软件和软件测试中有2个文件夹。 所以我有主文件夹“软件”如果声明,然后跳转到elseif - 这里我有备份文件夹,所以跳转到其他...

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

希望有人可以指导/帮助我:-)

    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
    }

2 个答案:

答案 0 :(得分:2)

我觉得非常困惑,在右边甚至在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."
    }
}   

这会对你有用吗?

答案 1 :(得分:0)

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

  • !$_.Name -like 'software'应为! ($_.Name -like 'software')或最好为 $_.Name -notlike 'software' - 使用PowerShell' not - 带前缀的运算符进行否定。

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

Get-Help about_Operator_Precedence中所述, !(又名-not)的优先级高于-like ,因此评估!$_.Name -like 'software'作为(!$_.Name) -like 'software',这意味着!$_.Name - 布尔的结果 - (字符串 - )与通配符模式'software'进行比较,始终< / em>返回$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),然后通过-Include过滤掉。

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

  • 注意:Get-ChildItem未使用 ,因为-Include仅对(后代)项(也)生效还指定了-Recurse;虽然-Recurse可以与-Depth 0(PSv3 +)结合使用以限制与直接子目录的匹配,Get-ChildItem显然仍然会尝试读取条目 >所有子目录,这可能会导致目标甚至没有感兴趣的访问拒绝错误。
    换句话说:Get-ChildItem -Recurse -Depth 0 -Directory $env:SystemRoot -include 'software*', '*software'只有在$env:SystemRoot 所有子目录的(至少)读取权限时才是等效的。