开发者

Get-ChildItem results looks like relative paths in Powershell

开发者 https://www.devze.com 2023-03-25 04:29 出处:网络
I would like to scan and move folders (and sub folders or even deeper) from one folder to another using Powershell.

I would like to scan and move folders (and sub folders or even deeper) from one folder to another using Powershell.

Currently I'm using this pipe of commands.

Get-ChildItem  -recurse  -path sub\WORK  -filter "* OK" | Where-Object { $_.PSIsContainer } | foreach { Move-Item -path $_  -destination sub\OK }

Unfortunately it doesn't work because the found results are relative to .\sub\WORK, when trying to move them Move-Item complains that the folders are not in the current folder:

Move-Item : Cannot find path 'C:\TMP\2011-12-12 test 2 OK' because it does not exist.

I expect that $_ would contain: 'C:\TMP\sub\WORK\2011-12-12开发者_如何学Python test 2 OK' because these are objects in Powershell and no strings like in Linux.


In case you use Get-ChildItem, be very careful. The best way is to pipe the objects to Move-Item and you don't need to think about it more:

Get-ChildItem  -recurse  -path sub\WORK  -filter "* OK" | Where-Object { $_.PSIsContainer } | Move-Item -destination sub\OK

(no need to use Foreach-Object)

The main reason why I'm answering is this one: Get-ChildItem constructs object differently, depending on the parameters. Look at examples:

PS C:\prgs\tools\Console2> gci -include * | % { "$_" } | select -fir 5
C:\prgs\tools\Console2\-verbose
C:\prgs\tools\Console2\1UpdateDataRepositoryServices.ps1
C:\prgs\tools\Console2\22-52-59.10o52l
C:\prgs\tools\Console2\2jvcelis.ps1
C:\prgs\tools\Console2\a
PS C:\prgs\tools\Console2> gci | % { "$_" } | select -fir 5
-verbose
1UpdateDataRepositoryServices.ps1
22-52-59.10o52l
2jvcelis.ps1
a

Then if you use $_ in a cycle and PowerShell needs to convert FileInfo from Get-ChildItem to string, it gives different results. That happened when you used $_ as argument for Move-Item. Quite bad.

I think there is a bug that reports this behaviour.


You are correct that objects are being piped down the pipeline instead of strings. This is good in that it is more flexible. The drawback is that if you don't explicitly tell the system which property of the object to use you are at the mercy of the system designers. See if explicitly telling the system the property that you want will help:

Get-ChildItem  -recurse  -path sub\WORK  -filter "* OK" | Where-Object { $_.PSIsContainer } | foreach { Move-Item -path $_.Fullname  -destination sub\OK }


I just learn't that the PSPath is automatically used in Copy-Item, Move-Item etc. when you don't specify the source in a pipeline, so something like:

gci .\sub\Work | move-item -Destination .\sub\OK

(simplified example)

would work and it would use the PSPath of the passed object to determine the source.


Since the Get-ChildItem returns objects like you said, you can use Get-Member to see what the object has to offer ( that is know about its properties and methods)

 Get-ChileItem path | Get-Member

You could see that FullName is one of the properties that you could use.


Here is what worked for me.

Get-ChildItem -Path .\ -Recurse -filter "* OK" | %{Join-Path -Path $_.Directory -ChildPath $_.Name } | Move-Item -Destination sub\OK
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号