How could I modify name of every file by adding _ before the filename extension in a Get-ChildItem -Include without calling 3 times a Foreach.
My script works, but I would like to simplify it by using -Include and not -Filter.
function renommer_fichier {
$files = Get-ChildItem -Path C:\mestp\mesFichiers -Filter *.jpg
Foreach ($file in $files)
{
$file | Rename-Item -NewName { $_.Name -replace '.jpg', '_.jpg' }
}
$files = Get-ChildItem -Path C:\mestp\mesFichiers -Filter *.mp3
Foreach ($file in $files)
{
$file | Rename-Item -NewName { $_.Name -replace '.mp3', '_.mp3' }
}
$files = Get-ChildItem -Path C:\mestp\mesFichiers -Filter *.mpeg
Foreach ($file in $files)
{
$file | Rename-Item -NewName { $_.Name -replace '.mpeg', '_.mpeg' }
}
}
Unfortunately, the -Include parameter - which supports specifying multiple patterns - doesn't work as one would intuitively expect:
Use Get-Item instead of Get-ChildItem and append \* to the input path to make -Include work as intended.
See this answer for background information.
Use the .BaseName and .Extension properties in the delay-bind script block you're passing to Rename-Item to facilitate inserting _ before the filename extension.
Get-Item -Path C:\mestp\mesFichiers\* -Include *.jpg, *mp3, *.mpeg |
Rename-Item -WhatIf -NewName { $_.BaseName + '_' + $_.Extension }
Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
I have an issue where a path to a file is generated by an application. So the path looks like this….
Unfortunately, this output is generated from an application…so I cannot manipulate the output.
Now…when I run my powershell script to copy the file …I get the following errors
It seems that the problem is that my powershell script is not getting the path correctly….
$folders = Get-Content -Path '\\TFA-APP-01\CUI\WS\FOUNDFILES\results.txt'
$dest = '\\TFA-APP-01\CUI\WS\FOUNDFILES\found\'
$excludes = "WS","FOUNDFILES"
foreach ($folder in $folders) {
# Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Desktop'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Documents'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Downloads'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Outlook'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'INetCache'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
Get-ChildItem -Path $folder | Where-Object{$_.Name -notin $excludes} | Where-Object{$_.FullName -like 'Attachments'} | Copy-Item -Destination $dest -Recurse -ErrorAction SilentlyContinue
}
How can I either parse the results.txt file and extract just the file paths to another text file?
Or how can I modify my CopyResults.ps1 script to interpret the file path correctly?
Your issue is that Get-Content converts every line of a file into an element of an array, and you don't want to look at every line. You want to look at a specific part of a specific line that repeats in a specific pattern.
Because of all of these constants, we can make a pretty simple script to get the information you want.
$paths = Get-Content C:\temp\paths.txt
for ($i = 1; $i -lt $paths.Length; $i += 3) {
$path = "$($paths[$i].Split('.txt')[0]).txt"
$path # \\SERVER\PATH\FILE.TXT
}
Your file has a pattern of [empty line, path line, company line]. If we think about the .txt file as an array with many subarrays of that pattern, we can see that we want to get the 1st index ($i = 1) for every set of 3 ($i += 3) in the file.
Since I split by .txt, I have to string interpolate the .txt extension back on.
Edit:
Here's the script modified for your issues
$paths = Get-Content C:\temp\paths.txt
for ($i = 1; $i -lt $paths.Length; $i += 3) {
$pathSplit = $paths[$i].Split('.')
$extension = $pathSplit[1].split(' ')[0]
$path = "${$pathSplit[0]).$extension"
$path # \\SERVER\PATH\FILE.TXT
}
$pathSplit is split at the extension into 2 parts. One is the majority of the path and the other is the rest of the line.
$extension looks at the 1st index and splits by the space in order to isolate the file extension.
Finally, $path combines $pathSplit[0] and $extension to give you the full file path.
I'm trying to migrate a file server to One Drive the problem is that there are many folders and files with special characters like '|' , '<' etc..
And also for some reason that company used '*' for versioning like :
'*' => v.1
'**' => v.2
etc...
So I wrote a Powershell script that renames all the files and folders that include a special characters.
#Files
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(":","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("<","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(">","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("?","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("/","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("|","-")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**********","10")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*********","9")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("********","8")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*******","7")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("******","6")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*****","5")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("****","4")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("***","3")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**","2")}
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*","1")}
#Directories
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(":","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("<","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(">","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("?","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("/","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("|","-")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**********","10")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*********","9")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("********","8")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*******","7")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("******","6")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*****","5")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("****","4")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("***","3")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("**","2")}
Get-ChildItem -Directory -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*","1")}
So this works fine but for some reason I'm getting many error when renaming the folders even though it worked...
Error:
… curse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace("*", …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Source and destination path must be different.
I also tried what this thread suggest but this didn't work for me:
Does anyone have a clue why I'm getting this error? And How to fix it?
Thanks in advance.
The error is normal, if you dont have reasons to rename the directory or file because the filename is ok and no character to modify, the name stays same, so an error is displayed saying you cant rename a file/directory with same name.
Despite this error, the process is not stopped and has no impact on the final result
i suggest you to set all couple key to search , new value in an object:
#add your template to replace
$r = #{
":" = "-"
"<" = "-"
"**********" = "10";
"*********" = "9";
"********" = "8"
}
$Folders=Get-ChildItem -Directory -path -Recurse
foreach($folder in $Folders){
$newname = $folder.Name
foreach($k in $r.Keys){
$newname = $newname.Replace($k,$r.$k)
}
#rename only if original name and newname are differents
if(!$newname.equals($folder.Name)){
Rename-Item -Path $folder.FullName -NewName $newname
}
}
do samething for your files......
On my Windows machine I cannot have characters like that in a file or folder name, but theoretically this should work:
(Get-ChildItem -File) | ForEach-Object {
$_ | Rename-Item -NewName {
# replace the '*' by the number of consecutive asterikses found
$name = $_.Name
$match = ([regex] '(\*+)').Match($name)
while ($match.Success) {
$name = $name -replace [regex]::Escape($match), $match.Length
$match = $match.NextMatch()
}
# finally replace the other special characters by a hyphen
$name -replace '[:<>?/|]', '-'
}
}
the brackets around Get-ChildItem force it to complete the gathering before piping to rename. Otherwise, you may end up trying to rename items that were already processed
You run 10 lines of code to rename only 1 type of match per line but effectively you run the same loop 10 times, in this case your code try to rename all folders every single time, but it errors out when it tries to rename the folder with the same newName , because Rename-Item tries to rename it even if the new name is the same as the old one, it appears to not have a validator for that.
In that case, the "cheapest" solution is to add -ErrorAction SilentlyContinue . But a more sophisticated solution would be to validate your dataset with an if statement or a more appropriate for the case switch .
Update : Regex might not be the easiest thing to deal with, so the example bellow account for the wildcard * character as well.
$allFolders=Get-ChildItem -Directory -Recurse
foreach($folder in $allFolders){
switch -Regex ($folder.Name){
'[:<>?\|]'{
$newName=$folder.Name.replace("[:<>?\|]","-")
Rename-Item -Path $folder.FullName -NewName $newName
}
'\*'{
$regexFormat = '\*'
$matchNumber=[regex]::Matches($folder.Name, $regexFormat) | ForEach-Object { $_.value }
$newName=$folder.Name.replace("*",$matchNumber.Count)
Rename-Item -Path $folder.FullName -NewName $newName
}
}
}
This way, you will run 1 loop instead of 10 and you only try to rename items that matches the pattern you provide, so you will see a significant performance increase compared to the multiline code you are using.
How can I run both 'rename' command and 'hidden' command after I filtered files using Where condition. Each command runs well on its own when placed first, but the second one is neglected.
Get-ChildItem -Recurse -Force | Where {(
$_.Extension -ne ".mp3" -and
$_.Extension -ne ".wmv" )} |
Set-ItemProperty -Name Attributes -Value "Hidden" -WhatIf |
Rename-Item -NewName {$_.Name -replace $_.Extension, -join($_.Extension, ".notmusic")} -
WhatIf
For-Each:
Get-ChildItem -Recurse -Force | Where {( $_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv" )} | ForEach-Object {
$_ | Set-ItemProperty -Name Attributes -Value "Hidden" -WhatIf
$_ | Rename-Item -NewName { $_.Name -replace $_.Extension, -join($_.Extension, ".notmusic")} -WhatIf
}
I use ForEach-Object
Get-ChildItem -Recurse -Force | Where {( $_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv" )} | ForEach-Object {
Set-ItemProperty -Name Attributes -Value "Hidden" -Path $_.FullName -WhatIf
Rename-Item -Path $_.FullName -NewName "$($_.Name).notmusic" -WhatIf
}
I add in Set-ItemProperty -Path
Set-ItemProperty -Name Attributes -Value "Hidden" -Path $_.FullName -WhatIf
i change Rename-Item -Path and -NewName
Rename-Item -Path $_.FullName -NewName "$($_.Name).notmusic"
I see the first couple stanzas grab files in your directory that are not mp3 or wmv files.
Get-ChildItem -Recurse -Force | Where {($_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv")}
That part is good. But since you're taking two actions on each file, you should then pipe to a ForEach-Object in the form of
... | ForEach-Object {
# do something
# do something else
}
And since you're not piping directly into the Set-ItemProperty cmdlet, you'll pass it the path of the filename as such:
Set-ItemProperty -Path $_.FullName -Name Attributes -Value "Hidden"
Then we get to your rename command. Looks like you want the name to be filename.notmusic. Again, we'll need to pass the file path to the cmdlet. Also note how using subexpressions is a clean/nice way of defining the new name
Rename-Item -Path $_.FullName -NewName "$($_.BaseName).notmusic"
Ok so put it all together and we have:
Get-ChildItem -Recurse -Force | Where-Object {($_.Extension -ne ".mp3" -and $_.Extension -ne ".wmv")} | ForEach-Object {
Set-ItemProperty -Path $_.FullName -Name Attributes -Value "Hidden" -WhatIf
Rename-Item -Path $_.FullName -NewName "$($_.BaseName).notmusic" -WhatIf
}
I want this to recurse every directory and create a zero-byte file for every file using the same name as the file with the extension .xxx added. I was thinking New-Item would be good to use here but I cant seem to get it working right.
Here is what I've tried with no success in PS version 2:
$drivesArray = Get-PSDrive -PSProvider 'FileSystem' | select -Expand Root
foreach ($drive in $drivesArray) {
ls "$drive" | where {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ls -ErrorAction SilentlyContinue -recurse | where {
-not $_.PSIsContainer -and
$_.Extension -notmatch '\.xxx|\.exe|\.html'
} | New-Item -Path { $_.BaseName } -Name ($_.FullName+".xxx") -Type File -Force
}
This errors out with
A positional parameter cannot be found that accepts argument "+xxx".
You need to wrap both the second Get-ChildItem (ls) and the New-Item in ForEach-Object statements. Also, do not pass $_.Basename as the path to New-Item. Do it either like this:
New-Item -Path ($_.FullName + '.xxx') -Type File -Force
or like this:
New-Item -Path $_.Directory -Name ($_.Name + '.xxx') -Type File -Force
Modified code:
foreach ($drive in $drivesArray) {
Get-ChildItem $drive | Where-Object {
$_.FullName -notlike "${Env:WinDir}*" -and
$_.FullName -notlike "${Env:ProgramFiles}*"
} | ForEach-Object {
Get-ChildItem $_.FullName -Recurse -ErrorAction SilentlyContinue
} | Where-Object {
-not $_.PSIsContainer -and
$_.Extension -notmatch '^\.(xxx|exe|html)$'
} | ForEach-Object {
New-Item -Path ($_.FullName + '.xxx') -Type File -Force
}
}