我需要我的脚本在 -Whatif 输出中包含 "LastWriteTime" 属性

I need my script to include the "LastWriteTime" property on the -Whatif output

我需要编辑我在此处找到的脚本,以便我可以首先看到它将删除的文件的报告,包括文件名和路径以及“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 的输出相当简洁 - “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

实际删除文件

作为 Mathias R. Jessen notes, you have no control over the target-object descriptions that cmdlets use with the common -WhatIf parameter,PowerShell 的 dry-运行 功能。

这是一个 解决方法 ,但请注意,它是 次优 ,主要是因为使用了 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标志,您有两个选项:

    • Either:用 [CmdletBinding(SupportsShouldProcess)] 属性修饰脚本的 param(...) 块以打开 -WhatIf 公共参数支持:

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

      • 由于 PowerShell 自动将此公共参数转换为本地 $WhatIfPreference preference 变量,因此必须修改上面的代码:

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

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

    • 或者,根据对问题的评论调整 Daniel 的方法,您可以调整上面的 if 语句以完全绕过 Remove-Item -WhatIf 调用,如果$whatIf 在脚本块中设置为 $true,并自己制作完整的假设消息:

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

当 运行 为 -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