Samantha J T Star
Samantha J T Star

Reputation: 32828

How can I use Powershell to keep two directories updated with the latest files

I have two directories:

C:\G\admin\less
C:\G\user\less

Inside of those directives I have multiple less and css files. I know all the names of the files so I would like to hardcode a list of these into the script. Perhaps this could be in an array or something but my knowledge of PowerShell is not even enough to know if there are arrays in the scripting language.

C:\G\admin\less

html-light.less
html-light.css
html-dark.less
html-dark.css
do-not-track-me.less

C:\G\user\less

html-light.less
html-light.css
html-dark.less
html-dairk.css
do-not-track-me.less

Is there a way I can use PowerShell to check each of these files (that I want to hardcode in my program) one by one and copy the last modified file from its directory to the other directory so that both directories will contain the same latest versions of these files?

Note that I would need to evaluate the predefined list of files one by one. Comparing modified date in one directory with the other and copying over as needed.

Upvotes: 1

Views: 677

Answers (2)

Felicio Balane
Felicio Balane

Reputation: 301

again assume that this isn't the best solution or approach
This solution assumes following
- when the LastWriteTime on one folder is bigger than the other it copy it to another folder.
- I'm not doing the path validation because of laziness but if you want with path validation just ask.
- I'm assuming that all the files on those folder must be tracked otherwise read the comment on code. - i suggest you backup your folder before you run the script.

#if there is a file you don't want to track on those folder (for example you don't want to track txt files) 
#just  write $userFiles=dir C:\G\user\less\ -Exclude "*.txt"
#if you don't want track txt but only one of them should be track among with other file format
#$userFiles=dir C:\G\user\less\ -Exclude "*.txt" -Include "C:\G\user\less\Txtadditionaltotrack.txt"
$userFiles=dir C:\G\user\less\
$adminfiles=dir C:\G\admin\less\
foreach($userfile in $userFiles)
{
   $exactadminfile= $adminfiles | ? {$_.Name -eq $userfile.Name} |Select -First 1
   #my suggestion is to validate if it got the file.
   #By now because of my lazy i will not call the test-path to validate if it got the file
   #I'm assuming all directory are exact copy of each other so it will find the file.

  if($exactadminfile.LastWriteTime -gt $userfile.LastWriteTime)
  {
    Write-Verbose "Copying  $exactadminfile.FullName to $userfile.FullName "
    Copy-Item -Path $exactadminfile.FullName -Destination $userfile.FullName -Force
  }
  else
  {
    Write-Verbose "Copying  $userfile.FullName to $exactadminfile.FullName "
    Copy-Item -Path $userfile.FullName -Destination $exactadminfile.FullName -Force
  }
}

you can improve it because the way this code is it always copy file from one directory to another inside the else you can validate so that when the lastwriteTime is equal on both it doesn't copy. You can improve it in many ways. i hope you got the ideia

Find the modification made to code so that it can archieve this requirement.
PLEASE READ THE COMMENT IN CODE.
NOTE THAT I'M NOT FOLLOWING THE BEST PRATICE (avoid unexpected error, name correctly all variable, ...)

#to make it more dynamical you can save on one file
#all the file names including extension in different lines.
#For example on path C:\FilesToWatch\watcher.txt
#$filestowatch=get-content C:\FilesToWatch\watcher.txt

$filestowatch="felicio.txt","marcos.txt"
$userFiles=dir C:\G\user\less\
$adminfiles=dir C:\G\admin\less\

#Optionally instead of use this if approach you can 

#$userFiles=dir C:\G\user\less\ |? {$filestowatch -contains $_.Name}
#$adminfiles=dir C:\G\admin\less\|? {$filestowatch -contains $_.Name}

#loading in the above manner the first if statement on code bellow can be removed because 
#We make sure that $userFiles and $adminfiles only have correct file to monitor

foreach($userfile in $userFiles)
{
   if($filestowatch -contains $userfile.Name)
   {
      $exactadminfile= $adminfiles | ? {$_.Name -eq $userfile.Name} |Select -First 1
       #my suggestion is to validate if it got the file.
       #By now because of my lazy i will not call the test-path to validate if it got the file
       #I'm assuming all directory are exact copy of each other so it will find the file.

      if($exactadminfile.LastWriteTime -gt $userfile.LastWriteTime)
      {
         Write-Verbose "Copying  $exactadminfile.FullName to $userfile.FullName "
         Copy-Item -Path $exactadminfile.FullName -Destination $userfile.FullName -Force
       }
       else
       {
          Write-Verbose "Copying  $userfile.FullName to $exactadminfile.FullName "
          Copy-Item -Path $userfile.FullName -Destination $exactadminfile.FullName -Force
       }
    }
}

Upvotes: 1

bmateus
bmateus

Reputation: 47

I think what you need is symbolic links, aka symlinks.

With symlinks, you can define files and folders that will be always in-sync, where the target file is updated automatically when the original is modified.

To create a symbolic link, enter the following in the console/command prompt:

mklink /[command] [link path] [file or folder path]

Mklink can create several types of links, according to these commands:

  • /D – creates a soft symbolic link, which is similar to a standard folder or file shortcut in Windows. This is the default option, and mklink will use it if you do not enter a command.
  • /H – creates a hard link to a file.
  • /J – creates a hard link to a folder.

The syntax is simple. Choose your option, define the path you want for the symlink, and finally the path of the original file/folder.

For example, imagine I'm developing a new project, and I want to share it to my client via Dropbox shared folder. I don't want to move all my workspace to dropbox, I just want to share that specific folder to them:

mklink /J C:\Dropbox\clients_shared_folders\project_x C:\my_dev_rootfolder\project_x

Note that the first path is the symbolic folder I want to create, while the second path is the existing directory.

In you case, I'll be assuming your working on the admin folder, and want to generate a syncd copy on the user folder:

mklink /J C:\G\user\less C:\G\admin\less

Here's a nice article for more info: http://www.howtogeek.com/howto/16226/complete-guide-to-symbolic-links-symlinks-on-windows-or-linux/

Upvotes: 0

Related Questions