Make temporary backup files in the same folder structure - powershell

Below is a full path to some files that have a specific file pattern I'm looking for. The files are not all located in the same location, however, I would like to change the ".gen" to ".tmp" for a short period of time while still maintaining ".gen" in its entirety.
D:\Example\CommonData\Settings\ConnectionSettings.config.gen
D:\Example\CommonData\Settings\FileExtensions.config.gen
D:\Example\WebApps\Website\Web.config.gen
D:\Example\Test\SCM\Config.Files\Some.Other.thing.config.gen
What I would like to do:
D:\Example\CommonData\Settings\ConnectionSettings.config.gen
D:\Example\CommonData\Settings\ConnectionSettings.config.tmp
D:\Example\CommonData\Settings\FileExtensions.config.gen
D:\Example\CommonData\Settings\FileExtensions.config.tmp
D:\Example\WebApps\Website\Web.config.gen
D:\Example\WebApps\Website\Web.config.tmp
D:\Example\Test\SCM\Config.Files\Some.Other.thing.config.gen
D:\Example\Test\SCM\Config.Files\Some.Other.thing.config.tmp
I've tried so far:
Get-ChildItem *.config.gen | ForEach {
$NewName = $_.Name -replace ".config.gen$", ".config.tmp"
Copy-Item $_ $NewName
}
Is what I'm trying to do more easier to do with xcopy or robocopy versus Copy-Item? If so, how would I go about using something other than Copy-Item.

Since you want the destination items renamed Get-ChildItem/Copy-Item is the better approach here. Something like this should work:
Get-ChildItem *.config.gen -Recurse |
Copy-Item -Destination { Join-Path $_.Directory ($_.BaseName + '.tmp') }

Related

concatenate columnar output in PowerShell

I want to use PowerShell to generate a list of commands to move files from one location to another. (I'm sure PowersSell could actually do the moving, but I'd like to see the list of commands first ... and yes I know about -WhatIf).
The files are in a series of subfolders one layer down, and need moved to a corresponding series of subfolders on another host. The subfolders have 8-digit identifiers. I need a series of commands like
move c:\certs\40139686\22_05_2018_16_23_Tyre-Calligraphy.jpg \\vcintra2012\images\40139686\Import\22_05_2018_16_23_Tyre-Calligraphy.jpg
move c:\certs\40152609\19_02_2018_11_34_Express.JPG \\vcintra2012\images\40152609\Import\19_02_2018_11_34_Express.JPG
The file needs to go into the \Import subdirectory of the corresponding 8-digit-identifier folder.
The following Powershell will generate the data that I need
dir -Directory |
Select -ExpandProperty Name |
dir -File |
Select-Object -Property Name, #{N='Parent';E={$_.Directory -replace 'C:\\certs\\', ''}}
40139686 22_05_2018_16_23_Tyre-Calligraphy.jpg
40152609 19_02_2018_11_34_Express.JPG
40152609 Express.JPG
40180489 27_11_2018_11_09_Appointment tuesday 5th.jpg
but I am stuck on how to take that data and generate the concatenated string which in PHP would look like this
move c:\certs\$Parent\$Name \\vcintra2012\images\$Parent\Import\$Name
(OK, the backslashes would likely need escaped but hopefully it is clear what I want)
I just don't know to do this sort of concatenation of columnar output - any SO refs I look at e.g.
How do I concatenate strings and variables in PowerShell?
are not about how to do this.
I think I need to pipe the output to an expression that effects the concatenation, perhaps using -join, but I don't know how to refer to $Parent and $Name on the far side of the pipe?
Pipe your output into a ForEach-Object loop where you build the command strings using the format operator (-f):
... | ForEach-Object {
'move c:\certs\{0}\{1} \\vcintra2012\images\{0}\Import\{1}' -f $_.Parent, $_.Name
}
Another approach:
$source = 'C:\certs'
$destination = '\\vcintra2012\images'
Get-ChildItem -Path $source -Depth 1 -Recurse -File | ForEach-Object {
$targetPath = [System.IO.Path]::Combine($destination, $_.Directory.Name , 'Import')
if (!(Test-Path -Path $targetPath -PathType Container)) {
New-Item -Path $targetPath -ItemType Directory | Out-Null
}
$_ | Move-Item -Destination $targetPath
}

Powershell change extension

I have a problem with change extension of a file. I need to write a script which is replicating data, but data have two files. Filename is not a string, so we can't use normal -replace
I need to get from
filename.number.extension
this form
filename.number.otherextension
We try to use a split, but this command show us things like below
filename
number
otherextension
Thanks for any ideas,
[System.IO.Path]::ChangeExtension("test.old",".new")
You probably want something like the -replace operator:
'filename.number.extension' -replace 'extension$','otherextension'
The $ is regular expression syntax meaning end of line. This should ensure that the -replace does not match "extension" appearing elsewhere in the filename.
A simple Utility Function
<#
# Renames all files under the given path (recursively) whose extension matches $OldExtension.
# Changes the extension to $NewExtension
#>
function ChangeFileExtensions([string] $Path, [string] $OldExtension, [string] $NewExtension) {
Get-ChildItem -Path $Path -Filter "*.$OldExtension" -Recurse | ForEach-Object {
$Destination = Join-Path -Path $_.Directory.FullName -ChildPath $_.Name.Replace($OldExtension, $NewExtension)
Move-Item -Path $_.FullName -Destination $Destination -Force
}
}
Usage
ChangeFileExtensions -Path "c:\myfolder\mysubfolder" -OldExtension "extension" -NewExtension "otherextension"
But it can do more than just this. If you had the following files in the same folder as your script
example.sample.csv
example.txt
mysubfolder/
myfile.sample.csv
myfile.txt
this script would rename all the .sample.csv files to .txt files in the given folder and all subfolders and overwrite any existing files with those names.
# Replaces all .sample.csv files with .txt extensions in c:\myfolder and in c:\myfolder\mysubfolder
ChangeFileExtensions -Path "c:\myfolder" -OldExtension "sample.csv" -NewExtension "txt"
If you don't want it to be recursive (affecting subfolders) just change
"*.$OldExtension" -Recurse | ForEach-Object
to
"*.$OldExtension" | ForEach-Object
This could work:
Get-ChildItem 'C:\Users\Administrator\Downloads\text files\more text\*' *.txt | rename-item -newname { [io.path]::ChangeExtension($_.name, "doc") }
You can remove the last item with the the [0..-1] slice and add the new extension to that
(("filename.number.extension" -split "\.")[0..-1] -join '.') +".otherextension"

Powershell: Copying files from multiple folders created x days while maintaining folder structure

I am having issues maintaining the folder structure during a Powershell copy using FOREACH loops as some folders under the parent folder need the data created longer than 90 days ago whereas others 180.
$Folders_90Days = "C:\Admin\Ripley","C:\Admin\Android","C:\Admin\Bishop"
$Folders_180Days = "C:\Admin\Archer","C:\Admin\Figgis","C:\Admin\Pam"
$Dest = 'D:\Archive_Target'
FOREACH($path in $Folders_90Days){
$files = (Get-ChildItem $path | Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-90)})
ForEACH($file in $Files){
Copy-Item $file.FullName -destination $Dest -Recurse
}
#End ForEach Folders_90Days loop
}
When the copy runs, the data copied from the source folders is copied directly into the target.
So in essence the data in Ripley copies directly to Archive_Target.
How can I get it to copy with the source folder becoming the target folder?
Example:
D:\Archive_Target\Ripley
- All the while maintaining the folder structure of Source Ripley?
Ive created a function that does exactly this without xcopy.
I put it in a workflow that allows Parallel processing.
Using Regex I get the folder that is the base for the source. If the path isnt there create it, else the real meat is in the pipe.
Get all items in source, pipe to a if older then AgeInDays then copy the item and its container which allows for the file structure to keep the same.
workflow Copy-ItemBasedOnCreation{
Param(
[string[]]$Sources,
[string]$Desination,
[int]$AgeInDays
)
foreach –parallel ($Source in $Sources){
$FixedDesination = "$($Desination)$($Source -replace '.*\\')"
if(!(Test-Path -Path $FixedDesination)){
md $FixedDesination
}
Get-ChildItem $Source -Recurse | ?{(($_.CreationTime).Day -gt $AgeInDays)} | Copy-Item -Destination $FixedDesination -Recurse -Container
}
}
Copy-ItemBasedOnCreation -Sources #("C:\Users\Default\Desktop\Source\TEST1","C:\Users\Default\Desktop\Source\TEST2") -Desination "C:\Users\Default\Desktop\Destination\" -AgeInDays 90
Copy-ItemBasedOnCreation -Sources #("C:\Users\Default\Desktop\Source\TEST4","C:\Users\Default\Desktop\Source\TEST5") -Desination "C:\Users\Default\Desktop\Destination\" -AgeInDays 180

Move Files to another folder based on part of file name

Hello Power Shell Champs,
I have a situation.
I have around 100 files with country name examples in C:\reports as:
Report File-USA.ppt
Report File-Canada.ppt
Report File-Brazil.ppt
Report File-Chile.ppt
I have folders with country names also in the folder C:\Countries
What I want to do is move files based on Country name to respective folders based on the name of country.
I'm uable to create a loop that works.
Note: Destination folders are already created, just files need to be moved
As Maigi mentioned, here is working code and it actually uses Move-Item as you requested in your original post rather than Copy-Item.
This code has been tested and works.
$list = (Get-ChildItem -Path C:\reports\ -Name -File).Replace('Report File-','').Replace('.ppt','')
ForEach-Object ($item in $list)
{
Move-Item -Path "C:\reports\Report File-$($item).ppt" -Destination "C:\Countries\$($item)\"
}
There is always more than one method to accomplish a task in PowerShell:
This script
splits the BaseName at the hyphen, and takes the second part(zero based)
if the destination path doesn't exist it is created.
Get-ChildItem 'C:\reports\Report File-*.ppt' -File | ForEach-Object{
$Country = Join-Path "C:\Country" $($_.BaseName.split('-')[1])
If (!(Test-path $Country)) {mkdir $Country|Out-Null}
$_|Move-Item -Destination $Country -whatif
}
If the output looks OK, remove the -whatif
Although some code from your side to see how far you've come would have been helpful, I imagine something like this should do the trick:
(edited)
$list = (Get-ChildItem -Path C:\reports\ -Name -File).Replace('Report File-','').Replace('.ppt','')
foreach ($item in $list) {
Move-Item -Source ".\Report File-$($item).ppt" -Destination "C:\Countries\$($item)\"
}

Script help rename - copy - move

I am trying to write a PowerShell script to do the following.
Rename files in source (FTP folders) directories with it's "current_name_datetime.csv" as per a source file "Source_list.csv" this file has the directories "source,destination" I want this script to look into.
Copy newly renamed files to backup directories as per destination in Source_list.csv this file has the directories "source,destination" I want this script to look into.
Move newly renamed files to final destination directory which is not in my current script.
Source_list.csv contents
cscenter,Costume_Supercenter
fkimports,FKImports
My Script:
$sdfiles = Get-Content c:\!tony\Source_list.csv
$sourceDir = "c:\test\"
$destinationDir = "c:\testing\"
Get-ChildItem $sourceDir -Recurse -Include $sdfiles "*.csv"|
ForEach-Object{
$newname= "{0}{1}_{2}.csv" -f $destinationDir, $_.BaseName, [datetime]::Now.ToString('MM-dd-yyyy-hh-mm-ss')
$_|Copy-Item -Include ,$sdfiles -Destination $newname -whatif }
Error:
What if: Performing operation "Copy Directory" on Target "Item: C:\test\cscenter Destination: C:\testing\cscenter_10-01-2015-12-22-24.csv".
I see in the error that it is trying to copy the directory not the single file in each directory and creating a new folder using the original folder name and renaming the folder and appending the date/time stamp.
Confused. The -Include parameter should only be accepting a single array of strings, throwing "*.csv" on to the end of it won't work AFAIK. Additionally It will be interpreting the whole line of the CSV, ie searching for the file "cscenter,Costume_Supercenter" so shouldn't be returning anything. At least that's what I see when I replicate this on my computer.
Lastly you've tried to filter the files, piped that to Copy-Item and tried to filter it again?
I'd take a more straightforward approach:
$sdfiles = Import-CSV c:\!tony\Source_list.csv -Header #("File", "Folder")
$sourcedir = "c:\test\"
$destinationdir = "c:\testing\"
$sdfiles | ForEach-Object {
$path = $sourcedir + $_.File + ".csv"
$folder = $destinationdir + $_.Folder + '\'
if (!(Test-Path $folder)) { New-Item -Type Directory -Path $folder }
if (Test-Path ($path))
{
$newname = "{0}{1}_{2}.csv" -f $folder, $_.File, (Get-Date).ToString('MM-dd-yyyy-hh-mm-ss')
Copy-Item -Path $path -Destination $newname -whatif
}
else { Write-Error "File $($_.File) not found" }
}
It's a bit chunkier but much easier to read and tweak to your liking. Note that Import-CSV does require PowerShell v3. Let me know if you've got v2 and need help tweaking it for a two-dimensional array.
I also recommend looking into Microsoft's MVA courses on PowerShell, they are excellent resources for starting out.