英文:
Variable for "Media created"? (Powershell)
问题
"Media created" 变量在Powershell中是什么?
我正在尝试一次性更改文件夹中的许多.mov文件的名称,将它们从"IMG-3523"更改为它们各自的创建日期。
我以前使用以下代码来执行此操作,使用 LastWriteTime
:
Get-ChildItem | Rename-Item -NewName {$_.LastWriteTime.ToString("yyyy-MM-dd hh.mm.ss ddd") + ($_.Extension)}
但出现了许多重复条目的原因,我遇到了错误提示。
有没有办法修改这段代码以使用"Media created"变量?这是唯一没有重复的日期。
(我尝试过编辑代码以包括微秒和$_.CreationTime
,但该变量也有许多重复项(实际上所有的CreationTime都相同 - 当我从外部磁盘复制文件时的时间戳)。)
英文:
What is the variable for "Media created", using Powershell?
I'm trying to change many .mov files at one time, in a folder, from "IMG-3523" to their respective creation dates.
I was using the following code to do so, using LastWriteTime
:
Get-ChildItem | Rename-Item -NewName {$_.LastWriteTime.ToString("yyyy-MM-dd hh.mm.ss ddd") + ($_.Extension)}
However for some reason there are many duplicate entries for that variable, and I run into an error stating so.
Is there any way I can edit this code to use the "Media created" variable? It's the only date without duplicates.
(I've tried editing the code to include microseconds and $_.CreationTime
, however there are many duplicates with that variable too (actually all have the same CreationTime - the timestamp of when I copied the files over from an external disk).
答案1
得分: 1
以下是代码的翻译部分:
对于目录中的所有文件:
$fldPath = "D:\FolderName";
$flExt = ".mov";
$attrName = "media created"
(Get-ChildItem -Path "$fldPath\*" -Include "*$flExt").FullName | % {
$path = $_
$shell = New-Object -COMObject Shell.Application;
$folder = Split-Path $path;
$file = Split-Path $path -Leaf;
$shellfolder = $shell.Namespace($folder);
$shellfile = $shellfolder.ParseName($file);
$a = 0..500 | % { Process { $x = '{0} = {1}' -f $_, $shellfolder.GetDetailsOf($null, $_); If ( $x.split("=")[1].Trim() ) { $x } } };
[int]$num = $a | % { Process { If ($_ -like "*$attrName*") { $_.Split("=")[0].trim() } } };
$mCreated = $shellfolder.GetDetailsOf($shellfile, $num);
$mCreated;
};
对于特定文件,您可以使用:
$flPath = "D:\FolderName\FileName.mov";
$attrName = "media created";
$path = $flPath;
$shell = New-Object -COMObject Shell.Application;
$folder = Split-Path $path;
$file = Split-Path $path -Leaf;
$shellfolder = $shell.Namespace($folder);
$shellfile = $shellfolder.ParseName($file);
$a = 0..500 | % { Process { $x = '{0} = {1}' -f $_, $shellfolder.GetDetailsOf($null, $_); If ( $x.split("=")[1].Trim() ) { $x } } };
[int]$num = $a | % { Process { If ($_ -like "*$attrName*") { $_.Split("=")[0].trim() } } };
$mCreated = $shellfolder.GetDetailsOf($shellfile, $num);
$mCreated;
希望这对您有所帮助。
英文:
For all files within a directory:
$fldPath = "D:\FolderName";
$flExt = ".mov";
$attrName = "media created"
(Get-ChildItem -Path "$fldPath\*" -Include "*$flExt").FullName | % {
$path = $_
$shell = New-Object -COMObject Shell.Application;
$folder = Split-Path $path;
$file = Split-Path $path -Leaf;
$shellfolder = $shell.Namespace($folder);
$shellfile = $shellfolder.ParseName($file);
$a = 0..500 | % { Process { $x = '{0} = {1}' -f $_, $shellfolder.GetDetailsOf($null, $_); If ( $x.split("=")[1].Trim() ) { $x } } };
[int]$num = $a | % { Process { If ($_ -like "*$attrName*") { $_.Split("=")[0].trim() } } };
$mCreated = $shellfolder.GetDetailsOf($shellfile, $num);
$mCreated;
};
For one specific File, you can use:
$flPath = "D:\FolderName\FileName.mov";
$attrName = "media created"
$path = $flPath;
$shell = New-Object -COMObject Shell.Application;
$folder = Split-Path $path;
$file = Split-Path $path -Leaf;
$shellfolder = $shell.Namespace($folder);
$shellfile = $shellfolder.ParseName($file);
$a = 0..500 | % { Process { $x = '{0} = {1}' -f $_, $shellfolder.GetDetailsOf($null, $_); If ( $x.split("=")[1].Trim() ) { $x } } };
[int]$num = $a | % { Process { If ($_ -like "*$attrName*") { $_.Split("=")[0].trim() } } };
$mCreated = $shellfolder.GetDetailsOf($shellfile, $num);
$mCreated;
This was answered in SuperUser by vomit-it-chunky-mess-style on Getting a Media Created via PS
答案2
得分: 1
以下是您要翻译的内容:
"Media created"属性可能在.mov文件中也可能是多个,或在许多情况下未定义,使用它可能会导致文件名重复,甚至出现错误。我建议采用另一种方法,首先检查"Media created"和"Date taken"的存在性,如果不存在,则保持使用"$_.LastWriteTime"作为基本文件名,如果有重复,则添加一个数字,如下所示:
#
# fnc001: 获取文件的媒体创建时间、拍摄时间或最后写入时间:
#
function entGetMediaCreatedOrLastWriteTime($objFile) {
$idxMediaCreated = 208
$objShell = New-Object -COMObject Shell.Application
$objShellFolder = $objShell.NameSpace($objFile.DirectoryName)
$iState = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objShell)
$objShellFile = $objShellFolder.ParseName($objFile.Name)
$mediaCreated = $objShellFolder.GetDetailsOf($objShellFile, $idxMediaCreated)
#
# 如果媒体创建时间为空,我们检查是否有拍摄时间:
#
if($mediaCreated -eq "") {
#
# 佳能相机设置照片的拍摄时间:
#
$idxDateTaken = 12
$dateTaken = $objShellFolder.GetDetailsOf($objShellFile, $idxDateTaken)
#
# 如果既没有媒体创建时间,也没有拍摄时间,则返回最后写入时间:
#
if($dateTaken -eq "") {
return $objFile.LastWriteTime
}
#
# 否则返回拍摄时间,删除非ASCII字符:
#
else
{
return [DateTime]($dateTaken -replace '\P{IsBasicLatin}')
}
}
#
# 否则返回有效的媒体创建时间,删除非ASCII字符:
#
else {
return [DateTime]($mediaCreated -replace '\P{IsBasicLatin}')
}
}
#
# fnc001: 如果文件名已存在,则增加文件名:
#
function entIncrementIfExistent($filename) {
$fnew = $filename
$ext = Split-Path $filename -Extension
#
# 定义文件号前缀:
#
$prefix = "-"
$i = 0
#
# 保存文件基本长度:
#
$lngbase = $fnew.length - $ext.length
#
# 在这里,$filename的格式如下:
# 2023-02-05 08.33.00 Sun.mov
#
# 如果已经存在,我们尝试使用以下可用的文件名之一:
#
# 2023-02-05 08.33.00 Sun-1.mov
# 2023-02-05 08.33.00 Sun-2.mov
# ...
# 2023-02-05 08.33.00 Sun-9.mov
# ...
# 2023-02-05 08.33.00 Sun-10.mov
# 2023-02-05 08.33.00 Sun-11.mov
# ...
#
while (Test-Path $fnew)
{
$i++
$fnew = $fnew.Substring(0, $lngbase) + $prefix + $i + $ext
}
return $fnew
}
Get-ChildItem *.mov | Rename-Item -NewName {
$xDateTime = entGetMediaCreatedOrLastWriteTime $_
$fnew = $xDateTime.ToString("yyyy-MM-dd hh.mm.ss ddd") + $_.Extension
entIncrementIfExistent $fnew
}
我已为您翻译了代码部分。如果您需要进一步的帮助,请随时告诉我。
英文:
As "Media created
" property of a .mov file might also be multiple, or undefined in many cases, use it may cause also file name duplication, even error.
I'd propose another approach, we first check existence of both "Media created
" and "Date taken
", if nonexistent, we keep using $_.LastWriteTime
as basic file name, adding a number to each file name if duplicated, like this:
<pre><code>
fnc001: get file media created, date taken or LastWriteTime:
function entGetMediaCreatedOrLastWriteTime($objFile) {
$idxMediaCreated = 208
$objShell = New-Object -COMObject Shell.Application
$objShellFolder = $objShell.NameSpace($objFile.DirectoryName)
$iState = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objShell)
$objShellFile = $objShellFolder.ParseName($objFile.Name)
$mediaCreated = $objShellFolder.GetDetailsOf($objShellFile, $idxMediaCreated)
if media created is empty, we check if we have Date taken:
if($mediaCreated -eq "") {
#
# canon cameras set Date taken for photos:
#
$idxDateTaken = 12
$dateTaken = $objShellFolder.GetDetailsOf($objShellFile, $idxDateTaken)
#
# return LastWriteTime if neither media created, nor Date taken:
#
if($dateTaken -eq "") {
return $objFile.LastWriteTime
}
#
# otherwise return Date taken, removing non-ascii before:
#
else
{
return [DateTime]($dateTaken -replace '\P{IsBasicLatin}')
}
}
otherwise return valid media created, removing non-ascii before:
else {
return [DateTime]($mediaCreated -replace '\P{IsBasicLatin}')
}
}
fnc001: increment filename if it already exists:
function entIncrementIfExistent($filename) {
$fnew = $filename
$ext = Split-Path $filename -Extension
define prefix before file number:
$prefix = "-"
$i = 0
save file base length:
$lngbase = $fnew.length - $ext.length
here $filename is like
2023-02-05 08.33.00 Sun.mov,
if it exists, we try to use first available of:
2023-02-05 08.33.00 Sun-1.mov
2023-02-05 08.33.00 Sun-2.mov
...
2023-02-05 08.33.00 Sun-9.mov
...
2023-02-05 08.33.00 Sun-10.mov
2023-02-05 08.33.00 Sun-11.mov
...
while (Test-Path $fnew)
{
$i++
$fnew = $fnew.Substring(0, $lngbase) + $prefix + $i + $ext
}
return $fnew
}
Get-ChildItem *.mov | Rename-Item -NewName {
$xDateTime = entGetMediaCreatedOrLastWriteTime $_
$fnew = $xDateTime.ToString("yyyy-MM-dd hh.mm.ss ddd") + $_.Extension
entIncrementIfExistent $fnew
}
</code></pre>
I've tried this code, it gets something like this:
答案3
得分: 1
使用Shell.Application
对象,您可以从文件中获取此值,但不幸的是,属性名称都是本地化的,因此如果您在非英语的机器上寻找名为Media created
的属性,您将找不到它。
对于.MOV文件,此属性的索引编号为4。
您可以使用下面的函数获取路径中所有文件的该值,然后使用它来重命名它们:
function Get-MetaData {
[CmdletBinding()]
[OutputType([Psobject[]])]
Param (
# 路径可以是文件夹的路径或单个文件的完整路径和文件名
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[string]$Path,
# 如果路径指向单个文件,则未使用筛选器
[Alias('Pattern')]
[string]$Filter = '*.*',
[Alias('Indices')]
[int[]]$Properties = 1..500,
# 如果路径指向单个文件,则未使用递归
[switch]$Recurse,
[switch]$IncludeEmptyProperties
)
$item = Get-Item -Path $Path -ErrorAction SilentlyContinue
if (!$item) { Write-Error "$Path could not be found."; return }
if (!$item.PSIsContainer) {
# 这是一个文件
$files = @($item)
$Path = $item.DirectoryName
}
else {
# 这是一个文件夹
$files = Get-ChildItem -Path $Path -Filter $Filter -File -Recurse:$Recurse
}
$shell = New-Object -ComObject "Shell.Application"
$objDir = $shell.NameSpace($Path)
foreach($file in $files) {
$objFile = $objDir.ParseName($file.Name)
$mediaFile = $objDir.Items()
foreach($index in $Properties) {
$name = $objDir.GetDetailsOf($mediaFile, $index)
if (![string]::IsNullOrWhiteSpace($name)) {
# 为了安全起见,删除其中可能存在的任何控制字符(ASCII < 32)
$value = $objDir.GetDetailsOf($objFile, $index) -replace '[\x00-\x1F]+'
if (![string]::IsNullOrWhiteSpace($value) -or $IncludeEmptyProperties) {
[PsCustomObject]@{
Path = $file.FullName
Index = $index
Property = $name
Value = $value
}
}
}
}
}
# 清理Com对象
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objFile)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objDir)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
# 属性索引 3 --> 最后修改
# 属性索引 4 --> 创建日期 # 我们将使用这个
# 属性索引 5 --> 最后访问
$SourceFolder = 'X:\Somewhere'
Get-MetaData -Path $SourceFolder -Filter '*.mov' -Properties 4 |
ForEach-Object {
# HH 表示24小时制; hh 表示12小时制
$dateCreated = '{0:yyyy-MM-dd HH.mm.ss ddd}' -f ([datetime]$_.Value)
$directory = [System.IO.Path]::GetDirectoryName($_.Path)
$extension = [System.IO.Path]::GetExtension($_.Path)
# 测试建议的新名称是否已经在使用中,如果是,附加一个序列号到基本名称,直到我们有一个唯一的名称
$newName = '{0}{1}' -f $dateCreated, $extension
$index = 1
while (Test-Path -Path (Join-Path -Path $directory -ChildPath $newName) -PathType Leaf) {
$newName = '{0}({1}){2}' -f $dateCreated, $index++, $extension
}
Rename-Item -Path $_.Path -NewName $newName -WhatIf
}
-WhatIf
是一种安全措施。它只会在控制台中显示代码将发生的操作,不会实际重命名文件。
如果您确信输出是正确的,请删除-WhatIf
开关,然后再次运行代码。
英文:
Using the Shell.Application
object you can get this value from the file, but unfortunately, the property names are all Localized, so if you are looking for a property named Media created
on a non-english machine, you will not find it..
For .MOV files, the index of this property in numbered 4.
You can use below function to get that value for all the files in the path and then use that to rename them:
function Get-MetaData {
[CmdletBinding()]
[OutputType([Psobject[]])]
Param (
# Path can be the path to a folder or the full path and filename of a single file
[Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
[string]$Path,
# Filter is unused if Path is pointing to a single file
[Alias('Pattern')]
[string]$Filter = '*.*',
[Alias('Indices')]
[int[]]$Properties = 1..500,
# Recurse is unused if Path is pointing to a single file
[switch]$Recurse,
[switch]$IncludeEmptyProperties
)
$item = Get-Item -Path $Path -ErrorAction SilentlyContinue
if (!$item) { Write-Error "$Path could not be found."; return }
if (!$item.PSIsContainer) {
# it's a file
$files = @($item)
$Path = $item.DirectoryName
}
else {
# it's a folder
$files = Get-ChildItem -Path $Path -Filter $Filter -File -Recurse:$Recurse
}
$shell = New-Object -ComObject "Shell.Application"
$objDir = $shell.NameSpace($Path)
foreach($file in $files) {
$objFile = $objDir.ParseName($file.Name)
$mediaFile = $objDir.Items()
foreach($index in $Properties) {
$name = $objDir.GetDetailsOf($mediaFile, $index)
if (![string]::IsNullOrWhiteSpace($name)) {
# to be on the safe side, remove any control character (ASCII < 32) that may be in there
$value = $objDir.GetDetailsOf($objFile, $index) -replace '[\x00-\x1F]+'
if (![string]::IsNullOrWhiteSpace($value) -or $IncludeEmptyProperties) {
[PsCustomObject]@{
Path = $file.FullName
Index = $index
Property = $name
Value = $value
}
}
}
}
}
# clean-up Com objects
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objFile)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objDir)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
# property index 3 --> Last Modified
# property index 4 --> Date Created # we'll use this one
# property index 5 --> Last Accessed
$SourceFolder = 'X:\Somewhere'
Get-MetaData -Path $SourceFolder -Filter '*.mov' -Properties 4 |
ForEach-Object {
# HH for 24-hour clock; hh for 12-hour clock
$dateCreated = '{0:yyyy-MM-dd HH.mm.ss ddd}' -f ([datetime]$_.Value)
$directory = [System.IO.Path]::GetDirectoryName($_.Path)
$extension = [System.IO.Path]::GetExtension($_.Path)
# test if the suggested new name is already in use, append a sequence
# number to the basename until we have a unique name
$newName = '{0}{1}' -f $dateCreated, $extension
$index = 1
while (Test-Path -Path (Join-Path -Path $directory -ChildPath $newName) -PathType Leaf) {
$newName = '{0}({1}){2}' -f $dateCreated, $index++, $extension
}
Rename-Item -Path $_.Path -NewName $newName -WhatIf
}
The -WhatIf
is a safety measure. It will make the code only show in the console what would happen. No file is actually renamed.
If you are convinced that output is correct, then remove the -WhatIf
switch and run the code again
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论