I have about 700 .txt files scattered in 300 directories and sub-directories.
I would like to open each of them, convert all text inside to lowercase, including Unicode characters (such as É to é), then save and close them.
Can you advise how it could be done through PowerShell? It is my own computer and I have admin rights.
I have started with the below:
Get-ChildItem C:\tmp -Recurse -File | ForEach-Object {}
but I am not sure what to put between the brackets of ForEach-Object {}.
Simple script, with your requirements:
$path=".\test\*.txt"
#With Default system encoding
Get-ChildItem $path -Recurse | foreach{
(Get-Content $_.FullName).ToLower() | Out-File $_.FullName
}
#Or with specified encoding
Get-ChildItem $path -Recurse | foreach{
(Get-Content $_.FullName -Encoding Unicode).ToLower() |
Out-File $_.FullName -Encoding Unicode
}
#Test
Get-ChildItem $path -Recurse | foreach{
Write-Host "`n File ($_.FullName): `n" -ForegroundColor DarkGreen
Get-Content $_.FullName
}
You need to use :
# Reading the file content and converting it to lowercase and finally putting the content back to the file with the same filename.
(Get-Content C:\path\file.txt -Raw).ToLower() | Out-File C:\path\file.txt -Force
inside the foreach and then change the case to lower.
If you want to iterate all the files in the corresponding folder then you can use another foreach to get that job done.
Hope it helps.
Related
I have a long list of folders. Most of the folders follow the "name_#name" format. I have some that don't follow that structure. I want to move all the folders (and the sub-folders/files within) that DON'T have "_" in the folder name.
For example:
test_#12352
moose_#4532
horse_#84462
cow24
fish3
Moved:
cow24
fish3
I think Move files when they contain a specific word? could be modified to make it work...just not sure how. I'm used to just using GUI, this is my first time using PowerShell
When I tried using that code in that link it didn't work with my situation
What you want to do is just filter the list before you move any files
So you can use the following to pick up all the files you want
$Files = Get-childItem -Path $Path -File
You can then filter it down. My favourite way is to pipe the variable into Where-Object and play around with the individual properties and match types. Since you don't want to include the _ we can use a -notmatch "_" to exclude those values
$Files = Get-ChildItem -Path $Path -File | Where-object{$_.Name -notmatch "_"}
And finally, you can move the files
$Files | move-item -path $_.FullName -Destination $Destination
Or as a one liner
Get-ChildItem -Path $Path -File | Where-object{$_.Name -notmatch "_"} | move-item -path $_.FullName -Destination $Destination
*Please note I haven't really tested this code. So test it out yourself before you run it
I need to move set of specific files having different extension to another folder.
I have following filtered files in the directory.
file1.txt
file2.xml
file3.dll
I have kept the above files in the variable $files and I need to move each of files to another folder.
Below is the code I tried.
foreach ($fileType in $files) {
Get-ChildItem -Path C:\Files -Filter "$fileType*." -Recurse |
Move-Item -Destination C:\Dest
}
I am getting following error
Get-ChildItem : Illegal characters in path.
At line:1 char:38
+ ... lude_files){Get-ChildItem -Path C:\Files
Appreciate if anyone can help on this?
An easy way to do this
ls C:\files | Foreach {
Move-Item -Path C:\files\$filetype -Destination C:\dest
}
If all the files you are after share a common 'starts-with' name like file as in your example, the below should do what you want. It uses the -Include parameter where you can add an array of (in this case) extensions to look for.
Get-ChildItem -Path 'C:\Files' -Filter 'file*' -Include '*.txt','*.xml','*.dll' -Recurse |
Move-Item -Destination 'C:\Dest'
Note: the -Include parameter only works when also used together with the -Recurse switch, OR by appending \* after the path (like in C:\Files\*)
I'm trying to replicate this command into PowerShell:
grep -lR 'Find' ./src | while read filename; do sed -i".bak" 's/Find/Replace/g' "$filename"; done
What I have so far:
Get-ChildItem "src" -Recurse -File | ForEach-Object { $f = $_; (Get-Content $f) | ForEach-Object { $_ -replace "Find", "Replace" } | Set-Content "$f.tmp"; Move-Item "$f.tmp" $f -Force }
I'm getting an error saying "filename.tmp" does not exist. I thought the above would create the file while parsing. Any help would be appreciated.
Most likely you've fallen victim to Windows PowerShell's inconsistent stringification of the System.IO.FileInfo instances output by Get-ChildItem - see this answer.
The workaround is to use explicit stringification via the .FullName property, which explicitly returns an item's full path.
Applied to your command, alongside some optimizations:
Get-ChildItem -File -Recurse src | ForEach-Object {
$f = $_.FullName # !! Explicitly retrieve the full path
(Get-Content $f -Raw) -creplace 'Find', 'Replace' |
Set-Content -NoNewline "$f.tmp"
Move-Item "$f.tmp" $f -Force
}
Get-Content -Raw reads the entire file into memory as a single string, which is more efficient.
-creplace (which performs case-sensitive replacement, as sed would by default) is directly applied to the resulting multiline string and replaces all occurrences.
-NoNewline (PSv5+) ensures that Set-Content doesn't add an additional trailing newline to the multiline string being saved (the same applies to Out-File / >).
Note: Given that Get-Content -Raw reads the entire file up front, you could even write the modified content back to the very same file, without requiring an intermediate temporary file and a subsequent Move-Item call; that said, doing so bears a slight risk of data loss, if the process of writing back to the same file is interrupted.
Also, while your sed call retains the original file with extension .bak, your PowerShell command does not.
I'm trying to copy all *.csproj.user files recursively from C:\Code\Trunk to C:\Code\F2.
For example:
C:\Code\Trunk\SomeProject\Blah\Blah.csproj.user
Would get copied to:
C:\Code\F2\SomeProject\Blah\Blah.csproj.user
My current attempt is:
Copy-Item C:\Code\Trunk -Filter *.csproj.user -Destination
C:\Code\F2 -Recurse -WhatIf
However I get:
What if: Performing operation "Copy Directory" on Target "Item:
C:\Code\Trunk Destination: C:\Code\F2\Trunk".
First, it wants to put them all in a new folder called F2\Trunk which is wrong. Second, it doesn't list any of the files. There should be about 10 files to be copied over.
What's the correct syntax for the command? Thanks!
Update:
Okay, it seems to have something to do with the fact that C:\Code\F2 already exists. If I try copying the files over to a destination that does not exist, it works.
I want to overwrite any existing .csproj.user files in the destination.
You guys are making this hideously complicated, when it's really simple:
Copy-Item C:\Code\Trunk -Filter *.csproj.user -Destination C:\Code\F2 -Recurse
Will copy the Directory, creating a "Trunk" directory in F2. If you want to avoid creating the top-level Trunk folder, you have to stop telling PowerShell to copy it:
Get-ChildItem C:\Code\Trunk | Copy-Item -Destination C:\Code\F2 -Recurse -filter *.csproj.user
While the most voted answer is perfectly valid for single file types, if you need to copy multiple file types there is a more useful functionality called robocopy exactly for this purpose with simpler usage
robocopy C:\Code\Trunk C:\Code\F2 *.cs *.xaml *.csproj *.appxmanifest /s
Seen this before, and I don't know why PowerShell can't seem to get it right (IMHO). What I would do is more cumbersome but it works.
$Source = 'C:\Code\Trunk'
$Files = '*.csproj.user'
$Dest = 'C:\Code\F2'
Get-ChildItem $Source -Filter $Files -Recurse | ForEach{
$Path = ($_.DirectoryName + "\") -Replace [Regex]::Escape($Source), $Dest
If(!(Test-Path $Path)){New-Item -ItemType Directory -Path $Path -Force | Out-Null
Copy-Item $_.FullName -Destination $Path -Force
}
I tried Jaykul answer and it did not work for me. I had to change it as below to get it to work. I also created the C:\Code\F2 folder before it worked.
Get-ChildItem C:\Code\Trunk -Recurse -filter *.csproj.user | Copy -Destination C:\Code\F2
Answer 1 looked good, and I changed to Move-Item for my purposes. However I found that in each folder it recursively went through, it only moved the first file. Below is my complete script which also includes some conversion of doc files to pdf's:
$Source = 'C:\Users\sgrody\Desktop\NSPM-Vol1'
$MoveFiles = '*.PDF'
$Dest = 'C:\Users\sgrody\Desktop\MedPassPDF'
$Folders = Get-ChildItem $Source -Directory -Recurse
ForEach ($Folder in $Folders)
{
$wdFormatPDF = 17
$word = New-Object -ComObject word.application
$word.visible = $false
$folderpath = "$($Folder.FullName)\*"
$fileTypes = "*.docx","*doc"
Get-ChildItem -path $folderpath -include $fileTypes |
foreach-object
{
$path = ($_.fullname).substring(0,($_.FullName).lastindexOf("."))
"Converting $path to pdf ..."
$doc = $word.documents.open($_.fullname)
$doc.saveas([ref] $path, [ref]$wdFormatPDF)
$doc.close()
}
$word.Quit()
}
Get-ChildItem $Source -Filter $MoveFiles -Recurse | ForEach{
$Path = ($_.DirectoryName + "\") -Replace [Regex]::Escape($Source), $Dest
If(!(Test-Path $Path)){New-Item -ItemType Directory -Path $Path -Force | Out-Null
Move-Item $_.FullName -Destination $Path -Force
}
}
Recently I had to replace a file present in several sub folders, I did it as below.
foreach($file in (Get-ChildItem File_you_want_to_be_copied.txt -Recurse)) {$target=$file.directoryname; Copy-Item -path C:\Source_Path\File_you_want_to_be_copied.txt -Destination $target}
I have subfolders which have names:
original_Optimize
Original_optimize
original_optimize
Original_Optimize
I would like to rename all of these to:
Original_Optimize
Is there an easy way of doing this in windows (perhaps using powershell or something in command prompt ) ?
You can do that in two Rename-Item calls. The first would add a prefix to each name to avoid the 'Source and destination path must be different.' error. The second run will remove the prefix.
Get-ChildItem -Filter original_optimize -Recurse |
Rename-Item -NewName __foo__Original_Optimize -PassThru |
Rename-Item -NewName {$_.Name -replace '^__foo__'} -PassThru
Try this.
Get-ChildItem C:\path-to-directory -Recurse -Filter *foo* | Rename-Item -NewName { $_.name -replace 'foo', 'bar'} -verbose