is there a way to use the equivalent of touch in powershell to update time stamps of a file?

瘦欲@ 提交于 2021-01-24 07:16:37

问题


I use the unix command 'touch' a lot to update time-stamps of any new acquired/downloaded file in my system. Many a times the time-stamp of the existing file is old so it can get lost in the system. Is there a way in MS-Windows powershell to do so. I have both powershell 5 as well as powershell 6.


回答1:


You can use

$file = Get-Item C:\Intel\Logs\IntelCpHDCPSvc.log
$file.LastWriteTime = (Get-Date)

Or CreationTime or LastAcccessTime, if you prefer.

As a function

Function UpdateFileLastWriteTimeToToday() { 
        Param ($FileName)
    $file = Get-Item $FileName
    Echo "Current last write time: " $file.LastWriteTime
    $file.LastWriteTime = (Get-Date)
    Echo "New last write time: " $file.LastWriteTime
}

#How to use

UpdateFileLastWriteTimeToToday -FileName C:\Intel\Logs\IntelGFX.Log

With the output of

Current last write time: 
Tuesday, April 16, 2019 1:09:49 PM

New last write time: 
Monday, November 4, 2019 9:59:55 AM



回答2:


Mark's helpful answer shows how to update a single file's last-modified timestamp.

Below is the source code for function Touch-Item, which implements most of the functionality that the Unix touch utility offers in a PowerShell-idiomatic fashion, including support for -WhatIf, verbose output, and a pass-thru option.

It works in both Windows PowerShell (version 3 or higher) and PowerShell Core.

You can put the function in your $PROFILE, for instance; call Get-Help Touch-Item for help.
If you want to define an alias, I recommend against naming it touch, to prevent confusion with the native utility on Unix-like platforms;
Set-Alias ti Touch-Item would work, for instance.

Examples:

# Sets the last-modified and last-accessed timestamps for all text files
# in the current directory to the current point in time.
Touch-Item *.txt


# Creates files 'newfile1' and 'newfile2' and outputs information about them as 
# System.IO.FileInfo instances.
# Note the need to use "," to pass multiple paths.
Touch-Item newfile1, newfile2 -PassThru


# Updates the last-modified and last-accessed timestamps for all text files
# in the current directory to midnight (the start of) of today's date.
Touch-Item *.txt -DateTime (Get-Date).Date


# Sets the last-modified and last-accessed timestamps of all text files
# in the current directory back by 1 hour.
Get-Item *.txt | Touch-Item -Offset '-1:0'


# Sets the last-modified and last-accessed timestamps of all files in the 
# current directory to the last-modified timestamp of the current directory minus
# 1 minute.
Get-ChildItem -File | Touch-Item -ReferencePath . -Offset '-0:1'

Touch-Item source code:

Note:

  • The function below is also available as an MIT-licensed Gist, and only the latter will be maintained going forward. Assuming you have looked at the linked code to ensure that it is safe (which I can personally assure you of, but you should always check), you can install it directly as follows:

    irm https://gist.github.com/mklement0/82ed8e73bb1d17c5ff7b57d958db2872/raw/Touch-Item.ps1 | iex
    
  • Touch is not an approved verb in PowerShell, but it was chosen nonetheless, because none of the approved verbs can adequately convey the core functionality of this command.

function Touch-Item {
  <#
.SYNOPSIS
"Touches" files and directories.

.DESCRIPTION
Similar to the Unix touch utility, this command updates the last-modified and
last-accessed timestamps of files and directories or creates files on
demand.

The current point in time is used by default, but you can pass a
specific timestamp with -DateTime or use an existing file or directory''s 
last-modified timestamp with -ReferencePath.
The resulting timestamp can be modified with -Offset.

Symbolic links are invariably followed, which means that it is a link''s
*target file or directory* whose timestamps get updated.
If the target doesn''t exist, a non-terminating error occurs.

Use -WhatIf to preview the effects of a given command, and -Verbose to see
details.
Use -PassThru to pass the touched items through, i.e., to output updated
information about them.

Note that in order to pass multiple target files / patterns as arguments
you must *comma*-separate them, because they bind to a single, array-valued
parameter.

.PARAMETER Path
The paths of one or more target files or directories, optionally expressed
as wildcard expressions, and optionally passed via the pipeline.

.PARAMETER LiteralPath
The literal paths of one or more target files or directories, optionally
passed via the pipeline as output from Get-ChildItem or Get-Item.

.PARAMETER DateTime
The timestamp to assign as the last-modified (last-write) and last-access
values, optionally modified by -Offset.

By default, the current point in time is used.

.PARAMETER ReferencePath
The literal path to an existing file or directory whose last-modified
timestamp should be used, optionally modified by -Offset.

.PARAMETER Offset
A timespan to apply as an offset to the effective new timestamp:

* If neither -DateTime nor -ReferencePath are specified, the offset is applied
to the current point in time.

* If -DateTime or -ReferencePath is specified, the offset is applied to the
given timestamp.

Examples of strings that can be used to specify timespans are '-1' for
one day ago and '-2:0' for two hours ago.

Note that positive values adjust the timestamps into the (relative) future,
whereas negative values adjust into the (relative) past.

Alternatively, use something like -(New-TimeSpan -Days 1)

.PARAMETER NoNew
Specifies that only existing files should have their timestamps updated.

By default, literal target paths that do not refer to existing items 
result in files with these paths getting created on demand.

.PARAMETER PassThru
Specifies that the "touched" items are passed through, i.e. produced as this 
command''s output, as System.IO.FileInfo / System.IO.DirectoryInfo instances.

.EXAMPLE
Touch-Item *.txt

Sets the last-modified and last-accessed timestamps for all text files
in the current directory to the current point in time.

.EXAMPLE
Touch-Item newfile -PassThru

Creates file 'newfile' and outputs information about it as a System.IO.FileInfo
instance.

.EXAMPLE
Touch-Item *.txt -DateTime (Get-Date).Date

Updates the last-modified and last-accessed timestamps for all text files
in the current directory to midnight (the start of) of today''s date.

.EXAMPLE
Get-Item *.txt | Touch-Item -Offset '-1:0'

Sets the last-modified and last-accessed timestamps of all text files
in the current directory back by 1 hour.

.EXAMPLE
Get-ChildItem -File | Touch-Item -ReferencePath . -Offset '-0:1'

Sets the last-modified and last-accessed timestamps of all files in the 
current directory to the last-modified timestamp of the current directory minus
1 minute.


.NOTES
"Touch" is not an approved verb in PowerShell, but it was chosen nonetheless,
because none of the approved verbs can adequately convey the core functionality
of this command.

Despite the generic "Item" noun, this command supports *filesystem* $items 
only.

In PowerShell *Core*, implementing this command to support multiple target
paths *as individual arguments* (as in Unix touch) would be possible
(via ValueFromRemainingArguments), but such a solution would misbehave in
Windows PowerShell.

#>

  [CmdletBinding(DefaultParameterSetName = 'Path', SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName = 'Path', Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [Parameter(ParameterSetName = 'PathAndDateTime', Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [Parameter(ParameterSetName = 'PathAndRefPath', Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)]
    [string[]] $Path
    ,
    [Parameter(ParameterSetName = 'LiteralPath', Mandatory, ValueFromPipelineByPropertyName)]
    [Parameter(ParameterSetName = 'LiteralPathAndDateTime', Mandatory, ValueFromPipelineByPropertyName)]
    [Parameter(ParameterSetName = 'LiteralPathAndRefPath', Mandatory, ValueFromPipelineByPropertyName)]
    [Alias('PSPath', 'LP')]
    [string[]] $LiteralPath
    ,
    [Parameter(ParameterSetName = 'PathAndRefPath', Mandatory)]
    [Parameter(ParameterSetName = 'LiteralPathAndRefPath', Mandatory)]
    [string] $ReferencePath
    ,
    [Parameter(ParameterSetName = 'PathAndDateTime', Mandatory)]
    [Parameter(ParameterSetName = 'LiteralPathAndDateTime', Mandatory)]
    [datetime] $DateTime
    ,
    [timespan] $Offset
    ,
    [switch] $NoNew
    ,
    [switch] $PassThru
  )
  begin { 
    Set-StrictMode -Version 1
    $haveRefPath = $PSBoundParameters.ContainsKey('ReferencePath')
    $haveDateTime = $PSBoundParameters.ContainsKey('DateTime')
    $haveOffset = $PSBoundParameters.ContainsKey('Offset')
    # Initialize defaults (even though they may not be used).
    # Defining them unconditionally prevents strict-mode violations in pseudo-ternary conditionals.
    if (-not ($haveDateTime -or $haveRefPath)) { $DateTime = [datetime]::Now }
    if (-not $haveOffset) { $Offset = 0 }
    # If a reference item was given, obtain its timestamp now and abort if that fails.
    if ($haveRefPath) {
      try {
        $DateTime = (Get-Item -ErrorAction Stop $ReferencePath).LastWriteTime
      }
      catch {
        Throw "Failed to get the reference path's last-modified timestamp: $_"
      }
    }
    $touchedCount = 0
  }

  process {
  
    $wildcardsSupported = $PSCmdlet.ParameterSetName -notlike 'LiteralPath*'

    # Try to retrieve existing items.
    [array] $items = if ($wildcardsSupported) {
      Get-Item -Path $Path -ErrorAction SilentlyContinue -ErrorVariable err
    }
    else {
      Get-Item -LiteralPath $LiteralPath -ErrorAction SilentlyContinue -ErrorVariable err
    } 

    # -WhatIf / -Confirm support.
    # Note: The prompt message is also printed with just -Verbose
    $targets = ($LiteralPath, ($Path, $items.FullName)[$items.Count -gt 0])[$wildcardsSupported] -replace '^Microsoft\.PowerShell\.Core\\FileSystem::' -replace ('^' + [regex]::Escape($PWD) + '[\\/]?')
    if ($targets.Count -gt 1) { $targets = "`n" + ($targets -join "`n") + "`n" }
    $newDateTimeDescr = if ($haveOffset -and -not ($haveDateTime -or $haveRefPath)) { "the current timestamp offset by $Offset" } else { "$($DateTime + $Offset)" }
    $actionDescr = ("Updating / creating with a last-modified timestamp of $newDateTimeDescr", "Updating the last-modified timestamp to $newDateTimeDescr")[$NoNew.IsPresent]
    if (-not $PSCmdlet.ShouldProcess($targets, $actionDescr)) { return }

    # Try to create the items that don't yet exist, as files - unless opt-out -NoNew was specified.
    if ($err -and -not $NoNew) {
      $items += foreach ($item in $err.TargetObject) {
        Write-Verbose "Creating: $item"
        New-Item -Type File -Path $item
      }
    }

    # Set the last-modified and last-access timestamps.
    foreach ($item in $items) {
      $newDateTime = ($DateTime, $item.LastWriteTime)[$haveOffset -and -not ($haveDateTime -or $haveRefPath)] + $Offset
      $item.LastWriteTime = $item.LastAccessTime = $newDateTime
      if ($PassThru) { $item }
    }
    $touchedCount += $items.Count
  
  }

  end {
    if (-not $WhatIfPreference -and $touchedCount -eq 0) {
      Write-Warning "Nothing to touch."
    }
  }

}


来源:https://stackoverflow.com/questions/58685459/is-there-a-way-to-use-the-equivalent-of-touch-in-powershell-to-update-time-stamp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!