PowerShell complaining about path, But path is valid - powershell

In the following code, when $client = XRS1
if (Test-Path C:\dbbackups\cm_$client-*.full.bak){
Rename-Item -path C:\dbbackups\cm_$client-*.bak -newname cm_$client.bak
Write-Host "New file found, renamed to: cm_$client.bak"
The Test-Path statement can find C:\dbbackups\cm_xrs1-2013414.full.full.bak but -path in the Rename-Item can't.
The error I get is
Rename-Item : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path" argument and run the operation again.
At C:\Users\Aaron\Documents\0000 - PowerShell DB Update Utility\UpdateCMDatabases.ps1:167 char:1
+ Rename-Item -path C:\dbbackups\cm_$client-*.bak -newname cm_$client.bak
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Item], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.RenameItemCommand

For those who need only a one line command, please note that this is a powershell only error and that this command works just fine in the good old command prompt.
The full form of the powershell command is
ren -Path [something with a wildcard] -NewName [something else]
The error relates to the value of the Path parameter. It accepts wildcards in the path but it must resolve to a single file [1]. To use wildcards with powershell, you'll need to pipe them one by one to the rename item command. Here is an example to rename txt files to log [2]:
get-childItem *.txt | rename-item -newname { $_.name -replace '\.txt','.log' }

If Rename-Item does not like a wildcard, then do not give it one
Convert-Path C:\dbbackups\cm_$client-*.full.bak | % {
if (Test-Path $_) {
Rename-Item $_ cm_$client.bak
}
}

Related

How do I remove a leading or trailing blank space in file name with PowerShell?

I'm basically trying to trim() any filenames that have a leading or trailing space at the end of the name. This is the code I've got so far
$foldersToCheck = "$env:userprofile\documents", "$env:userprofile\pictures", "$env:userprofile\desktop"
foreach ($folder in $foldersToCheck) {
get-childitem -path $folder -recurse | foreach-object {
if ($_.name.startswith(" ") -or $_.name.endswith(" ")) {
$newName = $_.name.trim()
rename-item -path $_ -newName $newname
}
}
}
If I create a test file (c:\users\someusername\desktop\ test.txt), then I receive this error
rename-item : Cannot rename because item at ' test.txt' does not exist.
At line:6 char:13
+ rename-item -path $_ -newName $newname
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
So, it looks like it found the file that needs to be renamed, but then says it doesnt exist.
The problem here is that PowerShell resolves $_ to just the file name when attempting to convert it to a string it can bind to -Path.
Explicitly pass the full path of the file and it'll work:
Rename-Item -Path $_.FullName -NewName $newname
Alternatively, pipe the $_ file object to Rename-Item and PowerShell will automatically figure out that it needs to bind $_.FullName to Rename-Item's -LiteralPath parameter:
$_ |Rename-Item -NewName $newname
You can also turn the whole loop into a single pipeline, and then take advantage of a pipeline-bound expression against -NewName:
$foldersToCheck |Get-ChildItem -Recurse |Rename-Item -NewName { $_.Name.Trim() }
If the existing Name and the -NewName values are the same, Rename-Item will just leave the files alone anyway :)

Recursively Search Dirs & SubDirs And Numerically Rename Files

I am attempting to recursively scan a directory and rename all .jpg and .jpeg files in the dirs (and sub dirs) to a numeric naming convention.
I have this syntax
get-childitem -Recurse -path C:\Users\jsimpson\Desktop\Test123 | where {($_.extension -eq '.jpg') -or ($_.extension -eq '.jpeg') | %{Rename-Item $_ -NewName (‘MyFile{0}.txt’ -f $nr++)}
However - this gives me an error of
Missing closing '}' in statement block or type definition.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingEndCurlyBrace
I am sure this is something mundane on my end that I am overlooking - but what would be the proper syntax to numerically rename all files?
EDIT
Current filename is P1870426.jpeg I want to rename it to 1.jpeg
The files are all an import from a digital camera and Since the files have garbage names - I am basically wanting a way to import them into a program and have the files remain in the same order.
As the error message says, there's a } missing to close Where :
Get-ChildItem -Recurse -Path 'C:\Users\jsimpson\Desktop\Test123' | Where-Object {$_.Extension -match 'jpg|jpeg'} | ForEach-Object {
$newFile = "{0}$($_.Extension)" -f $nr++
Rename-Item $_.FullName -NewName $newFile -Force
}

PowerShell: Rename multiple folders using $_.FullName.Replace

I have a google drive folder that occasionally gets out of sync. Google (or someone) will append (1) to the directory/file names. Then it will remove the original directory and I'll have a bunch of folders and files named "xxx (1)".
I've been trying to write a powershell script that will crawl the directory tree and rename the folders/files by simply removing the " (1)" portion. I realize that this may result in some collisions, but I was hoping to get most of them replaced using a script. I'm not that concerned about the directory structure, I'll restore if needed, but it's just kind of a nuisance.
I've tried several powershell scripts, and the closest I've come so far is this...
This will return the correct NEW folder names
Get-ChildItem -Path "* (1)" -Recurse | select { $_.FullName.Replace(" (1)", "")}
So I tried this...
Get-ChildItem -Path "* (1)" -Recurse | Replace-Item -Path $_.FullName -Destination $_.FullName.Replace(" (1)", "") -WhatIf
I get the error "You cannot call a method on a null-valued expression."
You cannot call a method on a null-valued expression.
At line:1 char:1
+ Get-ChildItem -Path "* (1)" -Recurse | rename-item $_.FullName $_.Fu ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Try surrounding the last half in a foreach-object, using Rename-Item instead of Replace-Item, etc etc:
Get-ChildItem -Path "* (1)" -Recurse | ForEach-Object {Rename-Item -Path $_.Fullname -NewName $($_.Name.Replace(" (1)", "")) -WhatIf}
$_ is only a variable inside a scriptblock. With:
.. | select { $_.FullName.Replace(" (1)", "")}
You can get-help select-object and see the first positional parameter is -Property, so this is short for
.. | Select-Object -Property { $_.FullName.Replace(" (1)", "") }
And now you can see the scriptblock gets the files in via the pipeline, accesses them as $_ and calculates a new Property for the output, and the $_ is used once for each file. When you try to use the same technique in your second line:
.. | Replace-Item -Path $_.FullName -Destination $_.FullName.Replace(" (1)", "") -WhatIf
The $_ is just free-floating, you can't use it like that, outside a {} scriptblock it doesn't mean anything. And you're piping the input files in through the pipeline and also trying to specify them with -Path, which is doubling up - clashing and redundant. And you're using Replace instead of Rename.
So in the other answer, nferrell uses ForEach to create a scriptblock. And pipes the files into ForEach and then specifies their name to the -Path of Rename-Item.
Which works, but it's wordy and roundabout. Why take the filenames out of the pipeline and use ForEach to shuffle them round to the other end of the cmdlet, only to put them straight back in?
Get-ChildItem .. | Rename-Item -NewName { $_.Name.Replace(" (1)", "") }
Files go in by the pipeline, NewName is calculated. No loop, no doubling up of input, no

ItemNotFoundException calling Remove-Item from pipeline on files outside the curent directory

Suppose I have the following files I'd like to remove from multiple directories.
PS d:\path> $files = gci -path . -Recurse -File
PS d:\path> $files
d:\path\foo.txt
d:\path\sub\bar.txt
I use foreach to call Remove-Item.
PS d:\path> $files | foreach { Remove-Item -Path $_ -WhatIf }
What if: Performing the operation "Remove File" on target "D:\path\foo.txt".
Remove-Item : Cannot find path 'D:\path\bar.txt' because it does not exist.
At line:1 char:19
+ $files | foreach { Remove-Item -Path $_ -WhatIf }
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (D:\path\bar.txt:String) [Remove-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
It would seem that when passed a recursive list of files, Remove-Item always tries to remove a file from the current directory. It can remove d:\path\foo.txt just fine. But it throws an error trying to remove d:\path\bar.txt, because there is no such file. The file it should be deleting is located in d:\path\sub\bar.txt.
Note that the following code works fine, presumably because the Get-ChildItem is not recursive.
PS D:\path> del .\sub\bar.txt -WhatIf
What if: Performing the operation "Remove File" on target "D:\path\sub\bar.txt".
PS D:\path> gci .\sub\bar.txt | % { del $_ -WhatIf }
What if: Performing the operation "Remove File" on target "D:\path\sub\bar.txt".
Is this a bug in PowerShell, or am I not using it right? Is there a different prescribed way to delete files recursively, subject to pipeline filtering?
Other notes:
Including the -WhatIf parameter doesn't affect the issue here; it just forces Remove-Item to print output instead of deleting my test files.
I can't just pass -Recurse to Remove-Item because in my actual code I'm doing non-trivial filtering on the pipeline to choose which files to delete.
This is Powershell v4.0 on Windows 8.1
Instead of using foreach-object you can just use:
$files | Remove-Item -WhatIf
$files returns objects of type : System.IO.FileSystemInfo
if you run :
help Remove-Item -Parameter path
you will see that the path parameter accepts an array of strings.
$files[0].gettype() is not a string so some type conversion has to happen
$files | foreach { Remove-Item -Path $_.FullName -WhatIf }

Cannot Bind Argument to Parameter 'NewName' because it is an empty string

Get-ChildItem -Name *.txt | Rename-Item -NewName { $_.name -replace '\.txt','.log' }
I have 3 text files in my current path, I'm using this snip bit of code found in the last example of...
get-help rename-item -full
(Powershell Version 2.0). For whatever reason, I keep receiving the following error:
Rename-Item : Cannot bind argument to parameter 'NewName' because it is an empty string.
At line:1 char:40
+ Get-ChildItem -Name *.txt | Rename-Item <<<< -NewName { $_.name -replace
'\.txt','.log' }
+ CategoryInfo : InvalidData: (testfile3.txt:PSObject) [Rename-Item],
ParameterBindingValidationException
+ FullyQualifiedErrorId :
ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.Rena
meItemCommand
Clearly my alteration form .txt to .log isn't an empty string, and this matches exactly the same code as in found in Microsoft's last example of the cmdlet rename-item.
Either don't use the -Name parameter since that outputs just strings containing the full path or don't reference the Name property:
Get-ChildItem -Name *.txt | Rename-Item -NewName { $_ -replace '\.txt','.log' }