Avoid recursively fetching specific folders in PowerShell - powershell

I have a Visual Studio solution with several projects. I clean up the bin and obj folders as part of clean up using the following script.
Get-ChildItem -path source -filter obj -recurse | Remove-Item -recurse
Get-ChildItem -path source -filter bin -recurse | Remove-Item -recurse
This works perfectly. However, I have a file-based data folder that has about 600,000 sub folders in it and is located in a folder called FILE_DATA.
The above script takes ages because it goes through all these 600,000 folders.
I need to avoid FILE_DATA folder when I recursively traverse and remove bin and obj folders.

Here is a more efficient approach that does what you need--skip subtrees that you want to exclude:
function GetFiles($path = $pwd, [string[]]$exclude)
{
foreach ($item in Get-ChildItem $path)
{
if ($exclude | Where {$item -like $_}) { continue }
$item
if (Test-Path $item.FullName -PathType Container)
{
GetFiles $item.FullName $exclude
}
}
}
This code is adapted from Keith Hill's answer to this post; my contribution is one bug fix and minor refactoring; you will find a complete explanation in my answer to that same SO question.
This invocation should do what you need:
GetFiles -path source -exclude FILE_DATA
For even more leisurely reading, check out my article on Simple-Talk.com that discusses this and more: Practical PowerShell: Pruning File Trees and Extending Cmdlets.

If the FILE_DATA folder is a subfolder of $source (not deeper), try:
$source = "C:\Users\Frode\Desktop\test"
Get-Item -Path $source\* -Exclude "FILE_DATA" | ? {$_.PSIsContainer} | % {
Get-ChildItem -Path $_.FullName -Filter "obj" -Recurse | Remove-Item -Recurse
Get-ChildItem -Path $_.FullName -Filter "bin" -Recurse | Remove-Item -Recurse
}

Related

Exclude multiple folders from get-childitem

I have this script that compares 2 directories with each other if it matches it copies it to the other directory. But i need 2 folders to be excluded on the source folder because there are old files there. I excluded one folder but i can't add an second one. Can someone help me out? (I'm a beginner in Powershell) I know the foreach loop is empty, this is for testing purposes.
$aDir = "C:\Replace TEST SCRIPT\A"
$bDir = "C:\Replace TEST SCRIPT\Y"
$aFiles = Get-ChildItem -Path "$bDir\" -Exclude "Folder1","Folder2" | Get-ChildItem -Path "$bDir\*.pdf" -Recurse -File | select -exp FullName
ForEach ($file in $aFiles) {
$laatste = (Get-Item $file).LastWriteTime
$filenaam = Split-Path -Path "$file" -Leaf
if(Test-Path -Path "C:\Replace TEST SCRIPT\A\$filenaam") {
Write-Output "$filenaam exists in $aDir. Copying."
Copy-Item -Path "$file" -Recurse -Destination "$aDir"
} else {
}
}
You can do it the following way:
$aFiles = Get-ChildItem -Path "$bDir\" -Exclude "PDF","folder2" | Get-ChildItem -filter "*.pdf" -Recurse -File | select -exp FullName
Btw.
There is already a post to your certain question:
How can I exclude multiple folders using Get-ChildItem -exclude?
Please take a look at it and let us know.

Powershell folder archiving

I have a powershell script that simply uses the Get-ChildItem command to search through a directory for a folder matching a keyword. When found I need it to zip it and leave it right in that same directory.
Here's what I've tried by piping the command into both 7zip and the native compress:
set-alias zip "$env:ProgramFiles\7-Zip\7z.exe"
Get-ChildItem $path "keyword" -Recurse -Directory | zip a
AND
Get-ChildItem $path"keyword" -Recurse -Directory | compress-archive
Both times it always asks for a source and destination which is hard to define since I'm having it search through a drive with many sub-folders. I though using the pipe would imply the source as well.
Any ideas? Thanks!
EDIT:
I suppose I could set the Get-ChildItem to a variable and use that as the "source" and have the destination be a generic location for them all but I'd have to name them differently, no?
Give this a try:
$path = "INSERT SOURCE ROOT"
foreach ($directory in Get-ChildItem $path -Recurse -Directory -Filter "keyword"| Select-Object FullName | foreach { $_.FullName}) {
$destination = Split-Path -Path $directory -Parent
Compress-Archive -Path $directory -DestinationPath $destination
}
This is looking inside the path for anything matching the "keyword", going up 1 level, and then zipping the found file.
With temp and temp2 directories under C:\ this is working for me (note that the directories must have content):
Get-ChildItem "C:\" "temp*" -directory | compress-archive -DestinationPath "C:\tempzip.zip"
It zips all directories found to C:\tempzip.zip.
I believe what you actually want is:
$dirs = Get-ChildItem "C:\" "temp*" -directory
foreach ($dir in $dirs){
compress-archive $dir.fullname -DestinationPath "$($dir.fullname).zip"
}
Note that I omitted -recurse for my testing.
You can do this:
get-childitem -path "The Source Path" -recurse | where {$_.Name -match "Keyword"} | foreach {
$parent = Split-Path -Path $_ -Parent
Compress-Archive -Path $_ -DestinationPath $parent
}

Move Files From One Location To Another And Exclude Subfolders

I want to move files from one location to another but not to move any files from subfolders in the directory I'm moving the files from.
I have the following code but this moves files in subfolders. Also, the extensions should only be .xml and .pdf.
This script moves all files from $MoveThese into the Destination, even the files in subfolders e.g. C:\Test\Folder1\Subfolder. Any suggestions would be helpful.
$MoveThese = "C:\Test\Folder1", "C:\Test2\Folder2", "C:\Test3\Folder3"
$Destination = "C:\Test\Docs", "C:\Test2\Docs", "C:\Test3\Docs"
For($i=0; $i -lt $FailFolders.Length; $i++){
Get-ChildItem -Path $MoveThese[$i] -Recurse -Include "*.xml", "*.pdf" | Move-Item -Destination $Destination[$i]
}
If you don't want files in subfolders, don't use -Recurse. As per Get-ChildItem documentation this "Gets the items in the specified locations and in all child items of the locations."
Missed this part of the -Include statement:
The -Include parameter is effective only when the command includes the
-Recurse parameter
Solution:
Get-ChildItem $MoveThese[$i] -File |
Where-Object {$_.Extension -in #(".xml",".pdf")} |
Move-Item -Destination $Destination[$i]
Include does not work without the -Recurse switch unfortunately unless the path uses a wildcard like in C:\Windows*
This might do it for you:
$MoveThese = "C:\Test\Folder1", "C:\Test2\Folder2", "C:\Test3\Folder3"
$Destination = "C:\Test\Docs", "C:\Test2\Docs", "C:\Test3\Docs"
For($i=0; $i -lt $MoveThese.Length; $i++){
Get-ChildItem $MoveThese[$i] -File |
Where-Object { $_.Name -like "*.xml" -or $_.Name -like "*.pdf" |
Move-Item -Destination $Destination[$i] -Force
}

I need to find a Folder on the Network Share

How can I find Folders called BlueMountain when this folder could be nested anywhere in my Users home folder
\\Server\Users\<personsname>\
Ultimately I want to delete the folder but just to be on the safe side. The BlueMountain folder must have one of these subfolder
Certs
Config
Macros
Scripts
Spool
Traces
Transfer
This is what I have so far
Get-ChildItem -Path \\Server\Users -Recurse -Directory -Filter $_.FOLDERNAME | ForEach-Object {
If $_.FullName --eq "BlueMountain" {
}
}
You can use -recurse to look for the last thing in your path recursively. So this:
Get-ChildItem \\server\Users\BlueMountain -recurse
Will look in all subfolders of "\server\Users" for anything named "BlueMountain". Then you just need to make sure it has one of your folders.
$SubFolders = 'Certs','Config','Macros','Scripts','Spool','Traces','Transfer'
Get-ChildItem \\server\Users\BlueMountain -recurse | Where{Get-ChildItem "$($_.FullName)\*" -Include $SubFolders}
That should list only the BlueMountain folders found recursively in \server\Users which contain one of the specified subfolders. Then you can just pipe that to Remove-Item -force and call it a day. Or if you want to track things pipe it to tee-object and then to remove-item.
try this :
$SubFolders = 'Certs','Config','Macros','Scripts','Spool','Traces','Transfer'
$wordtosearch="BlueMountain"
$SearchPattern= ($SubFolders | %{ "$wordtosearch\\$_" }) -join "|"
get-childitem "\\Server\Users" -directory -Recurse |
where FullName -match $SearchPattern |
Split-Path -path {$_.FullName} -Parent |
remove-item -Recurse -ErrorAction SilentlyContinue

How to rename files using HttpUtility.UrlEncode method in PowerShell?

I have a bunch of html files that I need to rename with url encoding before I upload them to the server. I've tried:
Get-ChildItem -Path c:\temp\ -Recurse -Filter *.html | Rename-Item -NewName { $_.Name.replace("*.html",[Web.Httputility]::UrlEncode("*.html")) }
But that doesn't apply the encoding, can this be even done somehow?
Here's a basic way to do it, based on this answer:
(Get-ChildItem -Path c:\temp\ -Recurse -Filter *.html -File) |
foreach { ren $_.fullname ([uri]::EscapeDataString($_))}
Originally I had written it without the () around the Get-ChildItem, but found it was still reading directory information while the rename had already renamed the first item. Then the rename reencoded the first item a second time, thus making it a bit munged up.
Here's a cleaner version that handles the files first and then folders:
$files = Get-ChildItem -Path c:\temp\ -Recurse -Filter *.html -File
$folders = Get-ChildItem -Path c:\temp\ -Recurse -Filter *.html -Directory
$files | foreach { ren $_.fullname ([uri]::EscapeDataString($_))}
$folders | foreach { ren $_.fullname ([uri]::EscapeDataString($_))}
Based on your answers i did this to make it work
(Get-ChildItem -Path c:\temp\ -Recurse -Filter *.html) |
foreach { ren $_.fullName ([uri]::EscapeDataString($_.Name))} | Out-Null
Get-ChildItem -Path c:\temp\ -Recurse | ?{ $_.PSIsContainer } |
foreach { ren $_.fullName ([uri]::EscapeDataString($_.Name))}
First I had to do only files and then folders, because when top folder gets renamed, then the path to files inside it doesn't exist any more.