Powershell copy and rename files - powershell

I'm trying to copy files from a source folder to a destination folder, and rename the files in the process.
$Source = "C:\Source"
$File01 = Get-ChildItem $Source | Where-Object {$_.name -like "File*"}
$Destination = "\\Server01\Destination"
Copy-Item "$Source\$File01" "$Destination\File01.test" -Force -
Confirm:$False -ErrorAction silentlyContinue
if(-not $?) {write-warning "Copy Failed"}
else {write-host "Successfully moved $Source\$File01 to
$Destination\File01.test"}
The problem is that since Get-ChildItem doesn't throw an error message if the file is not found, but rather just gives you a blank, I end up with a folder called File01.test in destination if no file named File* exists in $Source.
If it does exist, the copy operation carries out just fine. But I don't want a folder to be created if no matching files exist in $Source, rather I just want an error message logged in a log file, and no file operation to occur.

This shouldn't matter what the file name is, but it won't account for files that already exist in the destination. So if there is already File01.txt and you're trying to copy File01.txt again you'll have problems.
param
(
$Source = "C:\Source",
$Destination = "\\Server01\Destination",
$Filter = "File*"
)
$Files = `
Get-ChildItem -Path $Source `
| Where-Object -Property Name -Like -Value $Filter
for ($i=0;$i -lt $Files.Count;$i++ )
{
$NewName = '{0}{1:D2}{3}' -f $Files[$i].BaseName,$i,$Files[$i].Extension
$NewPath = Join-Path -Path $Destination -ChildPath $NewName
try
{
Write-Host "Moving file from '$($Files[$i].FullName)' to '$NewPath'"
Copy-Item -Path $Files[$i] -Destination
}
catch
{
throw "Error moving file from '$($Files[$i].FullName)' to '$NewPath'"
}
}

You can add an "if" statement to ensure that the code to copy the files only runs when the file exists.
$Source = "C:\Source"
$Destination = "\\Server01\Destination"
$File01 = Get-ChildItem $Source | Where-Object {$_.name -like "File*"}
if ($File01) {
Copy-Item "$Source\$File01" "$Destination\File01.test" -Force -Confirm:$False -ErrorAction silentlyContinue
if(-not $?) {write-warning "Copy Failed"}
else {write-host "Successfully moved $Source\$File01 to
$Destination\File01.test"}
} else {
Write-Output "File did not exist in $source" | Out-File log.log
}
In the "if" block, it will check to see if $File01 has anything in it, and if so, then it'll run the subsequent code. In the "else" block, if the previous code did not run, it'll send the output to the log file "log.log".

Related

copy files from folder and then delete some files with an exception

I have folder called Logfolder in C.
C:\LogFolder
it has multiple logs with name as follows
errorLogs.log
errorLogs.log.1
errorLogs.log.2
errorLogs.log.3
Transmitlogs.log
Transmitlogs.log.1
Transmitlogs.log.2
Transmitlogs.log.3
Transmitlogs.log.4
Transmitlogs.log.5
Receivelogs.log
Receivelogs.log.1
Receivelogs.log.2
Receivelogs.log.3
Receivelogs.log.4
Dataexchange.log
Dataexchange.log.1
and many other with the different name but with same extension like .log, .log.1 and so on.
I am interested in only above mention logs.
my goal is to copy this logs starting from log.1 upto log.10 or 20 all which exist and than
delete the original file with an exception .log and .log.1.
I have achieved following until now.
$logLocation = "C:LogFolder"
$tempLocation = "C:\Temp\Logs\"
$LogfileName = "errorLogs.log.", "Transmitlogs.log.","Receivelogs.log.","Dataexchange.log."
foreach ($element in $LogfileName)
{
$NewLogFileName = -join($element,"*")
Copy-Item -Path "$logLocation\$NewLogFileName" -Destination $tempLocation
}
I am able to copy all logs starting from .log.1 and all other which exist.
my problem is how can i delete those logs from original folder without deleting .log and .log.1
I have tried the following but not working.
foreach ($element in $LogfileName)
{
$deleteLogFileName = -join($element,"*")
Remove-Item –path "$logLocation\$deleteLogFileName" -exclude *.log, *.log.1
}
You can do that by selectively copy only file *.log.1 to the destination folder and move the others. That would save you removing files from the source location afterwards.
The thing that matters here most is to get a list of files that
have a numeric extension
have a basename like 'errorLogs.log', 'Transmitlogs.log', 'Receivelogs.log' or 'Dataexchange.log'
Try
$logLocation = "C:\LogFolder"
$tempLocation = "C:\Temp\Logs"
# if the destination folder does not exist yet, creatre it first
if (!(Test-Path -Path $tempLocation -PathType Container)) {
$null = New-Item -Path $tempLocation -ItemType Directory
}
# get an array of objects of the files where the extension ends in a numeric value
# and where the basename is either 'errorLogs.log', 'Transmitlogs.log', 'Receivelogs.log'
# or 'Dataexchange.log'.
$files = Get-ChildItem -Path $logLocation -Filter '*.log*' -File |
Where-Object {$_.Name -match '^(errorLogs|Transmitlogs|Receivelogs|Dataexchange)\.log\.\d+$' } |
Select-Object FullName, #{Name = 'Number'; Expression = {[int]($_.Name.Split(".")[-1])}}
foreach ($file in $files ) {
if ($file.Number -eq 1) {
# this file should be copied
Copy-Item -Path $file.FullName -Destination $tempLocation -Force
}
else {
# the others are to be moved
Move-Item -Path $file.FullName -Destination $tempLocation -Force
}
}

Avoiding File Duplication before Copying files to the folder and Subfolder

I am trying to create a code on Powershell that will actually Copy files from one Location( Lets say A) to location B. Now Location B have two subfolders (lets say X and Y). I need to copy the file from A to B but before copying I need to make sure that the files which I am copying should not be there in X or Y in order to avoid file duplication. If the file exist, it should not copy that particular file.
$PathS = Get-ChildItem -Path "\\sc-y-ap-swt-1\AutoClientFiles\reception\*.txt" |
Where-Object { $_.CreationTime -gt (Get-Date).AddDays(-1) }
$PathD = "C:\OCM\data\EverestSwift\inbound\"
$pathtest = Get-ChildItem -path "C:\OCM\data\EverestSwift\inbound\" -Recurse -File
If((Test-Path -Path "\\sc-y-ap-swt-1\AutoClientFiles\reception\*.txt") -eq $false) {
Exit
} Else {
Try {
Foreach ($File in $Pathtest){
if ($File -eq $PathS ){
Write-Host "Duplicate Files"
exit 1
}
Copy-Item -Path $PathS -Destination $PathD -Force
Exit 0
}
} catch [Exception]{
Write-Host $_.Exception.Message
Exit 1
}
}
You can do this, but why. As Cory said, this is why robocopy exists.
What do you mean by same?
The filename can be the same, but the timestamps can be different, thus making it a different file, even if the name is the same. So, you should be looking at name and timestamp or file hashes.
So, see these Q&A about such a use case.
Does Robocopy SKIP copying existing files by default?
How to skip existing and/or same size files when using robocopy
RoboCopy "%%F" %destination% *.srt *.pdf *.mp4 *.jpg /COPYALL /XO /R:0
Yet, doing this with powerShell, your post could be a duplicate of this one.
Copy items from Source to Destination if they don't already exist
Examples from the above:
$Source = 'C:\SourceFolder'
$Destination = 'C:\DestinationFolder'
Get-ChildItem $Source -Recurse | ForEach {
$ModifiedDestination = $($_.FullName).Replace("$Source","$Destination")
If ((Test-Path $ModifiedDestination) -eq $False) {
Copy-Item $_.FullName $ModifiedDestination
}
}
# Or
$Source = '<your path here>'
$Dest = '<your path here>'
$Exclude = Get-ChildItem -recurse $Dest
Get-ChildItem $Source -Recurse -Filter '*' |
Copy-Item -Destination $Dest -Verbose -Exclude $Exclude

Powershell: You cannot call a null-valued expression

Hello Stack Overflow Community,
at the moment I'm struggling with this code (it's not that beautiful):
$filepath = "C:\inetpub\logs\LogFiles"
$filearchivepath = "C:\inetpub\logs"
$daystoarchive = 1
$_ = "";
function create-7zip([String] $aDirectory, [String] $aZipfile){
#change the path where you downloaded the 7z exe
[string]$pathToZipExe = "C:\Users\kschweiger\Downloads\7za.exe";
[Array]$arguments = "a", "-tzip", "$aZipfile", "$aDirectory";
& $pathToZipExe $arguments;
}
#Create a new folder with the specific date
$ArchiveFolder = (Get-Date -Format dd.MM.yyyy) + " - Logs-Archive"
if(Test-Path "$filearchivepath\$ArchiveFolder"){
Write-Host "Folder already exists!"
}else{
New-Item -Path $filearchivepath -Name $ArchiveFolder -ItemType directory
}
#Save alle files older than X days into $Files
$Files = Get-ChildItem -Path $filepath -Recurse | where {$_.LastWriteTime -lt (Get-Date).AddDays(-$daystoarchive)}
#Copy/Move files and keep folder structure
foreach ($File in $Files){
$NewPath = $File.DirectoryName.Replace($filepath,"")
if (!(Test-Path "$filearchivepath\$ArchiveFolder\$NewPath"))
{
New-Item -Path "$filearchivepath\$ArchiveFolder\$NewPath" -ItemType Directory
}
$File | Copy-Item -Destination "$filearchivepath\$ArchiveFolder\$NewPath"
}
#Compress folder
if(Test-Path "$filearchivepath\$ArchiveFolder.zip"){
Write-Host "Archive-File already exists!"
}else{
#[IO.Compression.ZipFile]::CreateFromDirectory("$filearchivepath\$ArchiveFolder","$filearchivepath\$ArchiveFolder.zip")
create-7zip "$filearchivepath\$ArchiveFolder" "$filearchivepath\$ArchiveFolder.zip"
#Delete Folder
Remove-Item -Path "$filearchivepath\$ArchiveFolder" -Recurse -Force
}
The code works. but I also get a error message called:
You cannot call a null-valued expression
How can I resolve this?
Get-ChildItem by default returns files and folders. If you need only files, you should use -File. Otherwise, your $Files will contain folders too (as they have LastWriteTime property).
If you try to run .DirectoryName.Replace($filepath,"") on a folder, it'll return such error as you cannot run replacing on $null.
Update: for PowerShell 2.0 you can use | where { ! $_.PSIsContainer } (source)
How can I troubleshoot it by myself?
In your error you can see which line is broken:
$NewPath = $File.DirectoryName.Replace($filepath,"")
All you have to do to troubleshoot such situations is to list all the involved variables and check their values. You could do it like this:
$File
$File.DirectoryName
Pause
$NewPath = $File.DirectoryName.Replace($filepath,"")
Using Pause can be useful as it'll wait for you to press Enter before continuing.

Move-item "the path is not supported."

We have a script which is successfully compressing folders to 7z and then deleting the folder once it has been compressed.
What we would like to do is move the compressed 7z file to another location which is on cheaper storage and also for backup / offsite archiving purposes.
I've tried the below but I'm getting an error "the path is not supported."
Is anyone able to assist?
Get-ChildItem 'E:\AbleyTest\TestFolder\_Archived\*' | Where-Object {
$_.PSIsContainer
} | Select-Object -Expand FullName | ForEach-Object {
& 7z.exe a -mx=9 -t7z "$_.7z" "$_"
if ($LastExitCode -eq 0) {
$folder = (Get-Item $_).Parent.Parent.Name
if (Test-Path "e:\archived\$folder") {
Move-Item -Path "$_.7z" -Destination "e:\archived\$folder\$_.7z"
} else {
New-Item "e:\archived\$folder" -Type directory
Move-Item -Path "$_.7z" -Destination "e:\archived\$folder\$_.7z"
}
Remove-Item -Path $_ -Force -Recurse
} else {
Add-Content "e:\scripts\archivelog $(get-date -f dd-MM-yyyy).txt" "$_ ran into error $LastExitCode while archiving"
}
}
Your destination path is not valid. Consider that $_ is the full path to some folder (such as E:\AbleyTest\TestFolder\_Archived\SomeFolder, your destination path of:
"e:\archived\$folder\$_.7z"
suddenly becomes:
e:\archived\TestFolder\E:\AbleyTest\TestFolder\_Archived\SomeFolder.7z
Edit: I just realized that I told you the problem, but didn't really help you solve it. The destination path doesn't need the name of the file (it retains the file name to use at the destination), so simply stop after $folder, and you should be just fine:
Move-Item -Path "$_.7z" -Destination "e:\archived\$folder"

Powershell copy file after a date has passed with file structure

I am trying to copy a file off a server and onto another, I want to keep the structure of the file like so C:\folder\folder\file! If the folder is there copy the file into it, if it is not then create the folders and then copy into it!
I would like it also to filter out the files that are still needed so I want to keep files for 30 days and then move them!
Blockquote
`[int]$Count = 0
$filter = (Get-Date).AddDays(-15).ToString("MM/dd/yyyy")
Get-WMIObject Win32_LogicalDisk | ForEach-Object{
$SearchFolders = Get-Childitem ($_.DeviceID + "\crams") -recurse
$FileList = $SearchFolders |
Where-Object {$_.name -like "Stdout_*" -and $_.lastwritetime -le $filter}
[int]$Totalfiles = ($FileList | Measure-object).count
write-host "There are a total of $Totalfiles found."
echo $FileList
start-sleep 30
[int]
ForEach ($Item in $FileList)
{$Count++
$File = $Item
Write-Host "Now Moving $File"
$destination ="C:\StdLogFiles\"
$path = test-Path (get-childitem $destination -Exclude "Stdout_*")
if ($path -eq $true) {
write-Host "Directory Already exists"
copy-item $File -destination $destination
}
elseif ($path -eq $false) {
cd $destination
mkdir $File
copy-Item $File -destination $destination
}
}
}`
Is what I have so far it has changed a lot due to trying to get it to work but the search works and so does the date part I can not get it to keep the structure of the file!
Okay I took out the bottom part and put in
ForEach ($Item in Get-ChildItem $FileList)
also tried get-content but path is null
{$Count++
$destination = "C:\StdLogFiles"
$File = $Item
Write-Host "Now Moving $File to $destination"
Copy-Item -Path $file.fullname -Destination $destination -force}}
it is copying everything that is in c into that folder but not the files I do not understand what it is doing now! I had it copying the files even wen back to an older version and can't get it to work again! I am going to leave it before I break it more!
Any help or thoughts would be appreciated
I think RoboCopy is probably a simpler solution for you to be honest. But, if you insist on using PowerShell you are going to need to setup your destination better if you want to keep your file structure. You also want to leave your filter date as a [DateTime] object instead of converting it to a string since what you are comparing it to (lastwritetime) is a [DateTime] object. You'll need to do something like:
$filter = (Get-Date).AddDays(-15)
$FileList = Get-WMIObject Win32_LogicalDisk | ForEach-Object{
Get-Childitem ($_.DeviceID + "\crams") -recurse | Where-Object {$_.name -like "Stdout_*" -and $_.lastwritetime -le $filter}
}
$Totalfiles = $FileList.count
For($i = 1;$i -le $TotalFiles; $i++)
{
$File = $FileList[($i-1)]
Write-Progress -Activity "Backing up old files" -CurrentOperation ("Copying file: " + $file.Name) -Status "$i of $Totalfiles files" -PercentComplete ($i*100/$Totalfiles)
$Destination = (Split-Path $file.fullname) -replace "^.*?\\crams", "C:\StdLogFiles"
If(!(Test-Path $Destination)){
New-Item -Path $Destination -ItemType Directory | Out-Null
}
Copy-Item $File -Destination $Destination
}
Write-Progress -Completed
That gathers all the files you need to move from all disks. Takes a count of them, and then enters a loop that will cycle as many times as you have files. In the loop is assigns the current item to a variable, then updates a progress bar based on progress. It then parses the destination by replacing the beginning of the file's full path (minus file name) with your target destination of 'C:\StdLogFiles'. So D:\Crams\HolyPregnantNunsBatman\Stdout04122015.log becomes C:\StdLogFiles\HolyPregnantNunsBatman. Then it tests the path, and if it's not valid it creates it (piped to out-null to avoid spam). Then we copy the file to the destination and move on to the next item. After the files are done we close out the progress bar.