Skip to content

Instantly share code, notes, and snippets.

@jborean93
Created February 1, 2021 04:12
Show Gist options
  • Save jborean93/b5eba78e736e035b28e51f086390fa14 to your computer and use it in GitHub Desktop.
Save jborean93/b5eba78e736e035b28e51f086390fa14 to your computer and use it in GitHub Desktop.
Get Windows Explorer metadata properties
# Copyright: (c) 2021, Jordan Borean (@jborean93) <[email protected]>
# MIT License (see LICENSE or https://opensource.org/licenses/MIT)
Update-TypeData -TypeName 'Shell.Metadata' -DefaultDisplayPropertySet 'Name', 'Item type' -Force
Function Get-ItemMetadata {
<#
.SYNOPSIS
Get shell explorer metadata for a file.
.DESCRIPTION
Get the metadata for for file or directory. Outputs a PSObject with properties relating to the localised file
metadata properties as seen by Windows Explorer.
.PARAMETER Path
The list of paths to get the metadata for, can include wildcards.
.PARAMETER LiteralPath
The list of literal paths to get the metadata for.
.NOTES
Uses the 'Shell.Application' COM object
#>
[CmdletBinding(DefaultParameterSetName='Path')]
[OutputType('Shell.Metadata')]
param (
[Parameter(
Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
ParameterSetName = 'Path'
)]
[SupportsWildcards()]
[ValidateNotNullOrEmpty()]
[String[]]
$Path,
[Parameter(
Mandatory = $true,
Position = 0,
ValueFromPipelineByPropertyName = $true,
ParameterSetName = 'LiteralPath'
)]
[Alias('PSPath')]
[ValidateNotNullOrEmpty()]
[String[]]
$LiteralPath
)
begin {
$shell = New-Object -ComObject Shell.Application
}
process {
if ($PSCmdlet.ParameterSetName -eq 'Path') {
$allPaths = $Path | ForEach-Object -Process {
$provider = $null
$PSCmdlet.SessionState.Path.GetResolvedProviderPathFromPSPath($_, [ref]$provider)
}
}
elseif ($PSCmdlet.ParameterSetName -eq 'LiteralPath') {
$allPaths = $LiteralPath | ForEach-Object -Process {
$PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($_)
}
}
foreach ($filePath in $allPaths) {
if (-not (Test-Path -LiteralPath $filePath)) {
Write-Error -Message "Failed to find path $filePath" -Category ObjectNotFound
continue
}
$shellFolder = $shell.Namespace((Split-Path -Path $filePath -Parent))
$shellFile = $shellFolder.ParseName((Split-Path -Path $filePath -Leaf))
$metadata = [Ordered]@{
PSTypeName = 'Shell.Metadata'
FullName = $filePath
}
$metaId = 0
while ($true) {
$metaName = $shellFolder.GetDetailsOf($null, $metaId)
if ($metaName) {
$metaValue = $shellFolder.GetDetailsOf($ShellFile, $metaId)
$metadata.$metaName = $metaValue
}
elseif ($metaId -gt 300) {
# Don't know of a way to figure out the max number, I know that ~300 is around the max so just
# break the loop if the name is null and the id is >300.
break
}
$metaId += 1
}
[PSCustomObject]$metadata
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment