Copy and Rename Files Modified in Last Day Using Powershell - powershell

I am trying to copy over files from a source folder to a destination folder. I would like to only copy files that have been modified in the last 20 mins. While I am copying I would also like to append the date and time to the end of the file name. The script I currently have is:
$DestinationFolder = "C:\Output\"
$timespan = new-timespan -minutes 20
$Files = Get-ChildItem "C:\Input\*" -File
foreach ($File in $Files) {
if ($File.LastWriteTime -gt $timespan)
{
Copy-Item -Path $_.FullName -Destination $DestinationFolder$($_.BaseName)_$ ($_.LastWriteTime.ToString('yyyyMMdd_hhmmss'))$($_.Extension)
}
}
I am getting error messages in powershell when I attempt to test my scipt:
Could not compare "07/21/2017 07:31:01" to "00:20:00". Error: "Cannot convert the "00:20:00" value of type
"System.TimeSpan" to type "System.DateTime"."
At line:2 char:9
+ if ($File.LastWriteTime -gt $timespan)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : ComparisonFailure

You're comparing a DateTime with a TimeSpan. That doesn't make sense. A datetime is a point in time. A timespan is a duration. You need to compare two dates.
Try:
$DestinationFolder = "C:\Output\"
$Cutoff = (Get-Date).AddMinutes(-20)
Get-ChildItem "C:\Input\*" -File | Where-Object {
$_.LastWriteTime -gt $Cutoff
} | ForEach-Object {
$DestinationFileName = '{0}_{1:yyyyMMdd_HHmmss}{2}' -f $_.BaseName, $_.LastWriteTime, $_.Extension
$DestinationFullFileName = Join-Path -Path $DestinationFolder -ChildPath $DestinationFileName
Copy-Item -Path $_.FullName -Destination $DestinationFullFileName
}
I can't tell if there's a bug in your Copy-Item line or not. You may want a dollar sign and a space in there before the date, but I'm guessing that's not right.

According to the error you pasted Powershell is having trouble converting a System.TimeSpan to the type System.DateTime. Those are two different objects and you will have to cast one into the other before they will work together.

Related

using PowerShell to rename all files in a folder to each files last write time

$getdate = Get-Date -Format "yyyymmddHHmmss"
Get-ChildItem -Path C:\blah\*.tiff | foreach { rename-item -Path $_.FullName -NewName "($getdate).tif" }
This just tells me that the file already exists as if its trying to change them all to the same date and time.
This is what each file should be renamed as though but ending in .tif and not .tiff.
Get-ChildItem -Path C:\blah\* | Get-Date -Format "yyyymmddHHmmss"
20221413111408
20222013112039
20225413115422
20221816071813
How do I get this to work so that each file that comes into his folder is renamed when I run this.
I have also tried this:
Get-ChildItem -Path C:\Blah\*.tiff | foreach { rename-item -Path $_.FullName -NewName "Get-Date -Format ("yyyymmddHHmmss").tif" }
Which gives me this error:
Rename-Item : A positional parameter cannot be found that accepts argument 'yyyymmddHHmmss).tif'.
At line:1 char:52
+ ... | foreach { rename-item -Path $_.FullName -NewName "Get-Date -Format ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Rename-Item], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.RenameItemCommand
It's currently trying to rename all files to the same date timestamp because you're asking it to - the value stored in $getdate is not going to automatically update itself :)
Instead, you'll want to call Get-Date every time you rename an individual file by passing a scriptblock to the -NewName parameter - PowerShell will then re-evaluate the scriptblock for every file it's renaming:
Get-ChildItem -Path C:\blah*.tiff |Rename-Item -NewName { "$($_ |Get-Date -Format 'yyyymmddHHmmss').tif" }
As Santiago points out, this will still fail with a naming collision if you have multiple image files that were last written/modified within the same wallclock second.

PowerShell copy-item

I am trying to copy latest 30days files to the folder by this code:
$month = (get-date).AddDays(-30).ToString("yyyMM")
$lastmonthfiles = Write-Host (-join('DCP_', $month,"*.csv"))
Copy-Item -Path Write-Host (-join ("C:\DC+\History\", $lastmonthfiles)) -Destination C:\DC+\History\Backup
but I am having a problem in path in copy-item instruction, which is
Copy-Item : A positional parameter cannot be found that accepts argument 'C:\DC+\History\'.
At line:5 char:1
+ Copy-Item -Path Write-Host (-join ("C:\DC+\History\", $lastmonthfiles ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Copy-Item], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
I am new in PowerShell, and programming so, I could not understand, how can I update and achieve a goal.
Try this:
$Source = Get-Item "C:\Games"
$Destination = "E:\Backup"
$LogFile = "C:\Copy-LogFile.txt"
Copy-Item -Path $( $Source | Where LastWriteTime -LE (Get-Date).AddDays(-30) ) -Destination $Destination -Recurse -PassThru |
Out-File $LogFile -Force
This takes care of your copy function and generates an output log.
Sorry, but your code makes no sense to me...
If it is your aim to copy files to a subfolder in a backup path, try this:
# get the date to use as subfolder to copy to and also to filter the last 30 days files
$refDate = (Get-Date).AddDays(-30).Date # .Date sets it to midnight
# set this variable to the folder where the csv are to be found
$sourceFolder = 'X:\Path\To\Where\The\Files\Are'
# create a destination path to copy to (just a string)
$destination = Join-Path -Path 'C:\DC+\History\Backup' -ChildPath ($refDate.ToString("yyyMM"))
# create this destination folder
$null = New-Item -Path $destination -ItemType Directory -Force
# get the files and copy them to the destination folder
Get-ChildItem -Path $sourceFolder -Filter '*.csv' -File | # filter on CSV fies only
Where-Object { $_.LastWriteTime -ge $refDate } | # filter on date 'last 30 days'
Copy-Item -Destination $destination -Force

Powershell | Rename file with random name

I'm making a script to rename a specific file with a random name. But when running, the following error always occurs:
It is not possible to convert the value ".jpg" to the type "System.Int32". Error: "The input string was not in the correct format."
In C:\Windows\system32\WindowsPowerShell\v1.0\Modules\SetDiscordWallpaper\SetDiscordWallpaper.ps1:7 character:7
+ Rename-Item -Path $file.FullName -NewName ($random + $file.Exte ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastFromStringToInteger
Here is the code I am using
function Set-DiscordWallpaper {
$path = "C:\Windows\Temp\*"
foreach($file in $(Get-ChildItem -Path $path -Include "Wallpaper.jpg")) {
$extension = [System.IO.Path]::GetExtension($file.FullName);
$randomName = [System.IO.Path]::ChangeExtension([System.IO.Path]::GetRandomFileName(), $extension)
$newPath = "C:\inetpub\wwwroot\"
Write-Host "Changing File $($file.Name) to $randomName"
Move-Item -Path $file.FullName -Destination $newPath
}
}
I ask you to help me please. I'm waiting the answer. Thanks
The code (second part in your question) creates the new random filename just fine, only the line Move-Item -Path $file.FullName -Destination $newPath does nothing with that new name and moves the file with its original name to the new path.
Change that line to
Move-Item -Path $file.FullName -Destination (Join-Path -Path $newPath -ChildPath $randomName)
so the file gets moved with the random name in the new path.
Or is your intention to copy the file to its new destination keeping the original filename there and after that rename the original?
In that case do:
Write-Host "Changing File $($file.Name) to $randomName"
Copy-Item -Path $file.FullName -Destination $newPath # copy with original name
$file | Rename-Item -NewName $randomName # rename the original file

How to move and rename multiple files using powershell?

I have a large number of files (>4 million) and need to rename and move them to another folder in small steps.
I am a total beginner in powershell, but I already managed to move them in small packages of 100 files (the powershell script is executed as scheduled task).
But so far I failed with renaming the files. In each file, there are two strings that need to be replaced.
The following codes works fine, except for the renaming part (line 12 and 13):
#Get 'n' number of files
$FileLimit = 100
$PickupDirectory = Get-ChildItem -Path "\\server\path$\ERROR\subfolder\"
$DropDirectory = "\\server\path$\destination\"
$Counter = 0
foreach ($file in $PickupDirectory)
{
if ($Counter -ne $FileLimit)
{
$file | Rename-Item -NewName {$_.name -replace '999999','367'}
$file | Rename-Item -NewName {$_.name -replace 'oldname','newname'}
$Destination = $DropDirectory+$file.Name
Move-Item $file.FullName -destination $Destination
$Counter++
}
}
exit
What is the correct way to rename those files?
Thank you so much for your help!
Best wishes
Philipp
Edit: Sorry, here's the Error Log :
Rename-Item : Cannot rename because item at 'Microsoft.PowerShell.Core\FileSystem::\\server\path$\ERROR\subfolder\1566392#5990762$20180116^999999_2018_01_16_oldname_1566392_Kägi.pdf' does not exist.
At C:\Scripts\mv_Verordnung_für_Physiotherapie.ps1:12 char:28
+ ... pDirectory | Rename-Item -NewName {$_.name -replace '^999999','^367'}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Rename-Item], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.RenameItemCommand
Edit2: Updated the code with tipps from comments. Error still the same.
You should do the limiting (if necessary at all) earlier with the Get-ChildItem =>
$PickupDirectory = Get-ChildItem -Path "\\server\path$\ERROR\subfolder\" | Select -First $FileLimit
Instead of using the currently iterated item ($file) you use the whole array $PickupDirectory
You can't apply the 2. replace to an already changed value.
instead of rename and move do it in one step.
#Get 'n' number of files
$FileLimit = 100
$PickupDirectory = Get-ChildItem -Path "\\server\path$\ERROR\subfolder\" | Select -First $FileLimit
$DropDirectory = "\\server\path$\destination\"
foreach ($file in $PickupDirectory){
$Destination = Join-Path $DropDirectory ($file.Name -replace '^999999','^367' `
-replace 'oldname','newname')
$file | Move-Item -Destination $Destination
}
You're calling Rename-Item on the $PickupDirectory collection. Instead call it on the $file variable you are using in the foreach loop:
$file | Rename-Item -NewName { $_.name -replace '^999999', '^367' }
$file | Rename-Item -NewName { $_.name -replace 'oldname', 'newname' }

How to move folders from one location to another using PowerShell

So i have a directory full of folders that i want to move to another area, also i only want to move the folders that were created 30 days ago or more. I have a script that does what i need for files but it doesnt seem to work for folders. Script is below
Script for moving files
param (
[Parameter(Mandatory=$true)][string]$destinationRoot
)
$path = (Get-Item -Path ".\").FullName
Get-ChildItem -Recurse | ?{ $_.PSIsContainer }
Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} |
Foreach-Object {
$content = $path + "\" + $_.Name
$year = (Get-Item $content).LastWriteTime.year.ToString()
$monthNumber = (Get-Item $content).LastWriteTime.month
$month = (Get-Culture).DateTimeFormat.GetMonthName($monthNumber)
$destination = $destinationRoot + "\" + $year + "\" + $month
New-Item -ItemType Directory -Force -Path $destination
Move-Item -Path $content -Destination $destination -force
}
The Get-ChildItem portion does not seem to pull directories in like it should.
So looking at the script i decided to change some things up
Function Move-FilesByAge(){
param (
[Parameter(Mandatory=$true)][string]$Source,
[Parameter(Mandatory=$true)][string]$Destination,
[Parameter(Mandatory=$true)][timespan]$AgeLimit
)
Get-ChildItem $Source -Directory -Recurse | ?{
$($_.CreationTimeUtc.Add($AgeLimit)) -lt $((Get-Date).ToUniversalTime())
} | %{
$Dpath = $Destination + "\" + $_.CreationTimeUtc.ToString("yyyy") + "\" + $_.CreationTimeUtc.ToString("MMMM")
New-Item -ItemType Directory -Force -Path $Dpath
Move-Item $_ -Destination $Dpath -Force
}
}
Move-FilesByAge -Source C:\Test -Destination C:\Test2 -AgeLimit (New-TimeSpan -days 30)
This can lead to a major issue. If a folder with the same name exists then it will pop a error that folder exists.
Since you are new to powershell lets go over some basics about this script. In Powershell we love Piping | which you did well in the original. We also a big fan of aliases Where-Object ?{}, Foreach-Object %{}.
Get-ChildItem has a built in switch for just returning directories -directory.
You are also using last LastWriteTime when you should be using CreationTime. CreationTimeUtc allows you to standardize your time across timezones by providing a base timezone.
Date.ToString(Date Format Here). IS a great way to shorten how you parse the date as a string. .ToString("yyyy") gets you the year in 4 numbers like 2018. .ToString("MMMM") will get the month by name like March.