Renaming files in multiple subfolders - powershell

I have 100 folders that are incremental. E.g.
'20D, 0.5B001'...'20D, 0.5B002'
...all the way to
'20D, 0.5B100'
Each of those folders contains files that have the same incremental names. E.g. 'Test_C1S0002001'...'Test_C1S0002002' etc.
I want to rename every file in each of these folders to '002001' I.e. just get rid of 'Test_C1S0' in every one of these subfolders. How can I do this?

gci 'c:\path\' -File -Recurse | ren -NewName { $_ -replace 'Test_C1S0', '' }
(untested)

What TessellatingHeckler has should work perfectly fine. You don't need regex for this as you are removing a simple string from the beginning of the line. So using the same logic...
Get-ChildItem "C:\temp" -Recurse -File | Rename-Item {($_.Name).TrimStart("Test_C1S0")}
If you don't have PowerShell at least v3.0 then you would need to do this.
Get-ChildItem "C:\temp" -Recurse | Where-Object{!$_.PSIsContainer} | Rename-Item {($_.Name).TrimStart("Test_C1S0")}

Related

Powershell how to get-content across several subfolders

I'm working on a script to output some data from multiple files based on a string search. It outputs the string found, followed by the following six characters. I can get this to work for an exact location. However, I want to search across files inside multiple subfolders in the path. Using the below script, I get PermissionDenied errors...
[regex] $pattern = '(?<=(a piece of text))(?<chunk>.*)'
Get-Content -Path 'C:\Temp\*' |
ForEach-Object {
if ($_ -match $pattern) {
$smallchunk = $matches.chunk.substring(0, 6)
}
}
"$smallchunk" | Out-File 'C:\Temp\results.txt'
If I change -Path to one of the subfolders, it works fine, but I need it to go inside each subfolder and execute the get-content.
e.g., look inside...
C:\Temp\folder1\*
C:\Temp\folder2\*
C:\Temp\folder3\*
And so on...
Following up on boxdog's suggestion of Select-String, the only limitation would be folder recursion. Unfortunately, Select-String only allows the searching of multiple files in one directory.
So, the way around this is piping the output of Get-ChildItem with a -Recurse switch into Select-String:
$pattern = "(?<=(a piece of text))(?<chunk>.*)"
Get-ChildItem -Path "C:\Temp\" -Exclude "results.txt" -File -Recurse |
Select-String -Pattern $pattern |
ForEach-Object -Process {
$_.Matches[0].Groups['chunk'].Value.Substring(0,6)
} | Out-File -FilePath "C:\Temp\results.txt"
If there's a need for the result to be saved to $smallchunk you can still do so inside the loop if need be.
Abraham Zinala's helpful answer is the best solution to your problem, because letting Select-String search your files' content is faster and more memory-efficient than reading and processing each line with Get-Content.
As for what you tried:
Using the below script I get PermissionDenied errors...
These stem from directories being among the file-system items output by Get-ChildItem, which Get-Content cannot read.
If your files have distinct filename extensions that your directories don't, one option is to pass them to the (rarely used with Get-Content) -Include parameter; e.g.:
Get-Content -Path C:\Temp\* -Include *.txt, *.c
However, as with Select-String, this limits you to a single directory's content, and it doesn't allow you to limit processing to files fundamentally, if extension-based filtering isn't possible.
For recursive listing, you can use Get-ChildItem with -Recurse, as in Abraham's answer, and pipe the file-info objects to Get-Content:
Get-ChildItem -Recurse C:\Temp -Include *.txt, *.c | Get-Content
If you want to simply limit output to files, whatever their name is, use the -File switch (similarly, -Directory limits output to directories):
Get-ChildItem -File -Recurse C:\Temp | Get-Content

Renaming all the folder names in the current dir that has files and sub directories inside using Powershell

I have a set of folders like below, which has files and subfolders inside them, i want to rename
all the smv2103* folders to smv2106* folders , keeping the files and subfolders inside them intact using Powershell
E:\online\smv2103pdf
E:\online\smv2103mac
E:\online\smv2103frp
E:\online\smv2103rep
E:\online\smv2103soc
E:\online\smv2103bid
E:\online\smv2103rem
E:\online\smv2103nop
E:\online\smv2103gac
E:\online\smv2103pam
Any help would be highly appreciated , as Rename-Item itself is not working because of the files and subfolders inside
Get-ChildItem "E:\online\*" -Directory|
Where{ ( $_.Name -like "*2103*") } |
ForEach-Object{
((Get-Content $_.FullName -Raw) -replace "2103","2106") | Set-Content -Path $_.FullName
}
So you just want to rename the folders? You use Get-Content to get the content from within files. To filter for a certain criteria, Get-ChildItem has a -Filter Parameter you can use.
Get-ChildItem -Filter "*2013*"
When filtering in powershell, its good practice filtering as far left as possible. Now, knowing your just looking to rename the folders themselves, we can remove Get-Content and pipe the info onto Rename-Item.
Get-ChildItem -Path "E:\online*" -Filter "*2013*" -Directory |
ForEach-Object {
Rename-Item -Path $_.FullName -NewName $_.Name.Replace('2013','2016')
}

Advice with powershell script syntax

I am writing a powershell script to perform the following:
Within a folder Folder > Subfolder1 > Subfolder2 there are 30+ subfolders.zipin which there is another subfolder with 200 HRML files.
I would like to search for a keyword WTSE in the HTML files and any files containing such keyword would be moved to another folder.
My script looks as follows at the moment:
Get-childitem C:\Users\XXXXX\Desktop\Folder\ -filter *.html -recurse | select-string 'WTSE'|foreach-object -process{move-item} C:\Users\XXXXX\Desktop\Folder2`
You're almost there. The problem is with the part after ForEach-Object.
Since you are not searching for a string using regex, I would suggest adding the -SimpleMatch to the Select-String cmdlet.
Try below:
$sourceFolder = 'C:\Users\XXXXX\Desktop\Folder'
$destination = 'C:\Users\XXXXX\Desktop\Folder2'
(Get-ChildItem -Path $sourceFolder -Filter '*.html' -Recurse | Select-String -Pattern 'WTSE' -SimpleMatch) |
Move-Item -Destination $destination
The Move-Item cmdlet can take an array of paths and these can also accepts pipeline input, so there is no need to use ForEach-Object here.
Note I'm using brackets around the first part (Get-ChildItem ... -SimpleMatch). This prevents the error that the process cannot open the file because it is in use

Copy same file to multiple different folders PowerShell

I want to copy one file logo.png to different multiple folders. As of now I am doing like this
Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" |
Copy-Item -Destination "D:\LoginPage"
Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" |
Copy-Item -Destination "D:\HomePage"
Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" |
Copy-Item -Destination "D:\AboutUs"
Is there any way to make it single command?
I have seen this but looks different.
I am not aware of one single command to achieve what you are trying to do.
As pointed out in the link you posted, you can achieve your goal with one line of code, but this involves piping.
"D:\LoginPage", "D:\HomePage", "D:\AboutUs" | ForEach-Object { Get-Childitem "D:\OrgIcon" -Recurse -Include "*logo.png" | Copy-Item -Destination $_}
In the first part you just list your destinations as strings and separated by comma.
The second part will execute the code within the braces { } for each destination.
Note: $_ stands for the data currently in the pipeline, so on each iteration $_ will be replaced with your destination.
I guess if this is something you need to do regularly with different destinations, sources and filenames you could always write a script file that accepts input for it's parameters, but that's a topic for another question.
Hope this is useful.

XCOPY deployment script - how to include certain files?

I need to copy only certain parts of a folder using Powershell, specifically this list:
$files = #("MyProgram.exe",
"MyProgram.exe.config",
"MyProgram.pdb",
".\XmlConfig\*.xml")
In human readable form: 3 specific MyProgram.* files under root of target folder and all XML files under XmlConfig folder which itself is under root of source path (..\bin\Release\ in my case). XmlConfig folder must be created in destination, if it does not exist.
What I have tried:
(1) I tried the following, but it did not work, i.e. no folder or files were created at the destination path:
Copy-Item -Recurse -Path "..\bin\Release\" -Destination ".\Test\" -Include $files
(2) When -Include is removed, whole folder structure is successfully created, including subfolders and files:
Copy-Item -Recurse -Path "..\bin\Release\" -Destination ".\Test\"
It must be something wrong with my understanding of how -Include filter works:
(3) I tested an assumption that -Include needs an array of wildcards, but this did not work either:
$files = #("*MyProgram.exe*",
"*MyProgram.exe.config*",
"*MyProgram.pdb*",
"*.\XmlConfig\*.xml*")
Please advise on how to properly do Copy-Item in my case.
UPDATE (based on below answers):
I am looking for a generic implementation that takes an array of strings. It opens the possibility to put all necessary files/paths in one place, for easy editing, so that a non-Powershell knowledgeable person can understand and modify it as required. So in the end it would be single script to perform XCOPY deployments for any project, with input file being the only variable part. For above example, the input would look like this (saved as input.txt and passed as an argument to the main script):
MyProgram.exe
MyProgram.exe.config
MyProgram.pdb
.\XmlConfig\*.xml
I would prefer wildcards approach, since not many people know regex.
i don't know what is wrong with filter but you can still do
$files | % { copy-item ..\bin\release\$_ -Destination .\test}
if you want to preserve directoty structure you'll have to weak this a little, like :
$sourcedir="c:\temp\test"
$f=#("existing.txt","hf.csv";"..\dir2\*.txt")
$f |%{
$source=ls (join-Path $sourcedir $_) |select -expand directoryname
if ("$source" -like "$sourcedir*"){
$destination=$source.Substring($sourcedir.Length)+".\"
}
else{
$destination=$_
}
copy-item $sourcedir\$_ -Destination $destination -WhatIf
}
AFAICT -Include works only with file names or directory names and not combinations i.e. paths. You can try something like this:
$files = 'MyProgram\.exe|MyProgram\.exe\.config|MyProgram\.pdb|XmlConfig\\.*?\.xml'
Get-ChildItem ..\bin\release -r | Where {!$_.PSIsContainer -and ($_.FullName -match $files)} |
Copy-Item -Dest .\test
With wildcards you could do it this way:
$files = #('*MyProgram.exe','*MyProgram.exe.config','*MyProgram.pdb','*\XmkConfig\*.xml')
Get-ChildItem ..\bin\release -r |
Foreach {$fn=$_.Fullname;$_} |
Where {!$_.PSIsContainer -and ($files | Where {$fn -like $_})} |
Copy-Item -Dest .\test