Skip to content

Instantly share code, notes, and snippets.

@lidopaglia
Created December 31, 2013 17:22
Show Gist options
  • Save lidopaglia/8199868 to your computer and use it in GitHub Desktop.
Save lidopaglia/8199868 to your computer and use it in GitHub Desktop.
Change the access and modification times of one or more files.
#Requires -Version 3.0
<#
.SYNOPSIS
Change the access and modification times of one or more files.
.DESCRIPTION
Set-File is designed to work in similar fashion to the Unix 'touch(1)' command. If the given filepath does
not exist, Set-File creates the file setting its initial content to $null. If the file already exists then
some or all of the file's timestamps can be modified. Unless specific properties are specified an existing
file's CreationTime, LastAccessTime, and LastWriteTime properties will be modified. A specific date can be
used or a reference file can be provided from which to clone a timestamp from. If neither a date or file
is provided the default date is set to the current time.
.NOTES
Author : Lido Paglia <lido@paglia.org>
Date : 12/31/2013 10:18:28
Tags : file, path, touch, date, timestamp
Comments :
.PARAMETER FilePath
One or more files to modify.
.PARAMETER Property
The specific timestamp property to modify. Properties include LastWriteTime, LastAccessTime, and CreationTime.
The default behavior will modify all three properties if a single property is not provided.
.PARAMETER Date
A specific datetime object to use for modifying one or more file timestamps. If a date is not specified the
current time will be used.
.PARAMETER ReferenceFile
A path to a reference file from which to clone a timestamp from. Similar to -r, --reference=FILE
in touch(1).
.PARAMETER ReferenceProperty
The timestamp to use from the given reference file. This parameter is mandatory if -FileDate is specified.
Available options are: LastAccessTime, LastWriteTime, or CreationTime.
.PARAMETER PassThru
Passes an FileInfo object representing the modified item to the pipeline. By default, this script cmdlet does
not generate any output.
.PARAMETER Force
Allows overwriting an existing read-only file. If the file path specified does not exist using -Force will create the
file including any non-existent directories in the specified path. Even using the Force parameter, the cmdlet cannot
override filesystem security restrictions.
.INPUTS
System.String. You can pipe a list of objects to Set-File to operate on.
.OUTPUTS
None or an object representing the new or changed item.
When you use the Passthru parameter, Set-File generates an object representing the modified item.
Otherwise, this cmdlet does not generate any output.
.EXAMPLE
touch .\foo\bar\bat -Force
Creates the file 'bat' in the folder path '.\foo\bar' in the current working directory.
.EXAMPLE
touch -FilePath foo.txt -Date (Get-Date).AddDays(-2)
.EXAMPLE
Get-ChildItem f* -File | touch -PassThru
Gets all files beginning with the letter 'f' in the current working directory and sets their LastWriteTime,
LastAccessTime, and CreationTime to the current time and passes their fileinfo objects to the pipeline.
.EXAMPLE
ls f* -File | touch -Property LastWriteTime -Date (Get-Date 12/20/1990)
Gets all files beginning with the letter 'f' in the current working directory and sets their LastWriteTime
to the specified date, 12/20/1990
.LINK
Set-Content
.LINK
New-Item
.LINK
http://en.wikipedia.org/wiki/Touch_(Unix)
.LINK
http://sushihangover.blogspot.com/2012/10/powershell-true-touch-file-routine.html
.LINK
http://stackoverflow.com/questions/3038337/powershell-resolve-path-that-might-not-exist
#>
function Set-File
{
[cmdletbinding(SupportsShouldProcess)]
Param(
[Parameter(Mandatory,Position=0,ValueFromPipeline,ValueFromPipelineByPropertyName,HelpMessage="Which file to create or modify?")]
[Alias("FullName")]
[String[]]$FilePath,
[ValidateSet("All","LastAccessTime","LastWriteTime","CreationTime")]
[String]$Property = "All",
[Parameter(ParameterSetName='DateFromArgs')]
[DateTime]$Date,
[Parameter(ParameterSetName='DateFromFile')]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[String]$ReferenceFile,
[Parameter(Mandatory,ParameterSetName='DateFromFile',HelpMessage="Which of the reference file's attributes to use? (LastAccessTime, LastWriteTime, or CreationTime)")]
[ValidateSet("LastAccessTime","LastWriteTime","CreationTime")]
[String]$ReferenceProperty,
[Switch]$PassThru,
[Switch]$Force
)
begin
{
#region 'Domestic Workers'
function updateFileSystemInfo
{
[cmdletbinding()]
Param(
[Parameter(Mandatory,Position=0)]
[System.IO.FileSystemInfo]$InputObject,
[ValidateSet("All","LastAccessTime","LastWriteTime","CreationTime")]
[String]$Property = "All",
[Parameter(Mandatory,Position=1)]
[DateTime]$Date,
[Switch]$PassThru
)
switch ($Property) {
'CreationTime' { $InputObject.CreationTime = $FileTime }
'LastAccessTime' { $InputObject.LastAccessTime = $FileTime }
'LastWriteTime' { $InputObject.LastWriteTime = $FileTime }
Default { $InputObject.CreationTime = $FileTime
$InputObject.LastAccessTime = $FileTime
$InputObject.LastWriteTime = $FileTime }
} #endswitch
if($PassThru)
{
$InputObject
}
}
function touchNewFile
{
[cmdletbinding()]
Param(
[String]$FilePath,
[Switch]$Force
)
$ParentPathExists = (Test-Path -Path (Split-Path $FilePath -Parent))
if($ParentPathExists)
{
Set-Content -Path $FilePath -Value $null -Force:$Force
}
elseif((-Not($ParentPathExists)) -and $Force)
{
mkdir (Split-Path $FilePath -Parent) -Force -Confirm:$false | Out-Null
Set-Content -Path $FilePath -Value $null -Confirm:$false -Force:$Force
}
else
{
Write-Error "Ensure the path `"$FilePath`" exists or use the -Force Parameter."
}
}
function getFileTime
{
Param(
[ValidateScript({Test-Path $_ -PathType Leaf})]
[String]$FilePath,
[ValidateSet("LastAccessTime","LastWriteTime","CreationTime")]
[String]$Property = "CreationTime"
)
switch ($Property)
{
'CreationTime' {(Get-ChildItem -Path $FilePath).CreationTime}
'LastAccessTime' {(Get-ChildItem -Path $FilePath).LastAccessTime}
'LastWriteTime' {(Get-ChildItem -Path $FilePath).LastWriteTime}
}
}
#endregion
#region 'Hey, wanna go on a date?'
if($Date)
{
$FileTime = $Date
}
elseif($ReferenceFile)
{
$FileTime = getFileTime -FilePath $ReferenceFile -Property:$ReferenceProperty
}
else
{
$FileTime = Get-Date
}
$updateParams = @{Date=$FileTime;Property=$Property;ErrorAction='Stop'}
#endregion
}
process
{
foreach($Path in $FilePath)
{
#http://stackoverflow.com/questions/3038337/powershell-resolve-path-that-might-not-exist
$File = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("$Path")
if(Test-Path $File)
{
if($PSCmdlet.ShouldProcess($File, "Modify File"))
{
updateFileSystemInfo -InputObject (Get-ChildItem $File) @updateParams -PassThru:$PassThru
}
}
else
{
if($PSCmdlet.ShouldProcess($File, "Create File"))
{
try
{
touchNewFile -FilePath $File -Force:$Force -ErrorAction Stop
}
catch
{
Write-Error "Ensure the path `"$FilePath`" exists or use the -Force Parameter."
break;
}
updateFileSystemInfo -InputObject (Get-ChildItem $File) @updateParams -PassThru:$PassThru
}
}
}
}
}
Set-Alias -Name touch -Value Set-File
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment