0
votes

I have found multiple code snippets to scroll through a folder and display the metadata of each item in the folder, like this:

function funLine($strIN) 
{
    $strLine = "=" * $strIn.length
    Write-Host -ForegroundColor Yellow "`n$strIN"
    Write-Host -ForegroundColor Cyan $strLine
}

$sfolder = "S:\Temp"
$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.namespace($sFolder)
foreach ($strFileName in $objFolder.items())
    {funline "$($strFileName.name)"
    for ($a ; $a  -le 266; $a++)
    { 
        $a
        if($objFolder.getDetailsOf($strFileName, $a))
        {
            $hash += @{ $($objFolder.getDetailsOf($objFolder.items, $a)) = $a.tostring() + $($objFolder.getDetailsOf($strFileName, $a)) }
            $hash | out-file c:\temp\output.txt -Append
            $hash.clear()
        }
    }
    $a=0
}

But in my script, I would like to loop through the folder(s) using Get-ChildItem and for selected files, I would like to use the getDetailsOf() to extract the authors of MS Office documents.

So, knowing the filename (example: $strFileName, can I skip the looping through each $strFileName in $objFolder.items() and just access the metadata details (where $a = 20) for the authors of $sFileName?

I have seen it done using "New-Object -ComObject word.application" but I believe that opens the document, so on a large file system with many files locked by users, this could be slow and painful.

Can I just jump to the index of $objFolder.items() for my selected filename?

2
If you know the index item of what you are looking for then just remove the loop and replace $A with the index value. I cant find the table I want but here is another question doing something very similar: stackoverflow.com/questions/25474023/…Matt

2 Answers

4
votes

Here, I was curious how it'd be done too so I looked it up and made a function that'll add that property to your [FileInfo] object (what's normally passed for a file by the Get-ChildItem cmdlet).

Function Get-CreatedBy{
[cmdletbinding()]
Param(
    [Parameter(ValueFromPipelineByPropertyName=$true)]
    [Alias("Path")]
    [string[]]$FullName
)
Begin{
    $Shell = New-Object -ComObject Shell.Application
}
Process{
    ForEach($FilePath in $FullName){
        $NameSpace = $Shell.NameSpace((Split-Path $FilePath))
        $File = $NameSpace.ParseName((Split-Path $FilePath -Leaf))
        $CreatedBy = $NameSpace.GetDetailsOf($File,20)
        [System.IO.FileInfo]$FilePath|Add-Member 'CreatedBy' $CreatedBy -PassThru
    }
}
}

Then you can just pipe things to that, or specify a path directly like:

Get-ChildItem *.docx | Get-CreatedBy | FT Name,CreatedBy

or

Get-CreatedBy 'C:\Temp\File.docx' | Select -Expand CreatedBy

Edit: Fixed for arrays of files! Sorry about the previous error.

2
votes

Thanks Matt! Although that question was different, it had the one piece I was looking for - how to reference $objFolder.items().item($_.Name)

So this makes a quick little snippet to display the Authors (or any other metadata field):

$FullName = "S:\Temp\filename.xlsx"

$Folder = Split-Path $FullName
$File = Split-Path $FullName -Leaf

$objShell = New-Object -ComObject Shell.Application
$objFolder = $objShell.namespace($Folder)

$Item = $objFolder.items().item($File)
$Author = $objFolder.getDetailsOf($Item, 20)

Write-Host "$FullName is owned by $Author"

Where Author is the 20th metadata item.