在 powershell 中处理哈希 table
process a hash table in powershell
我想要一个 Powershell 脚本来告诉我特定目录中每个文件版本的最新版本。文件名由基本名称和时间戳构成
例如StaffTS2016_20220308010543.7z
StaffTS2016 是我感兴趣的基本名称。时间戳可以丢弃,因为我指的是文件系统中的 LastAccessTime。我想知道 StaffTS2016 的最新版本:可以多次出现具有此基本名称的文件。我想知道目录中每个基本名称的最新年龄。这篇 SO 文章让我走到了那里
$strDays = @{l="Days";e={((Get-Date) - $_.LastAccessTime).Days}}
$path = "D:\HVBackup\VP20"
$output1 = Get-ChildItem $path -File | Select-Object Name, $strDays | Out-String
Name
Days
StaffTS2016_20220308010543.7z
8
StaffTS2016_20220314231747.7z
1
vc2012R2DC1_20220308022625.7z
4
vc2012R2DC1_20220314230635.7z
2
vcApache_20220308023655.7z
5
vcApache_20220314235915.7z
1
vcEX1a2012_20220307230943.7z
8
vcSQL2016_20220308014925.7z
8
vcSQL2016_20220314223040.7z
1
我无法弄清楚如何处理生成的散列 table,要么直接通过扩展管道,要么通过 post 处理来导出我想要的信息。
如您所见,我的散列 table 有两个字段,Name 和 Days。从 $.Name 我想将 BaseName 提取为 $.Name.split('_')[0]。然后,如果输出 table 中不存在 BaseName,我想将 (BaseName, Days) 添加到我的输出 table 中,如果存在并且新的天数较低,则将天数更新为较低的值。我可以用其他语言做到这一点,但不能用 Powershell。
期望的输出是
Name
Days
StaffTS2016
1
vc2012R2DC1
2
vcApache
1
vcEX1a2012
8
vcSQL2016
1
这一眼就能告诉我备份 vcEX1a2012 时出现问题
顾名思义,Out-String
将 Get-ChildItem ... | Select ...
的输出转换为 字符串 ( 不是 哈希表),这无疑使数据处理起来很麻烦。
相反,首先根据名称的第一部分将文件分组在一起,然后根据时间戳对每组中的文件进行排序:
# prepare calculated property selectors for both the name and the days for later
$selectors = @(
@{Label="Days"; Expression = {((Get-Date) - $_.LastAccessTime).Days}}
@{Label="Name"; Expression = { $_.BaseName.Split('_')[0] }}
)
# discover the files
$path = "D:\HVBackup\VP20"
$files = Get-ChildItem $path -File
# group the files by the first part of their base name
$files |Group-Object { $_.BaseName.Split('_')[0] } |ForEach-Object {
# then pick only the newest from each, based on the timestamp part of the name
$_.Group |Sort-Object { $_.BaseName.Split('_')[-1] } -Descending |Select-Object -First 1 -Property $selectors
}
你可以把最后一个命令改成这样
$output1 = Get-ChildItem $path -File | Select-Object Name, $strDays |
ForEach-Object { $_.Name = $_.Name.split('_')[0]; $_ } |
Group-Object -Property Name |
ForEach-Object { $_.Group | Sort-Object -Property Days | Select-Object -First 1 }
Group-Object
允许您将每个文件与具有相同名称的文件进行比较,这些文件在前面的 ForEach-Object
中设置为 $_.Name.split('_')[0]
,如您指定的那样。
我想要一个 Powershell 脚本来告诉我特定目录中每个文件版本的最新版本。文件名由基本名称和时间戳构成
例如StaffTS2016_20220308010543.7z
StaffTS2016 是我感兴趣的基本名称。时间戳可以丢弃,因为我指的是文件系统中的 LastAccessTime。我想知道 StaffTS2016 的最新版本:可以多次出现具有此基本名称的文件。我想知道目录中每个基本名称的最新年龄。这篇 SO 文章让我走到了那里
$strDays = @{l="Days";e={((Get-Date) - $_.LastAccessTime).Days}}
$path = "D:\HVBackup\VP20"
$output1 = Get-ChildItem $path -File | Select-Object Name, $strDays | Out-String
Name | Days |
---|---|
StaffTS2016_20220308010543.7z | 8 |
StaffTS2016_20220314231747.7z | 1 |
vc2012R2DC1_20220308022625.7z | 4 |
vc2012R2DC1_20220314230635.7z | 2 |
vcApache_20220308023655.7z | 5 |
vcApache_20220314235915.7z | 1 |
vcEX1a2012_20220307230943.7z | 8 |
vcSQL2016_20220308014925.7z | 8 |
vcSQL2016_20220314223040.7z | 1 |
我无法弄清楚如何处理生成的散列 table,要么直接通过扩展管道,要么通过 post 处理来导出我想要的信息。
如您所见,我的散列 table 有两个字段,Name 和 Days。从 $.Name 我想将 BaseName 提取为 $.Name.split('_')[0]。然后,如果输出 table 中不存在 BaseName,我想将 (BaseName, Days) 添加到我的输出 table 中,如果存在并且新的天数较低,则将天数更新为较低的值。我可以用其他语言做到这一点,但不能用 Powershell。
期望的输出是
Name | Days |
---|---|
StaffTS2016 | 1 |
vc2012R2DC1 | 2 |
vcApache | 1 |
vcEX1a2012 | 8 |
vcSQL2016 | 1 |
这一眼就能告诉我备份 vcEX1a2012 时出现问题
顾名思义,Out-String
将 Get-ChildItem ... | Select ...
的输出转换为 字符串 ( 不是 哈希表),这无疑使数据处理起来很麻烦。
相反,首先根据名称的第一部分将文件分组在一起,然后根据时间戳对每组中的文件进行排序:
# prepare calculated property selectors for both the name and the days for later
$selectors = @(
@{Label="Days"; Expression = {((Get-Date) - $_.LastAccessTime).Days}}
@{Label="Name"; Expression = { $_.BaseName.Split('_')[0] }}
)
# discover the files
$path = "D:\HVBackup\VP20"
$files = Get-ChildItem $path -File
# group the files by the first part of their base name
$files |Group-Object { $_.BaseName.Split('_')[0] } |ForEach-Object {
# then pick only the newest from each, based on the timestamp part of the name
$_.Group |Sort-Object { $_.BaseName.Split('_')[-1] } -Descending |Select-Object -First 1 -Property $selectors
}
你可以把最后一个命令改成这样
$output1 = Get-ChildItem $path -File | Select-Object Name, $strDays |
ForEach-Object { $_.Name = $_.Name.split('_')[0]; $_ } |
Group-Object -Property Name |
ForEach-Object { $_.Group | Sort-Object -Property Days | Select-Object -First 1 }
Group-Object
允许您将每个文件与具有相同名称的文件进行比较,这些文件在前面的 ForEach-Object
中设置为 $_.Name.split('_')[0]
,如您指定的那样。