Out-File or Add-Content result in empty file - powershell-2.0

Why does this
Try{ Copy-Item -Path "D:\file.txt" -Destination "E:\file.txt"}
Catch { $_.Exception.Message|Add-Content C:\logs\copy.log}
give me an empty file? The log file exists. I have read&write permission to both file and D: drive. I've also tried with Out-File -append and `Out-File $_.Exception.Message, but I am not capturing any errors. The error is thrown in the console, telling me that
Copy-Item : Cannot find path 'D:\file.txt' because it does not exist. (...)

Thank you to #kim: Adding -ErrorAction Stop did the trick!
Try{ Copy-Item -Path "D:\file.txt" -Destination "E:\file.txt" -ErrorAction Stop}
Catch { $_.Exception.Message|Add-Content C:\logs\copy.log}

Related

Rename files with same name and extension (usually .pdf) in the sub directories with incrementing number

My folder structure is like this:
Folder 1
File 1.pdf
File 2.pdf
File 3.pdf
Folder 2
File 1.pdf ---> Rename this to "File 1-1.pdf"
File 2.pdf ---> Rename this to "File 2-1.pdf"
File 5.pdf
SubFolder 2.1
File 2.pdf ---> Rename this to "File 2-2.pdf"
File 4.pdf
File 5.pdf ---> Rename this to "File 5-1.pdf"
Folder 3
File 1.pdf ---> Rename this to "File 1-2.pdf"
File 2.pdf ---> Rename this to "File 2-3.pdf"
File 4.pdf ---> Rename this to "File 4-1.pdf"
File 6.pdf
File 7.pdf
This is what i was trying, but its certainly wrong. I am using Powershell Version 2.0.
$i = 1
$folder = Get-ChildItem "C:\Users\xyz\testfolder\pdf_files\"
foreach ($file in $folder){
if (($file.BaseName + $file.extension) -match ($file.BaseName +
$file.extension)){
Rename-Item -Path $file.FullName -NewName "$($file.BaseName +
$i)$($file.extension)" -Verbose -WhatIf
$i++
}
}
I just found the answer to my question through a very kind person. Anyway..here is the PS script that worked for me..
$Files = Get-ChildItem -LiteralPath 'C:\Foo\Bar\Files\' -Recurse | Where-
Object { -not $_.PSIsContainer }
$FileNameCounts = #{}
ForEach ($File In $Files) {
$BaseName = $File.BaseName
If ($FileNameCounts.Keys -contains $BaseName) {
$NewName = '{0}-{1}{2}' -f $BaseName, $FileNameCounts[$BaseName],
$File.Extension
$File | Rename-Item -NewName $NewName -WhatIf
$FileNameCounts[$BaseName]++
} Else {
$FileNameCounts[$BaseName] = 1
}
}
Here is an alternative way of doing the same thing.
Get-ChildItem -Recurse -file | Group-Object Name | foreach-object {
$script:i = 1
$_.Group | Select-Object -Skip 1 |
Rename-Item -newname { "{0}-{1}{2}" -f $_.basename, $script:i++, $_.extension }
}
Group-Object gives us all the files with the same name, and for each group of names, the first file is skipped and the rest is being renamed.
It also takes advantage of a feature that was designed specifically for this usecase, that -NewName can take a scriptblock as a parameter. The scriptblock will be invoked for each pipeline item and the result will be passed to Rename-Item as the newname.

powershell v2 - rename a file whose name matches a string containing a wildcard

I'm trying to create a script to rename a file that matches a given filename, with a wildcard character. e.g.
I have a folder containing the following files:
201412180900_filename_123.log
201412181000_filename_123.log
201412181100_filename_456.log
filename_789.log
I want to scan through this folder, and append the current time to the start of any file starting with the word 'filename'
I have the following so far:
$d = Get-Date -format "yyyyMMddHHmm"
$dir = "C:\test"
$file = "filename*.log"
get-childitem -Path "$dir" | where-object { $_.Name -like "$file" } | rename-item -path $_ -newname $d."_".$_.name
but it doesn't work.
As I see it the individual sections 'should' work from my reading of the documentation, but clearly something is wrong. If someone can point it out it would be appreciated.
We're getting closer. It would appear that -path in the rename-item section needs to be $dir$_ as $_ (seemingly) only contains the filename. (The get-help example suggests it needs to be the full path and filename)
If I take out the rename-item section and replace it with %{write-host $d"_"$_} it gives the correct new filename
However, simply placing this into rename-item section still doesn't update the filename.
rename-item -path $dir$_ -newname $d"_"$_
SUCCESS
the correct syntax appears to be:
get-childitem -Path "$dir" | where-object { $_.Name -like "$file" } | %{rename-item -path $dir$_ -newname $d"_"$_}
The missing element was the %{ ... } surrounding the rename-item section which enabled me to reference $_
$d = Get-Date -format "yyyyMMddHHmm"
$dir = "C:\test"
$file = "filename*.log"
get-childitem -Path $dir | where-object { $_.Name -like $file } | %{ rename-item -LiteralPath $_.FullName -NewName "$d`_$($_.name)" }
This should work, assuming that the errors were relating to "Cannot bind argument to parameter 'Path'", and the NewName string.
Issues included:
Not being able to reference $_ when not in a foreach style block (see here)
The Concatenation issue raised by #alroc
You could, instead of passing the pipeline object to a Foreach-Object, pass directly to the Rename-Item - but I'm unsure quite how to reference the name of the object for the -NewName parameter.
I don't recall . being a string concatenation operator in PowerShell (I may be wrong). Try this:
rename-item -path $_ -newname "$d_$($_.name)"
Or this
rename-item -path $_ -newname ($d + "_" + $_.name)
Or even this
rename-item -path $_ -newname ({0}_{1} -f $d,$_.name)
See the answers here
Yet another way to do it without using foreach or %, but a script block instead:
get-childitem -Path "$dir" -filter $file | rename-item -newname { $d + "_" + $_.name }
See the examples in the doc for rename-item: https://msdn.microsoft.com/en-us/powershell/reference/3.0/microsoft.powershell.management/rename-item There's a -replace operator too, but it can't use wildcards? Oh, you don't need wildcards:
get-childitem -Path "$dir" -filter $file | rename-item -newname { $_.name -replace 'filename',($d + '_filename') }

Can't replace file names with PowerShell 2.0

I have files like this.
[mix]aaaa.flv
[mix]aaaa.mpv
[mix]aaaa.ogv
[mix]aaaa.webm
[mix]bb.flv
[mix]bb.mpv
[mix]bb.ogv
[mix]bb.webm
...
I just need to remove "[mix]" from the file names.
I use this command, but failed
Dir | Rename-Item –NewName { $_.name –replace "[mix]", "" }
Error says
Rename-Item : 'Microsoft.PowerShell.Core\FileSystem::C:\Users\Desktop\[mix]aaaa.mp4'에 항목이 없으므로 이름을 바꿀 수 없습니다.
위치 줄:1 문자:18
+ Dir | Rename-Item <<<< –NewName { $_.name –replace “[mix]“,”” }
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
There's korean in error code, it might say : Can't change name, there is no item at 'Microsoft.PowerShell.Core\FileSystem::C:\Users\Desktop\[mix]aaaa.mp4'
And I don't understand what I'm doing wrong. I used to change file names with this command.
I think this is a known bug with Rename-Item and powershell 2.0
What I did was to use Move-Item instead, you should be able to use the following (tested on powershell 2.0):
Dir | Move-Item -Destination {$_.Name -replace "\[mix\]", ""}
I was able to make this work. Remember that [ and ] are regex metacharacters and need to be escaped:
Dir | Rename-Item -NewName {$_.Name -replace "\[mix\]",""}

What is wrong with this script to create files in all subfolders?

I have a directory tree, consisting of several layers, within which I want to create 30 placeholder files, recursively in each folder.
The tree looks something like this:
--F:\inbox\test
----folder1
------subfolder1
------subfolder2
----folder2
------subfolder1
------subfolder2
----folder3
------subfolder1
------subfolder2
Here is what I have.
$folders = gci -path f:\inbox\test -recurse | where {$_.PsIsContainer}
foreach ($folder in $folders) {
1..30 | % { New-Item -Name "$_.txt" -Value (get-date).tostring() -Itemtype file -force}
}
This just creates 30 files in the root folder. I know I am missing something in my logic.
You're not telling new-item where to put the file, so it uses the current working directory. Fortunately, this is easliy fixed with the -Path parameter for the cmdlet.
$folders = gci -path f:\inbox\test -recurse | where {$_.PsIsContainer}
foreach ($folder in $folders) {
1..30 | % { New-Item -Path $folder.FullName -Name "$_.txt" -Value (get-date).tostring() -Itemtype file -force}
}

Unable to collect *.bak files as a single object

I am new to PowerShell.
I wanted to write a simple program to list all *.bak files which I can then either sort by date or size as shown below.
$Drives = Get-WMIObject -class win32_logicaldisk -filter "DriveType = 3" ;
foreach ($d in $Drives){
If (($d.deviceId -ne "C:") -and ($d.VolumeName -ne "PAGEFILE")) {
$backups += Get-ChildItem -Path $d.deviceID -Recurse -filter *.bak
}
This generally works fine except when say for example D: drive has only one *.bak file.
In that case I get an error.
Method invocation failed because [System.IO.FileInfo] doesn't contain a method named 'op_Addition'.
At F:\work\PowerShell\DiskSpace\generate-disk-report-v2.ps1:39 char:13
+ $backups += <<<< Get-ChildItem -Path $d.deviceID -Recurse -filter *.bak
+ CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
If I add an additional junk.bak to that drive, it works fine.
In my case, I found that the variable needs to be initialized as an array and Get-ChildItem needs to be returned as an array even, or especially, if it's only returning one file.
In your case:
$backups = #() - (Before calling Get-ChildItem)
and
$backups = #(Get-ChildItem -Path $d.deviceID -Recurse -filter *.bak) - (Cast as an array)

Resources