使用PowerShell清空回收站中的旧文件

9

好的,我正在用PowerShell编写一个脚本,用于删除回收站中的旧文件。我想让它删除所有在2天前被删除的回收站中的文件。我已经做了很多研究,但并没有找到合适的答案。

这是我目前所拥有的(从网上找到的脚本,我并不太了解PowerShell):

$Path = 'C' + ':\$Recycle.Bin'
Get-ChildItem $Path -Force -Recurse -ErrorAction SilentlyContinue |
#Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-3) } |
Remove-Item -Recurse -exclude *.ini -ErrorAction SilentlyContinue

除了一个例外,它检查文件参数“LastWriteTime”,如果用户在修改文件后的同一天删除该文件,那么这很棒。否则会失败。

我该如何修改此代码以便检查文件被删除的时间,而不是写入的时间。

-另外,如果我在Microsoft Server 2008上的管理员帐户中运行此脚本,它会为所有用户的回收站工作还是只有我的回收站?


答案:

对我有效的代码是:

$Shell = New-Object -ComObject Shell.Application
$Global:Recycler = $Shell.NameSpace(0xa)

foreach($item in $Recycler.Items())
{
    $DeletedDate = $Recycler.GetDetailsOf($item,2) -replace "\u200f|\u200e",""
    $dtDeletedDate = get-date $DeletedDate 
    If($dtDeletedDate -lt (Get-Date).AddDays(-3))
    {
        Remove-Item -Path $item.Path -Confirm:$false -Force -Recurse
    }#EndIF
}#EndForeach item

这对我非常有效,但仍有两个问题……我如何在多个驱动器上进行此操作?这将应用于所有用户还是只适用于我自己?

5个回答

6

WMF 5 包含了新的 "Clear-RecycleBin" 命令。

PS > Clear-RecycleBin -DriveLetter C:\


(注:该命令为清空指定磁盘的回收站内容)

3

以下两行命令将清空所有文件的回收站:

$Recycler = (New-Object -ComObject Shell.Application).NameSpace(0xa)
$Recycler.items() | foreach { rm $_.path -force -recurse }

2
如果重要的话,请注意这不会刷新桌面上的回收站图标。 - xdhmoore

1
这篇文章回答了你所有的问题。

http://baldwin-ps.blogspot.be/2013/07/empty-recycle-bin-with-retention-time.html

留存代码:

# ----------------------------------------------------------------------- 
#
#       Author    :   Baldwin D.
#       Description : Empty Recycle Bin with Retention (Logoff Script)
#     
# -----------------------------------------------------------------------

$Global:Collection = @()

$Shell = New-Object -ComObject Shell.Application
$Global:Recycler = $Shell.NameSpace(0xa)

$csvfile = "\\YourNetworkShare\RecycleBin.txt"
$LogFailed = "\\YourNetworkShare\RecycleBinFailed.txt"


function Get-recyclebin
{ 
    [CmdletBinding()]
    Param
    (
        $RetentionTime = "7",
        [Switch]$DeleteItems
    )

    $User = $env:USERNAME
    $Computer = $env:COMPUTERNAME
    $DateRun = Get-Date

    foreach($item in $Recycler.Items())
        {
        $DeletedDate = $Recycler.GetDetailsOf($item,2) -replace "\u200f|\u200e","" #Invisible Unicode Characters
        $DeletedDate_datetime = get-date $DeletedDate   
        [Int]$DeletedDays = (New-TimeSpan -Start $DeletedDate_datetime -End $(Get-Date)).Days

        If($DeletedDays -ge $RetentionTime)
            {
            $Size = $Recycler.GetDetailsOf($item,3)

            $SizeArray = $Size -split " "
            $Decimal = $SizeArray[0] -replace ",","."
            If ($SizeArray[1] -contains "bytes") { $Size = [int]$Decimal /1024 }
            If ($SizeArray[1] -contains "KB") { $Size = [int]$Decimal }
            If ($SizeArray[1] -contains "MB") { $Size = [int]$Decimal * 1024 }
            If ($SizeArray[1] -contains "GB") { $Size = [int]$Decimal *1024 *1024 }

       $Object = New-Object Psobject -Property @{
                Computer = $computer
                User = $User
                DateRun = $DateRun
                Name = $item.Name
                Type = $item.Type
                SizeKb = $Size
                Path = $item.path
                "Deleted Date" = $DeletedDate_datetime
                "Deleted Days" = $DeletedDays }

            $Object

                If ($DeleteItems)
                {
                    Remove-Item -Path $item.Path -Confirm:$false -Force -Recurse

                    if ($?)
                    {
                        $Global:Collection += @($object)
                    }
                    else
                    {
                        Add-Content -Path $LogFailed -Value $error[0]
                    }
                }#EndIf $DeleteItems
            }#EndIf($DeletedDays -ge $RetentionTime)
}#EndForeach item
}#EndFunction

Get-recyclebin -RetentionTime 7 #-DeleteItems #Remove the comment if you wish to actually delete the content


if (@($collection).count -gt "0")
{
$Collection = $Collection | Select-Object "Computer","User","DateRun","Name","Type","Path","SizeKb","Deleted Days","Deleted Date"
$CsvData = $Collection | ConvertTo-Csv -NoTypeInformation
$Null, $Data = $CsvData

Add-Content -Path $csvfile -Value $Data
}

[System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell)

#ScriptEnd

我喜欢这个,它似乎可以做到我想要的,但是我很难从他的脚本中过滤出我想要的内容。我看到 $DeletedDate = $Recycler.GetDetailsOf($item,2) -replace "\u200f|\u200e","" 可以得到我想要的内容,但是 $Recycler 是在哪里定义的? - Dead_Jester
脚本的第二行,$Global:Recycler 将其定义为全局变量。 - TheMadTechnician
5
可以把文章中的一些观点放到你的回答中吗?我们不能假定链接会一直有效。 - Anthony Neace
好的,那是一个愚蠢的错误。我一直在看他脚本顶部的摘录,而不是底部的整个脚本。现在代码运行得很好!但是如何将此应用于不同的驱动器呢?我需要它对 E: 和 F: 做同样的事情。这是否适用于所有用户,还是只适用于我自己? - Dead_Jester
我没有太多问题。我只想要几行PowerShell代码来清空所有驱动器上的回收站。 - AndreiM

0

在这方面我自己也做了一些研究,回收站包含win 10中每个驱动器上删除的每个文件的两个文件(在win 7中文件保持原样,因此此脚本过于复杂,需要削减,特别是对于powershell 2.0,win 8未经测试),一个在删除时创建的信息文件 $I(非常适合确定删除日期)和原始文件 $R。我发现组件对象方法会忽略更多的文件,但好的一面是提供了关于已删除原始文件的感兴趣的信息,所以经过一番探索,我发现简单的 get-content信息文件可包括原始文件位置,通过一些正则表达式清理后得出如下结果:

# Refresh Desktop Ability
$definition = @'
    [System.Runtime.InteropServices.DllImport("Shell32.dll")] 
    private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
    public static void Refresh() {
        SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);    
    }
'@
Add-Type -MemberDefinition $definition -Namespace WinAPI -Name Explorer

# Set Safe within deleted days and get physical drive letters
$ignoreDeletedWithinDays = 2
$drives = (gwmi -Class Win32_LogicalDisk | ? {$_.drivetype -eq 3}).deviceid

# Process discovered drives
$drives | % {$drive = $_
    gci -Path ($drive+'\$Recycle.Bin\*\$I*') -Recurse -Force | ? {($_.LastWriteTime -lt [datetime]::Now.AddDays(-$ignoreDeletedWithinDays)) -and ($_.name -like "`$*.*")} | % {

        # Just a few calcs
        $infoFile         = $_
        $originalFile     = gi ($drive+"\`$Recycle.Bin\*\`$R$($infoFile.Name.Substring(2))") -Force
        $originalLocation = [regex]::match([string](gc $infoFile.FullName -Force -Encoding Unicode),($drive+'[^<>:"/|?*]+\.[\w\-_\+]+')).Value
        $deletedDate      = $infoFile.LastWriteTime
        $sid              = $infoFile.FullName.split('\') | ? {$_ -like "S-1-5*"}
        $user             = try{(gpv "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\$($sid)" -Name ProfileImagePath).replace("$(gpv 'HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList' -Name ProfilesDirectory)\",'')}catch{$Sid}

        #' Various info
        $originalLocation
        $deletedDate
        $user
        $sid
        $infoFile.Fullname
        ((gi $infoFile -force).length / 1mb).ToString('0.00MB')
        $originalFile.fullname
        ((gi $originalFile -force).length / 1mb).ToString('0.00MB')
        ""

        # Blow it all Away
        #ri $InfoFile -Recurse -Force -Confirm:$false -WhatIf
        #ri $OriginalFile -Recurse -Force -Confirm:$false- WhatIf
        # remove comment before two lines above and the '-WhatIf' statement to delete files
    }
}

# Refresh desktop icons
[WinAPI.Explorer]::Refresh()

作为 PowerShell 新手,这个脚本在哪里运行?它可以放到 .bat 文件中吗? - WonderWorker
没问题。我发现这段代码可以从一个扩展名为 .ps1 的文件中运行。要运行,请右键单击该文件,然后点击“使用 PowerShell 运行”。 - WonderWorker

-2

这也可以作为任务计划程序的脚本很好地工作。

Clear-RecycleBin -Force


我只是在尝试弄清楚如何将此PS针对所有驱动器字母作为变量运行:Get-ChildItem“d:`$Recycle.bin\”-Force | Remove-Item -Recurse -WhatIf,因为仍有人在使用PS4,尚未迁移到5.1。 - Patrick Burwell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接