bwerks
bwerks

Reputation: 9001

Powershell: NTFS paths in file metadata with New-ItemProperty, Set-ItemProperty?

I'm interested in adding a property to my files under a certain scope that contains their current locations in my file system, in order to track file movement. I would think that this could be done with New-ItemProperty, with a command similar to the following:

Get-ChildItem -recurse | foreach { New-ItemProperty -Path $.FullName -Name "OriginalLocation" -PropertyType string -Value $.FullName }

However, when I try this, I'm spammed with the following error:

New-ItemProperty : Cannot use interface. The IDynamicPropertyCmdletProvider interface is not implemented by this provider.

After some searching, it appears that New-ItemProperty is all but useless except for working with the registry. Fine. Windows has myriad other file properties I should be able to hijack in order to get this done. "Label" and "Tags" come to mind. So let's try setting those via Set-ItemProperty instead.

Set-ItemProperty : Property System.String Label=D:\test\file.txt does not exist.

It appears I need to create these properties after all. Is this a shortcoming of New-ItemProperty? Maybe setting properties such as this on arbitrary items is some WMI thing I don't know about?

Upvotes: 1

Views: 1833

Answers (2)

JPBlanc
JPBlanc

Reputation: 72670

Here is my solution using the redirections ('<' & '>') that allow to manipulate alternate data stream in CMD.EXE. It works in Powershell without any extentions

# AlternateDataStream.ps1

$scriptBlockSetStream = {cmd /C `"echo $($Args[0])`>$($Args[1]):$($Args[2])`"}
$scriptBlockGetStream = {cmd /C `"more `<$($Args[0]):$($Args[1])`"}

$streamName = "NativeFilePath"
$File = "C:\Temp\ADSTest\toto.txt"
$streamContent = Split-Path -Path $File -Parent

# Set the data stream
Invoke-Command -ScriptBlock $scriptBlockSetStream  -ArgumentList $streamContent,$File,$streamName
# Get the Data Stream
$res = Invoke-Command -ScriptBlock $scriptBlockGetStream  -ArgumentList $File,$streamName
$res

Upvotes: 3

David Brabant
David Brabant

Reputation: 43539

Another option might be to use alternate data streams to store your path. If you are running PowerShell 3.0, you can manipulate them quite easily. Based on the first article, you would have something resembling:

"echo test" | out-file c:\powershell\test.ps1                                                                                         

$fs = new NTFS.FileStreams('c:\powershell\test.ps1')                                                                                  
$fs.add('OriginalPath')                                                                                                                  

$stream = $fs.Item('OriginalPath').open()                                                                                                
$sw = [System.IO.streamwriter]$stream                                                                                                 
$sw.writeline('<path>')                                                                                                  
$sw.close()                                                                                                                           
$stream.close()                                                                                                                       

Upvotes: 1

Related Questions