就像不同的Powershell版本上的行为一样

时间:2017-07-24 06:03:58

标签: powershell powershell-v2.0 powershell-v4.0 powershell-v5.0

此代码在Powershell 5+中运行良好,但在Powershell 4.0和2.0中不起作用:

$DaysToDelete = 2

$targets = "profile/Default",
           "profile/Profile 1",
           "profile/Profile 2",
           "profile/Profile 3",
           "profile/Profile 4"

$special = @("chromium", "64")

$profiles = Get-ChildItem "C:\" -Directory -Force |
    Where-Object Name -In $special |
    Select-Object -ExpandProperty FullName

$chromeDir = "C:\Users\*\AppData\Local\Google\Chrome\User Data\Default"
$chromeSetDir = "C:\Users\*\Local Settings\Application Data\Google\Chrome\User Data\Default"

$Items = @("*Archived History*",
            "*Cache*",
            "*Cookies*",
            "*History*",
            "*Top Sites*",
            "*Visited Links*",
            "*Web Data*")

$profiles | ForEach-Object {
    foreach($target in $targets) {
        $profile = Join-Path $_ $target

        $items | ForEach-Object {
        $item = $_ 
        Get-ChildItem $profile, $chromeDir, $chromeSetDir -Recurse -Force -ErrorAction SilentlyContinue |
            Where-Object { ($_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete))  -and $_.Directory -like $item} | ForEach-Object { 
            $path = Join-Path $_.DirectoryName $_
            Remove-Item $path -force -Verbose -recurse -ErrorAction SilentlyContinue }
         }

    }
}

我透露,打破执行的那块是

-and $_.Directory -like $item

它在PS 5+(Windows 10)上工作正常但在PS 4(Windows 7)上没有发现任何相似的模式。 Chrome版本及其目录层次结构在两台计算机上都相同: 59.0.3071.115(官方版本)(64位)

在Win10上启动脚本,版本规范相似

powershell.exe -Version 4.0
什么都没有,它运行得很好。 我对Powershell版本的细节不太熟悉,欢迎大师提出任何建议。 如何使脚本独立于版本

更新: Here is完整代码,但它没有任何价值。我验证了所有地方,并确切地说明了上面的问题行。

另一个有趣的时刻:我发现问题本身不在like子句中,而在like$_.CreationTime组合中检查:< / p>

$_.CreationTime -lt $(Get-Date).AddDays(-$DaysToDelete) -and $_.Directory -like $item

如果我单独放置其中任何一个条件,一切正常,但是如果我将它们组合成单一复合条件,则不会返回任何内容,但 文件夹符合这两个条件。

我无法以任何方式解释这一点。

2 个答案:

答案 0 :(得分:4)

我在评论中提到过这一点;我不确定它是否足够清楚,以及这是否是整个问题。

根据您的原始问题,此行不起作用。这不依赖于PowerShell版本。

$_.Directory -like $item
  • Get-ChildItem找到文件时,它会返回System.IO.FileInfo class个对象。

    • DirectoryFileInfo类的属性,因此文件将具有此属性。
    • Directory属于DirectoryInfo
  • Get-ChildItem找到文件夹/目录时,它将返回System.IO.DirectoryInfo class个对象。

    • DirectoryInfo个对象没有Directory属性。
    • 他们有Parent,还会返回System.IO.DirectoryInfo个对象
  • 在任何一种情况下,您都在处理一个对象并将其与字符串进行比较。当你真的想要将文件夹名称与字符串进行比较时 对于运行v5.1.14409.1005的Windows 8.1,修改为True;对于较旧的操作系统,期望是相同的 运行PS v5.1.143993.1480的Windows 10为False;期望在Server 2016上保持不变。不确定Name / FullName属性是如何自动评估的......

Get-ChildItem -File      | Where {$_.Directory      -like "*test*"}   # not ok: comparing object to string.
Get-ChildItem -Directory | Where {$_.Directory.Name -like "*test*"}   # not ok: DirectoryInfo object does not have Directory property

Get-ChildItem -File      | Where {$_.Directory.Name -like "*test*"}   # ok
Get-ChildItem -Directory | Where {$_.Parent.Name    -like "*test*"}   # ok

答案 1 :(得分:2)

如何使脚本与版本无关?

对我而言,如何使其与版本无关的最佳方法是使用您需要支持的最低版本,在您的情况下为2.0。

另一个选项是检测PowerShell版本并使您的版本彼此独立。

我查看了你的剧本 我建议在实际删除项目之前使用Test-Path -Path "$var"工具来测试结果的有效性。

现在要真正解决您的问题: 在使用PowerShell和清除用户配置文件时,我遇到了类似的问题。

针对您的具体情况进行调整(通过like来解决您的问题):

$newer_file_exist += Get-ChildItem -Path $profile -Recurse -Force -ErrorAction SilentlyContinue | Where-Object {$_.PSIsContainer -eq $FALSE} | where {($_.CreationTime).ToString('yyyy-MM-dd') -lt (get-date).adddays(-$DaysToDelete).ToString('yyyy-MM-dd')};

它将选择比-$DaysToDelete更新的所有文件。它将递归并仅选择文件{$_.PSIsContainer -eq $FALSE}。如果你想选择目录`{$ _.PSIsContainer -eq $ TRUE}。

# get all files to be deleted
ForEach ($dir in $profiles_with_path) {
    # to check
    $test_current_pathPath = Test-Path -Path $dir
    If ($test_current_pathPath) {
        #write-host 'Currently writing for these months:'$($time.Name);
        $files_to_delete += Get-ChildItem -Path $dir -recurse -Force | Where-Object {$_.PSIsContainer -eq $FALSE} | % { $_.FullName }
    }
}

要删除文件:

  If ($files_to_delete) {
            ForEach ($file in $files_to_delete) { 
                #Remove-Item $file -Recurse -Force -ErrorAction SilentlyContinue
                Remove-Item $file -Force -ErrorAction SilentlyContinue
                If ($? -eq $true) {
                    $files_deleted ++;
                    #Write-Verbose -Verbose "$File deleted successfully!"
                }
            }

所有目录

ForEach ($dir in $profiles_with_path) { #
    Remove-Item $dir -Recurse -Force -ErrorAction SilentlyContinue
    If ($? -eq $true) {
        $directories_deleted ++;
        #Write-Verbose -Verbose "$File deleted successfully!"
    }
}

这些代码段适用于2.0(在WinXP和Windows 2003(SPx)以及4.0 Win7测试中测试过。

首次编辑:

我试图为你选择有效的代码,但显然我可以做得更好。 逻辑如下:我想删除所有不包含任何3个月以上文件的配置文件。

变量$newer_file_exist - 用于指示是否找到此类文件。如果找到了 已跳过整个个人资料 - 已添加到$excluded_directories.Add($profile)(有关详情,请参阅源代码链接)

$profiles_with_path填充了 - $profiles_with_path = Get-ChildItem -Path $folder_to_cleanse -exclude $excluded_directories | Where-Object {$_.PSIsContainer -eq $True} 我从$excluded_directories

中排除了所有目录

这是我在BB上公开的剧本:   The whole source code on my BB (它包括测试运行逻辑,时间规范等)