Get creation date with format - powershell

I want to loop over images and move each into a folder of the creation date, but I seem to fail to see the point about how to format the resulting datetime string and maybe also how ChildItem works...
I intend to create a variable containing the correct formatted string of the creation date "2017-03-06", so that I can create a directory with that name and move the file there. This shall happen within a loop (for, foreach, ...).
$files = Get-ChildItem "P:\photos\"
for ($i=0; $i -lt $files.Count; $i++) {
$outfile = $files[$i].FullName
Write-Host "file: " $outfile
$CreationDateStr = Get-ChildItem $files[$i].CreationTime |
Get-Date -f "yyyy-MM-dd"
Write-Host "file creation time: " $CreationDateStr
}
Read-Host -Prompt "Press Enter to exit"
This does not work, and the code is not correct:
Get-ChildItem : The disc was not found. Not disc with name "03/06/2017 07"
This works, but it needs to be formatted:
$files[$i].CreationTime
file creation time: 06.03.2017 07:53:21

We don't recommend Write-Host because you can't redirect it.
Here's what I think you are looking for:
Get-ChildItem "P:\Photos" | ForEach-Object {
$dirName = "{0:yyyy-MM-dd}" -f $_.CreationTime
if ( -not (Test-Path $dirName -PathType Container) ) {
[Void] (New-Item $dirName -ItemType Directory)
}
Move-Item $_ $dirName -WhatIf
}
So in the loop, we check if the specified directory doesn't exist (create it if it doesn't), then move the file to the new directory. Remove -WhatIf if the code does what you want.

Related

PowerShell: "Move-Item : Cannot create a file when that file already exists."

The code below has been wonderful so far for organising my hard-drives.
I do face this error when I transfer large amounts of data:
Move-Item : Cannot create a file when that file already exists.
This happens when I move a file that is duplicate, is there a way to rename the duplicate file in some sort of sequence?
That would be much appreciated :))
# Get all files
Get-ChildItem "C:\zAa" -File -Recurse | ForEach-Object {
# Get the modified date
$dt = Get-Date $_.LastWriteTime
$year = $dt.Year
$month = $dt.Month
# This adds "0" in front of the 1-9 months
if($dt.Month -lt 10) {
$month = "0" + $dt.Month.ToString()
} else {
$month = $dt.Month
}
# Remove leading '.' from the extension
$extension = $_.Extension.Replace(".", "")
# Where we want to move the file
$destinationFolder = "C:\zBb\$extension\$year\$month\"
# Ensure full folder path exists
if(!(Test-Path $destinationFolder)) {
New-Item -ItemType Directory -Force -Path $destinationFolder
}
# Copy/Move the item to it's new home
Move-Item $_.FullName $destinationFolder
}
I haven't been able to do much, I normally go find the duplicates and rename them manually.
Probably the easiest way to move a file with a unique name is to use a Hashtable that stores the filenames already present.
Then a simple loop can add a sequence number to its file name until it is no longer found in the Hashtable.
Next simply move the file under that new name.
Your code modified:
# Where we want to move the file
$destinationFolder = 'C:\zBb\{0}\{1:yyyy}\{1:MM}' -f $_.Extension.TrimStart("."), $_.LastWriteTime
# Ensure full folder path exists
$null = New-Item -Path $destinationFolder -ItemType Directory -Force
# create a Hashtable and store the filenames already present in the destination folder
$existing = #{}
Get-ChildItem -Path $destinationFolder -File | ForEach-Object { $existing[$_.Name] = $true }
# Get all source files
Get-ChildItem "C:\zAa" -File -Recurse | ForEach-Object {
# Copy/Move the item to it's new home
# construct the new filename by appending an index number in between brackets
$newName = $_.Name
$count = 1
while ($existing.ContainsKey($newName)) {
$newName = "{0}({1}){2}" -f $_.BaseName, $count++, $_.Extension
}
# add this new name to the Hashtable so it exists in the next run
$existing[$newName] = $true
# use Join-Path to create a FullName for the file
$newFile = Join-Path -Path $destinationFolder -ChildPath $newName
Write-Verbose "Moving '$($_.FullName)' as '$newFile'"
$_ | Move-Item -Destination $newFile -Force
}

Get missing file name in a sequence of files

In a folder i have many files, they are sequential, type ABC001.csv,ABC002.csv,ABC003.csv and so on. Sometimes this sequence breaks, then there are missing files and I need to identify which of the sequence are missing in the folder manually, we have more than 700files.
Does anyone here know a power shell script to help me with this task?
If all files to be counted always have a naming format ABC<3-digit number>.csv, then you could do this:
# get an array of integer sequence numbers from the files
$sequence = (Get-ChildItem -Path 'D:\Test' -Filter 'ABC*.csv' -File).BaseName |
Where-Object { $_ -match '(\d{3})$' } | ForEach-Object { [int]$matches[1] } |
Sort-Object -Unique
# get the missing numbers (if any) and output filenames to be collected in $missingFiles
$missingFiles = Compare-Object $sequence (1..($sequence[-1])) -PassThru | ForEach-Object {
'ABC{0:D3}.csv' -f $_ # reconstruct the filename with the missing number
}
# output on screen
if (#($missingFiles).Count) {
Write-Host "Files missing:" -ForegroundColor Yellow
$missingFiles
}
else {
Write-Host "All files are in sequence" -ForegroundColor Green
}
Of course, change the rootpath of the files (here 'D:\Test') to your own
In this example,
The script is located in the same location as a folder named "Temp".
The "Temp" folder had files ABC001.csv through ABC717.csv.
Files ABC123.csv and ABC555.csv were deleted from "Temp" folder.
for ($i = 1; $i -lt 718; $i++) {
$FileName = $PSScriptRoot + '\Temp\ABC{0:d3}.csv' -f $i
if(-not (Test-Path -Path $FileName -PathType Leaf)) {
Write-Host "Missing $FileName"
}
}
Output when ran:
Missing 123
Missing 555

How to backup these files into specific folders using powershell

I've finally have given up googling and come here out of desperation. Go easy on me I'm fairly new to Powershell.
So, the objective of the code below was to first look through the source folder, then read through each .zip file and move to the directory specified by the value in the hashtable. Unfortunately, this is not how they want it to work anymore.
Now I need to retain the parent folder from source: for example "DAL" and then create the proceeding folders based on the file names and finally move each .zip to its file specified folder. Also, it needs to go through each folder under source which will be at least 20 other folders with a unique 3 character names.
$srcRoot = "C:\Cloud\source\dal"
$dstRoot = "C:\Cloud\Destination"
##$map = #{}; dir -recurse | ? { !$_.psiscontainer} | % { ##$map.add($_.name,$_.PSChildName) }
# DAT and DEV will have to be excluded from folder creation
$map = {
#AEODDAT_201901 = "AEOD\2019\01"
#AEOMDEV_201902 = "AEOM\2019\01"
#AEOYDAT_201902 = "AEOY\2019\01"
}
$fileList = Get-ChildItem -Path $srcRoot -Filter "*.zip*" -File -Force -Recurse
foreach ($file in $fileList)
{
#Go through each file up to mapped string
$key = $file.BaseName.Substring(0,14)
if ($key -in $map.Keys)
{
$fileName = $file.Name
$dstDir = Join-Path -Path $dstRoot -ChildPath $map[$key]
#create direcotory if not in path
if (-not (Test-Path -Path $dstDir))
{
mkdir -Path $dstDir
}
Write-Verbose "Moving $($file.FullName)"
if (Test-Path -Path (Join-Path -Path $dstDir -ChildPath $fileName))
{
#Write error if name exists
Write-Error -Message "File $fileName already exists at $dstDir"
#move path
} else {
Move-Item -Path $($file.FullName) -Destination $dstDir
}
}
}
So C:\Cloud\source\DAL\AEODDAT20190101.zip should create folders in C:\Cloud\Destination\DAL\AEOD\2019\01\AEODDAT20190101.zip would be my desired output.
Welcome, Matt! (no pun intended) One of the habits I have in similar situations with destination folders is to Set-Location $dstRoot and create folders from the relative path. You can execute New-Item with the relative path and the syntax is simpler. For example, your If statement could look like this and it would work the same way (with a slightly different error message):
if ($key -in $map.Keys){
Set-Location $dstRoot
New-Item -ItemType Directory $map[$key] -ErrorAction Ignore #won't raise an error if it exists
Write-Verbose "Moving $($file.FullName)"
#this will raise an error if the file already exists, unless you specify -Force
Move-Item "$($file.FullName)" $map[$key]
}
EDIT: Found 2 issues.
$map is a Hashtable literal that should be preceded with #:
$map = #{
AEODDAT20190101 = "AEOD\2019\01"
You were missing the last character of the base file name by taking only the first 14 characters. AEODDAT2019010 didn't match AEODDAT20190101. This should fix it:
$key = $file.BaseName.Substring(0,15)

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.

Powershell script to deploy files with necessary backup

Team,
I'm writing a powershell script to automate one of the manual task we are doing daily. I need expert suggestion and help here as I'm new to powershell scripting.
Requirement:
There is a source, destination and a backup folder.
Source may have diff files and files within multiple folders of source.
eg: source\Login.aspx or source\App_Code\BLogic.vb or source\bin\servr.dll etc.
While copying to destination, my source file has to be checked for existence at destination, if exists then we need to copy the current existing file in destination to backup folder, then copy source to destination.
Below are the scripts that i have tried till now.
Script1:
I'm able to list files which are same but not able to copy those array elements to backup location:
#Declare Source and Destination
$source = Get-ChildItem -Recurse -path \\server1\\e$\ps\src\
$dest = Get-ChildItem -Recurse -path \\server2\\e$\ps\dest\
#lists only objects which are equal and assign to variable
$files=compare-Object -DifferenceObject $source -ReferenceObject $dest -IncludeEqual -ExcludeDifferent
$array = #($files)
$len=$array.length
for ($i=0; $i -lt $array.length; $i++)
{
$array[$i]
}
Script2:
As script1 i was facing problem i tried a silly logic with this script, but i feel this is also having too much manual work :( please help me.
Function cpytest ($s, $d)
{
Copy-Item -Path $s -Destination $d;
}
$n = Read-Host "Enter no of files to be uploaded"
$b = Read-Host "Enter Backup Location for file backups"
for ($i=0;$i -lt $n;$i++)
{
$s = Read-Host "Enter Source with complete file name"
$d = Read-Host "Enter Destination with file name too"
$r = Test-Path $d
If ($r -eq "True")
{
cpytest $d $b
cpytest $s $d
}
Else
{
cpytest $s $d
}
}
Try something like this:
Function BackupAndMoveFile($filePath, $backupPath, $deployPath) {
$fileName = Split-Path $filePath -Leaf
$deployFile = Join-Path $deployPath $fileName
if ((Test-Path $deployFile)) {
$backupFile = Join-Path $backupPath $fileName
Move-Item $deployFile $backupFile -Force
if (!(Test-Path $backupFile)) {
Write-Warning "Can't backup $fileName to $backupFile"
return $false
}
}
Copy-Item $filePath $deployPath -Force
if (!(Test-Path $deployPath)) {
Write-Warning "Can't deploy $fileName to $deployPath"
return $false
}
return $true
}
BackupAndMoveFile 'C:\temp\backup-test.txt' `
'C:\temp\backup' `
'C:\temp\deploy'
It will overwrite anything in the backup directory so you might want to modify to add a timestamp.