windows - 是否有用于收集超过 260 个字符的时间戳的 robocopy 开关?
问题描述
我正在尝试从 Windows 目录中的文件中提取上次修改的日期。这是我的基本脚本:
Function Get-FolderItem {
[cmdletbinding(DefaultParameterSetName='Filter')]
Param (
[parameter(Position=0,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
[Alias('FullName')]
[string[]]$Path = $PWD,
[parameter(ParameterSetName='Filter')]
[string[]]$Filter = '*.*',
[parameter(ParameterSetName='Exclude')]
[string[]]$ExcludeFile,
[parameter()]
[int]$MaxAge,
[parameter()]
[int]$MinAge
)
Begin {
$params = New-Object System.Collections.Arraylist
$params.AddRange(@("/L","/E","/NJH","/NDL","/BYTES","/FP","/NC","/XJ","/R:0","/W:0","T:W","/TS","/UNILOG:c:\temp\test.txt"))
#params.AddRange(@("/L","/S","/NJH","/BYTES","/FP","/NC","/NDL","/TS","/XJ","/R:0","/W:0"))
If ($PSBoundParameters['MaxAge']) {
$params.Add("/MaxAge:$MaxAge") | Out-Null
}
If ($PSBoundParameters['MinAge']) {
$params.Add("/MinAge:$MinAge") | Out-Null
}
}
Process {
ForEach ($item in $Path) {
Try {
$item = (Resolve-Path -LiteralPath $item -ErrorAction Stop).ProviderPath
If (-Not (Test-Path -LiteralPath $item -Type Container -ErrorAction Stop)) {
Write-Warning ("{0} is not a directory and will be skipped" -f $item)
Return
}
If ($PSBoundParameters['ExcludeFile']) {
$Script = "robocopy `"$item`" NULL $Filter $params /XF $($ExcludeFile -join ',')"
} Else {
$Script = "robocopy `"$item`" NULL $Filter $params"
}
Write-Verbose ("Scanning {0}" -f $item)
Invoke-Expression $Script | Out-Null
get-content "c:\temp\test.txt" | ForEach {
Try {
If ($_.Trim() -match "^(?<Children>\d+)\s(?<FullName>.*)") {
$object = New-Object PSObject -Property @{
FullName = $matches.FullName
Extension = $matches.fullname -replace '.*\.(.*)','$1'
FullPathLength = [int] $matches.FullName.Length
FileHash = Get-FileHash -LiteralPath "\\?\$($matches.FullName)" |Select -Expand Hash
Created = ([System.IO.FileInfo] $matches.FullName).creationtime
LastWriteTime = ([System.IO.FileInfo] $matches.FullName).LastWriteTime
Characters = (Get-Content -LiteralPath "\\?\$($matches.FullName)" | Measure-Object -ignorewhitespace -Character).Characters
Owner = (Get-ACL $matches.Fullname).Owner
}
$object.pstypenames.insert(0,'System.IO.RobocopyDirectoryInfo')
Write-Output $object
} Else {
Write-Verbose ("Not matched: {0}" -f $_)
}
} Catch {
Write-Warning ("{0}" -f $_.Exception.Message)
Return
}
}
} Catch {
Write-Warning ("{0}" -f $_.Exception.Message)
Return
}
}
}
}
$a = Get-FolderItem "C:\TargetDirectory\Folder" | Export-Csv -Path C:\Temp\output.csv -Encoding Unicode
该脚本提取少于 260 个字符的文件路径的最后修改日期。对于长度超过 260 个字符的文件,它将返回1600-12-31 4:00:00 PM的无意义日期。这是不起作用的行:
LastWriteTime = ([System.IO.FileInfo] $matches.FullName).LastWriteTime
我第一次尝试解决这个问题是找到一个以Get-开头的命令,因为这样的命令在提取文件哈希、文件路径、字符数和超过 260 个字符的文件的所有者名称时很有用。例如:
Owner = (Get-ACL $matches.Fullname).Owner
Characters = (Get-Content -LiteralPath "\\?\$($matches.FullName)" | Measure-Object-ignorewhitespace -Character).Characters
FileHash = Get-FileHash -LiteralPath "\\?\$($matches.FullName)" |Select -Expand Hash
Get-Date
但是似乎是关于获取当前日期。
在我的第二次尝试中,我回到了 Boe Prox 关于这个脚本的原始博客文章,并注意到他的脚本有两个我的脚本中缺少的组件:
robocopy 开关
/TS
Date = [datetime]$matches.Date
我添加到我的脚本中,但是这样做会返回一个错误:WARNING: Cannot convert null to type "System.DateTime".
我重新检查了目录中的文件,它显然有一个日期。
我重新检查了Get-Date上的文档并尝试了
Date = Get-Date -Format o | ForEach-Object { $matches -replace ":", "." }
然而,这返回WARNING: Cannot convert value "2018/03/05 18:06:54 C:TargetDirectory\Folder\Temp.csv to type "System.IO.FileInfo". Error: " Illegal characters in path."
(注意在其他帖子中,人们建议更改服务器设置以允许存在超过 260 个字符的文件。这对我来说不是一个选项,因为我无权访问服务器。)
解决方案
一旦你在路径中达到 260 个字符,你就达到了旧的Windows MAX_PATH 限制。为了解决这个问题,您必须在路径前添加\\?\
.
在上面的代码中,您这样做是为了Characters
,FileHash
但在检索LastWriteTime
. 例如,更改此路径将起作用:
Created = ([System.IO.FileInfo] "\\?\$($matches.FullName)").creationtime
LastWriteTime = ([System.IO.FileInfo] "\\?\$($matches.FullName)").LastWriteTime
另一种方法是使用Get-ChildItem
cmdlet 以及\\?\
附加到路径来检索您想要的大部分字段,而无需多次查询:
get-content "c:\temp\test.txt" | ForEach {
Try {
If ($_.Trim() -match "^(?<Children>\d+)\s(?<FullName>.*)") {
$file = Get-ChildItem "\\?\$($matches.FullName)"
$object = New-Object PSObject -Property @{
FullName = $file.FullName
Extension = $file.Extension
FullPathLength = $file.FullName.Length
FileHash = Get-FileHash -LiteralPath "\\?\$($matches.FullName)" |Select -Expand Hash
Created = $file.CreationTime
LastWriteTime = $file.LastWriteTime
Characters = (Get-Content -LiteralPath "\\?\$($matches.FullName)" | Measure-Object -ignorewhitespace -Character).Characters
Owner = (Get-ACL $matches.Fullname).Owner
}
$object.pstypenames.insert(0,'System.IO.RobocopyDirectoryInfo')
Write-Output $object
} Else {
Write-Verbose ("Not matched: {0}" -f $_)
}
} Catch {
Write-Warning ("{0}" -f $_.Exception.Message)
Return
}
}
推荐阅读
- elasticsearch - 如何仅返回嵌套字段中的匹配对象,而不是整个对象?
- css - REACT-IconButton 在 flexlayout 中不可见
- angularjs - 为什么 URL 在单独执行而不是在 forkJoin 中时给出响应?
- c# - 当我键入`@`时如何制作一个文本框光标自动转到文本框的开头C#
- python - 登录ubuntu之前如何在python守护进程中使用DBUS
- swift - iOS 14 Widget 每天自动刷新
- sql - 如何避免收到消息 ORA-00979:不是 GROUP BY 表达式
- complex-event-processing - Esper / NEsper EPL 事件声明
- javascript - 解禁命令 Discord.js V12
- react-native - 反应本机导航 v5 导航选项卡在底部栏内