【问题标题】:I need my script to include the "LastWriteTime" property on the -Whatif output我需要我的脚本在 -Whatif 输出中包含“LastWriteTime”属性
【发布时间】:2021-02-11 03:29:52
【问题描述】:

我需要编辑我在此处找到的脚本,以便我可以首先查看它将删除的文件的报告,包括文件名和路径以及“LastWriteTime”属性,以便我可以分析脚本的输出执行前几个月,在我将其配置为计划任务之前:

我曾尝试使用 LastWriteTime 对象属性一段时间,但我不知道还能做什么..

下面是代码:

$limit = (Get-Date).AddDays(-30)

$del30 = "D:\contoso_ftp\users"

$ignore = Get-Content "C:\Users\username\Documents\Scripts\ignorelist.txt"

Get-ChildItem $del30 -Recurse | 

Where-Object {$_.LastWriteTime -lt $limit } |

Select-Object -ExpandProperty FullName |

Select-String -SimpleMatch -Pattern $ignore -NotMatch | 

Select-Object -ExpandProperty Line |

Remove-Item -Recurse -WhatIf

这是目前 -Whatif 输出的样子:

如果:对目标“D:\contoso_ftp\users\ftp-contosoaccount\contoso Downloads\contosofile.zip”执行“删除文件”操作。

所以.. 如您所见,我需要能够在其中获取“LastWriteTime”属性。

非常感谢任何有关文章或文档的帮助或提示。

提前致谢,

//伦纳特

【问题讨论】:

  • 当使用-WhatIf 运行时,您无法修改Remove-Item 表面的参数 - 但您可以|Remove-Item ... 替换为|Get-ChildItem -Recurse |Select FullName,LastWriteTime
  • 大家好!非常感谢你的帮助!!!当我进行 Mathias 告诉我的更改时,它为我提供了我正在寻找的信息,但我必须重新编辑代码才能实际执行文件的删除,对吗?
  • 嗯我想知道其他人的回复发生了什么?我删除了“Get-ChildItem”部分并添加了他的建议,但我只得到以下输出:如果:使用 LastWriteTime 在目标“”上执行“删除文件”操作:我怀疑我必须在这些括号内编辑某些内容?谢谢, //Lennart
  • 是的,当您准备好删除文件时,您必须将脚本修改回 | Remove-Item -Recurse
  • 抱歉,我遗漏了 Get-Item | Get-ChildItem -Recurse |% {Write-host "What if: Performing the operation ""Remove File"" on target ""$($_.FullName)"" with LastWriteTime: $($_.LastWriteTime) "}(对所有的编辑感到抱歉。我现在就下车回去睡觉...)

标签: powershell automation


【解决方案1】:

当使用-WhatIf 运行时,您无法修改Remove-Item 的输出,但您可以将管道包装在支持-WhatIf 并提供自己定制的-WhatIf 输出的函数中:

function Test-Something {
    [CmdletBinding(SupportsShouldProcess)]    # This enables -WhatIf processing
    param (
        [string] $path,
        [datetime] $limit,
        [string] $ignore
    )
        
    Get-ChildItem $path -Recurse | 

    Where-Object { $_.LastWriteTime -lt $limit } |
        
    Select-Object -ExpandProperty FullName |
        
    Select-String -SimpleMatch -Pattern $ignore -NotMatch | 
        
    Select-Object -ExpandProperty Line |

    Get-ChildItem -Recurse | ForEach-Object {

        # If -WhatIf is passed, output the message and skip the deletion.
        # Else enter the if-block and delete the file.
        if( $PSCmdlet.ShouldProcess( 
                "Performing the operation `"Remove File`" on target `"$_`" (LastWriteTime: $($_.LastWriteTime))", 
                "Are you sure you want to delete file `"$_`" ?", 
                "Confirm" ) ) {
                
            Remove-Item $_ 
        }
    }  
}

请注意,我不必在函数中定义-WhatIf 参数,因为它是通过指定SupportsShouldProcess 自动添加的。现在您可以将-WhatIf 传递给您的函数以进行试运行:

Test-Something $del30 $limit $ignore -WhatIf

样本输出:

What if: Performing the operation "Remove File" on target "C:\test\file1.txt" (LastWriteTime: 12/30/2020 19:47:10)
What if: Performing the operation "Remove File" on target "C:\test\file2.txt" (LastWriteTime: 01/12/2021 00:59:59)

我使用了$PSCmdlet.ShouldProcess overload,它接受三个参数来提供详细的-WhatIf 消息。另外两个参数为相关的-Confirm 参数提供消息和标题,该函数也支持:

Test-Something $del30 $limit $ignore -Confirm

现在 PowerShell 会在删除前询问:

Confirm
Are you sure you want to delete file "C:\test\file1.txt" ?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Yes"): 

您免费获得的另一个很酷的功能是详细输出。当您使用-Verbose 调用该函数时,提供给$PSCmdlet.ShouldProcess() 的消息将用作详细输出:

Test-Something $del30 $limit $ignore -Verbose

输出:

VERBOSE: Performing the operation "Remove File" on target "C:\test\file1.txt" (LastWriteTime: 12/30/2020 19:47:10)
VERBOSE: Performing the operation "Remove File" on target "C:\test\file2.txt" (LastWriteTime: 01/12/2021 00:59:59)

延伸阅读:Everything you wanted to know about ShouldProcess

【讨论】:

    【解决方案2】:

    如您所见,-WhatIf 的输出相当简洁——“Action: Thing”——仅此而已。

    您可以在脚本中通过分离报告和实际删除来解决此问题:

    param(
      [string]$Path = "D:\banqsoft_ftp\users",
    
      [datetime]$Limit = $((Get-Date).AddDays(-30)),
    
      [string[]]$ignore = $(Get-Content "$env:USERPROFILE\Documents\Scripts\ignorelist.txt"),
    
      [switch]$Force
    )
    
    $targetPaths = Get-ChildItem $del30 -Recurse |
      Where-Object {$_.LastWriteTime -lt $limit } |
      Select-Object -ExpandProperty FullName |
      Select-String -SimpleMatch -Pattern $ignore -NotMatch |
      Select-Object -ExpandProperty Line
    
    # List files that would have been affected + their timestamps
    Get-ChildItem $targetPaths -Recurse -File |Select-Object FullName,LastWriteTime
    
    if($Force){
      # If -Force was specified then we remove as well
      $targetPaths |Remove-Item -Recurse -Force
    }
    

    现在你可以这样运行它:

    PS ~> .\script.ps1
    

    ... 仅列出带有LastWriteTime 的文件,一旦您有信心,使用-Force 运行它:

    PS ~> .\script.ps1 -Force
    

    实际删除文件

    【讨论】:

    • 您的建议有效,但我需要为此脚本安排一个作业,每月运行一次并实际执行删除。我现在想知道的是如何在映射脚本后在计划任务上添加 -Force 参数?我尝试阅读这篇文章,但它对我没有用。我认为我在错误的位置添加了 -Force 参数:这是我在“添加参数(可选)字段:C:\Users\userX\ Documents\Scripts\DeleteFilesOlderThan30 - 01.ps1 -RunType$targetPaths -Force
    【解决方案3】:

    正如Mathias R. Jessen 所说,您无法控制 cmdlet 与 PowerShell 的试运行功能 common -WhatIf parameter 一起使用的目标对象描述

    这是一个解决方法,但请注意它次优,主要是因为使用ForEach-Object 调用和脚本块的每个对象执行会减慢命令速度明显:

    'file1.txt', 'file2.txt' | # Stand-in for everything before your Remove-Item call
      Get-Item | # transform strings into [System.IO.FileInfo] objects
        ForEach-Object {
          $whatIf = $true # Set this to $false later to perform actual deletion.
          # Prepend the last-write timestamp *without a trailing newline*
          if ($whatIf) { Write-Host -NoNewline "$($_.LastWriteTime): " }
          # Let Remove-Item append its what-if message
          $_ | Remove-Item -WhatIf:$whatif
        }
    

    输出将如下所示:

    02/07/2021 15:44:24: What if: Performing the operation "Remove File" on target "/Users/jdoe/file1.txt".
    02/07/2021 15:44:24: What if: Performing the operation "Remove File" on target "/Users/jdoe/file2.txt".
    

    注意:

    • 如果您想从您的脚本外部控制-WhatIf标志,您有两种选择:

      • 任一:使用[CmdletBinding(SupportsShouldProcess)] 属性装饰脚本的param(...) 块以启用-WhatIf 通用参数支持:

        • 警告:这将调用您脚本中支持-WhatIf所有 cmdlet,当您传递-WhatIf隐式应用它到您的脚本中,尽管您可以使用-WhatIf:$false 选择性地抑制它;请参阅下面的替代方法以了解逆向方法。

        • 由于 PowerShell 会自动将此常用参数转换为本地 $WhatIfPreferencepreference 变量,因此必须对上面的代码进行修改:

          • 使用if ($WhatIfPreference) 来测试-WhatIf 是否已通过并应生成Write-Host 输出。
          • Remove-Item 调用中删除 -WhatIf:$whatIf - 如果将-WhatIf 传递给您的脚本,它将自动应用
      • 或者:如果您想要更多控制,请使用 自定义 [switch] $WhatIf 参数声明而不是 SupportsShouldProcess,并查询 @987654345 @ / 应用-WhatIf:$WhatIf 明确和选择性地

        • 在这种情况下,只需从上面的代码中删除 $whatIf = $true 语句即可。
        • 警告:您的脚本将尊重$WhatIfPreference 变量,除非您明确检查它以防-WhatIf 未明确传递(检查$PSBoundParameters.ContainsKey('WhatIf') )。
    • 您可以通过内联 Write-Host 调用获得尽可能详细的信息,但请注意,单行 输出只有在您预先添加 Write-Host 时才有可能输出。

      • 或者,如果$whatIf 在脚本块中设置为$true ,并自己制作完整的假设信息:

        if ($whatif) { Write-Host ...  } else { $_ | Remove-Item }
        
    • 请注意,-WhatIf 输出既不能被捕获也不能被抑制 - 它总是直接打印到主机(控制台)。

    【讨论】:

      猜你喜欢
      • 2016-10-10
      • 2019-10-02
      • 1970-01-01
      • 1970-01-01
      • 2012-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多