Есть ли способ использовать эквивалент прикосновения в powershell для обновления меток времени файла? - PullRequest
1 голос
/ 04 ноября 2019

Я использую команду unix 'touch' для обновления меток времени любого нового полученного / загруженного файла в моей системе. Много раз отметка времени существующего файла устарела, поэтому он может потеряться в системе. Есть ли способ в PowerShell MS-Windows сделать это. У меня есть как powershell 5, так и powershell 6.

Ответы [ 2 ]

2 голосов
/ 04 ноября 2019

Вы можете использовать

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

Или CreationTime или LastAcccessTime, если вы предпочитаете.

Как функцию

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

С выводом

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

New last write time: 
Monday, November 4, 2019 9:59:55 AM
0 голосов
/ 07 ноября 2019

Полезный ответ Марка показывает, как обновить последнюю временную метку отдельного файла.

Ниже приведен исходный код для функции Touch-Item, которая реализует большинство функциональных возможностей, которые предлагает утилита Unix touch, идиоматически * PowerShell , включая поддержку -WhatIf, подробный вывод и сквозную опцию.

Работает вWindows PowerShell (версия 3 или выше) и PowerShell Core.

Вы можете, например, поместить эту функцию в $PROFILE;позвоните Get-Help Touch-Item за помощью.
Если вы хотите определить псевдоним, я рекомендую не называть его touch, чтобы избежать путаницы с нативной утилитой на Unix-подобных платформах;
Set-Alias ti Touch-Item будет работать, дляэкземпляр.

Примечание. Код также доступен в виде сценария .ps1 в этом Gist .

Примеры :

# 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 исходный код:

Примечание. «Прикосновение» не является утвержденным глаголом в PowerShell, но, тем не менее, оно было выбрано, поскольку ни один из утвержденных глаголовможет адекватно передать основные функциональные возможности этой команды.

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."
    }
  }

}
...