Thursday, January 5, 2012

Powershell (v2) - Using Pipelined Collection to Move Files

Problem: can I move files as a collection (that is, a variable) without enumerating over the collection?

Quick answer: Yes. Pass the collection (or pipelined set of commands) to Move-Item -Destination $destination.

Long answer: To do some automated file clean up I got it in my head to research whether passing collections to Remote-Item via the pipeline would work.  I started by posting on the Technet forums
Is there a way to use Move-Item without using foreach on a collection?
to see if I did this whether it would work or not.  As I posted in the forum,
The idea that came to mind is something like this (being hypothetical here):
$files = Get-ChildItem .\somedir\* | Where {$_.PSIsNotContainer -ne $true}
Move-Item $files $destination
At present, the only way I can think of doing this is:
$files | % {Move $_.fullname $destination}
The real concept I had in mind was being able to pass an object which contained a collection, and, having the cmdlet work on that object instead of having to hook up iteration.
Kazun replied with this sample to illustrate how the pipelined object could be handled by Move-Item without any issues:
Get-ChildItem .\somedir | Where {!$_.PSIsNotContainer} | Move-Item -Destination $destination 
Not sure whether he got what I was going after I came up with my own sample code to test both paths,
Get-ChildItem .\somedir | Where {!$_.PSIsNotContainer} | Move-Item -Destination $destination
using the $files object as the pipelined object.

$files = Get-ChildItem .\somedir | Where {!$_.PSIsNotContainer}
$files | Move-item -Destination $destination
I did this test and it seemed to work both ways:

$path = "C:\testing\powershell\testfiles";

#region Method 1

# method 1 - pipelining a collection object
$destination1 = Join-Path -Path $path -ChildPath "method1"

if([System.IO.Directory]::Exists($destination1) -ne $true) {
New-Item -Path $destination1 -ItemType Directory
}

for($i=1;$i -le 10;$i++) {
New-Item -Path $path -Name "$i.txt" -ItemType File -Value "$i" -force
}

$files = Get-ChildItem $path | where {$_.PSIsContainer -ne $true};

Write-Output "Method 1";
$files | Move-Item -Destination $destination1

#endregion Method 1

#region Method 2
# method 2 - pipelining the cmdlets
$destination2 = Join-Path -Path $path -ChildPath "method2"

if([System.IO.Directory]::Exists($destination2) -ne $true) {
New-Item -Path $destination2 -ItemType Directory
}

for($i=1;$i -le 10;$i++) {
New-Item -Path $path -Name "$i.txt" -ItemType File -Value "$i" -force
}

Write-Output "Method 2";
Get-ChildItem $path | where {$_.PSIsContainer -ne $true} | Move-Item -Destination $destination2

#endregion Method 2
As it turned out, passing the pipelined set of commands (method 1) worked just as well as gathering the collection into an object, then, passing the object to the Move-Item cmdlet (method 2).

0 comments:

Post a Comment