当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 重新审视使用 PowerShell 进行清理

作者:精品下载站 日期:2024-12-14 08:02:24 浏览:14 分类:玩电脑

重新审视使用 PowerShell 进行清理


[玩转系统] 重新审视使用 PowerShell 进行清理

北美的春天即将来临。我住的地方,雪终于融化了,天空蔚蓝,气温变暖。当然,这意味着春季大扫除。是时候清理冬季残骸并装饰房子了。对我来说,这也是进行一些计算清理工作的好时机。我不知道你的Windows环境如何,但我倾向于积累很多垃圾。大多数时候我看不到它,但我知道它就在那里。虽然垃圾通常不会产生负面影响,但我认为在精神上,我喜欢清理和整理东西。所以我拿出了一些旧的 PowerShell 代码,对其进行了更新,现在我有了一套用于清除垃圾和临时文件夹的工具。让我告诉你我的想法。

删除旧文件

第一个任务是删除早于给定日期的文件。我通常想清除临时文件夹中的文件。我知道其中一些文件可能仍在使用中,因此我不一定要广泛删除所有文件。我只想删除上次修改日期早于给定日期的文件。最终,我将使用上次启动时间。任何早于上次启动时间的文件都应该可以安全地从任何临时文件夹中删除。这是我的 PowerShell 函数。

Function Remove-File {
    [cmdletbinding(SupportsShouldProcess)]
    [Alias("rfi")]
    Param(
        [Parameter(Position = 0)]
        [ValidateScript( { Test-Path $_ })]
        [string]$Path = $env:temp,
        [Parameter(Position = 1, Mandatory, HelpMessage = "Enter a cutoff date. All files modified BEFORE this date will be removed.")]
        [ValidateScript( { $_ -lt (Get-Date) })]
        [datetime]$Cutoff,
        [Switch]$Recurse,
        [Switch]$Force
    )

    Write-Verbose "Starting $($MyInvocation.MyCommand)"
    Write-Verbose "Removing files in $path older than $cutoff"

    #clean up PSBoundParameters which will be splatted to Get-ChildItem
    [void]$PSBoundParameters.Add("File", $True)
    [void]$PSBoundParameters.Remove("CutOff")
    if ($WhatIfPreference) {
        [void]$PSBoundParameters.Remove("Whatif")
    }

    Write-Verbose "Using these parameters: `n $($PSBoundParameters | Out-String)"
    Try {
        $files = Get-ChildItem @PSBoundParameters -ErrorAction Stop | Where-Object { $_.lastwritetime -lt $cutoff }
    }
    Catch {
        Write-Warning "Failed to enumerate files in $path"
        Write-Warning $_.Exception.Message
        #Bail out
        Return
    }

    if ($files) {
        Write-Verbose "Found $($files.count) file(s) to delete."
        $stats = $files | Measure-Object -Sum length
        $msg = "Removing {0} files for a total of {1} MB ({2} bytes) from {3}." -f $stats.count, ($stats.sum / 1MB -as [int]), $stats.sum, $path.toUpper()
        Write-Verbose $msg

        #only remove files if anything was found
        $files | Remove-Item -Force

        #Display a WhatIf Summary
        if ($WhatIfPreference) {
            Write-Host "What if: $msg" -ForegroundColor CYAN
        }

    } #if $files
    else {
        Write-Warning "No files found to remove in $($path.ToUpper()) older than $Cutoff."
    }

    Write-Verbose "Ending $($MyInvocation.MyCommand)"
} #close function

我在 cmdletbinding 中支持 -WhatIf。我不需要编写任何特殊的代码来使用它。 Remove-Item 支持 -WhatIf,因此如果我使用参数运行该函数,Remove-Item 将自动检测它。

[玩转系统] 重新审视使用 PowerShell 进行清理

我的函数有一段代码,它为我提供了该函数将执行的操作的摘要。我什至让它看起来像 WhatIf 输出,只不过我使用 Write-Host 并以青色显示消息,以便它脱颖而出。

删除空目录

接下来,我想删除空目录。多年来我编写了各种函数和脚本来做到这一点。这是我当前的迭代。

Function Remove-EmptyFolder {
  [cmdletbinding(SupportsShouldProcess)]
  [alias("ref")]
  [outputType("None")]
  Param(
    [Parameter(Position = 0, Mandatory, HelpMessage = "Enter a root directory path")]
    [ValidateScript( {
        Try {
          Convert-Path -Path $_ -ErrorAction stop
          if ((Get-Item $_).PSProvider.Name -ne 'FileSystem') {
            Throw "$_ is not a file system path."
          }
          $true
        }
        Catch {
          Write-Warning $_.exception.message
          Throw "Try again."
        }
      })]
    [string]$Path
  )

  Write-Verbose "Starting $($myinvocation.mycommand)"

  Write-Verbose "Enumerating folders in $Path"

  $folders = (Get-Item -Path $Path -force).EnumerateDirectories("*", [System.IO.SearchOption]::AllDirectories).foreach( {
      if ($((Get-Item $_.FullName -force).EnumerateFiles("*", [System.IO.SearchOption]::AllDirectories)).count -eq 0) {
        $_.fullname
      } })

  If ($folders.count -gt 0) {

    $msg = "Removing $($folders.count) empty folder(s) in $($path.ToUpper())"
    Write-Verbose $msg
    #Test each path to make sure it still exists and then delete it
    foreach ($folder in $folders) {
      If (Test-Path -Path $Folder) {
        Write-Verbose "Removing $folder"
        Remove-Item -Path $folder -Force -Recurse
      }
    }

    #Display a WhatIf Summary
    if ($WhatIfPreference) {
      Write-Host "What if: $msg" -ForegroundColor CYAN
    }
  }
  else {
    Write-Warning "No empty folders found under $($path.ToUpper())."
  }

  Write-Verbose "Ending $($myinvocation.mycommand)"

} #end Remove-EmptyFolder

我没有获取每个文件夹的子列表,而是调用 EnumerateDirectories() 和 EnumerateFiles() 方法。这似乎执行得更快一些。

$folders = (Get-Item -Path $Path -force).EnumerateDirectories("*", [System.IO.SearchOption]::AllDirectories).foreach( {
      if ($((Get-Item $_.FullName -force).EnumerateFiles("*", [System.IO.SearchOption]::AllDirectories)).count -eq 0) {
        $_.fullname
      } })

该表达式的第一部分是获取搜索路径中的所有目录。然后我测试每个文件夹中的所有文件。如果没有文件,则空目录的完整路径将保存到 $folders。这将成为要删除的项目列表。

foreach ($folder in $folders) {
   If (Test-Path -Path $Folder) {
      Write-Verbose "Removing $folder"
     Remove-Item -Path $folder -Force -Recurse
   }
}

我正在对每条路径进行快速测试,因为我可能已经删除了一个空的父路径。

[玩转系统] 重新审视使用 PowerShell 进行清理

使用控制脚本

虽然我可以单独运行这些函数,但我编写了一个简单的控制脚本。这些功能是工具,控制器脚本“编排”它们的使用。控制器脚本本身成为一个可重用的工具。

#requires -version 5.1

<#
  CleanTemp.ps1
  A control script to clean temp folders of files since last boot
  and empty folders.
#>
[cmdletbinding(SupportsShouldProcess)]
Param(
  [Parameter(Position = 0,HelpMessage = "Specify the temp folder path")]
  [string[]]$Path = @($env:temp, 'c:\windows\temp', 'D:\Temp')
)

#dot source functions
. C:\scripts\Remove-EmptyFolder.ps1
. C:\scripts\Remove-File.ps1

#get last boot up time
$bootTime = (Get-CimInstance -ClassName Win32_OperatingSystem).LastBootUpTime
Write-Verbose "Last boot = $boottime"
#delete files in temp folders older than the last bootup time
foreach ($folder in $Path) {
  if (Test-Path $Folder) {
    Remove-File -path $folder -cutoff $bootTime -recurse -force
    Remove-EmptyFolder -path $folder
  }
  else {
    Write-Warning "Failed to validate $($folder.toUpper())"
  }
}

脚本参数具有默认值,这使得我运行起来非常简单。我可以而且可能应该将清洁功能放入模块中,因为它们是相关的。但在那之前,我将简单地对文件进行点源处理。控制器脚本将必要的参数传递给底层命令。几秒钟之内,我的临时文件夹就被清理干净了。

安排任务

现在我想起来了,我可能应该做的是创建一个 PowerShell 计划作业以在登录时运行此脚本。

$params = @{
    FilePath       = "C:\scripts\CleanTemp.ps1"
    Name           = "ClearTemp"
    Trigger        = (New-JobTrigger -AtLogOn)
    MaxResultCount = 1
}

Register-ScheduledJob @params

现在我再也不用担心春季大扫除了!

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯