1

I have a PowerShell script that moves all files from one location to another that have a date modified older than 3 years. I have it so the file when moved to the new location also keeps the file structure of the original.

I am trying to make it so once the file has been moved to the new location it creates a shortcut in the original directory which points to the new location of the file.

Below is my script so far which does all the above minus the shortcut.

$sourceDir = "C:\Users\bgough\Documents\powershell\docs"
$archiveTarget = "C:\Users\bgough\Documents\archive"
$dateToday = Get-Date
$date = $dateToday.AddYears(-3)

$items = Get-ChildItem $sourceDir -Recurse |
         Where-Object {!$_.PSIsContainer -and $_.LastWriteTime -le $date}

foreach ($item in $items)
{
  $withoutRoot = $item.FullName.Substring([System.IO.Path]::GetPathRoot($item.FullName).Length);
  $destination = Join-Path -Path $archiveTarget -ChildPath $withoutRoot

  $dir = Split-Path $destination
  if (!(Test-Path $dir))
  {
    mkdir $dir
  }

  Move-Item -Path $item.FullName -Destination $destination

  $WshShell = New-Object -ComObject WScript.Shell
  $Shortcut = $WshShell.CreateShortcut("$sourceDir")
  $Shortcut.TargetPath = $destination
  $Shortcut.Save()
}

In my script I have included my attempt at creating this shortcut but it hasn't helped. I have also read through the following but don't understand it too well..

How to create a shortcut using Powershell

Powershell Hard and Soft Links

Edit:

I have successfully got the shortcut to create and in the original folder. However, I can't seem to figure out how to pass a variable to use as the shortcut name. At the moment a string is hard coded, which is what the shortcut gets named. Please see code below: I would like to set the name as the item full name (Same name as document that was moved).

$sourceDir = "C:\Users\bgough\Documents\powershell\docs"
$archiveTarget = "C:\Users\bgough\Documents\archive"
$dateToday = Get-Date
$date = $dateToday.AddYears(-3)

$items = Get-ChildItem $sourceDir -recurse | Where-Object {!$_.PsIsContainer -and $_.LastWriteTime -le $date}

foreach ($item in $items)
{
  $withoutRoot = $item.FullName.Substring([System.IO.Path]::GetPathRoot($item.FullName).Length);
  $destination = Join-Path -Path $archiveTarget -ChildPath $withoutRoot

  $dir = Split-Path $destination
  if (!(Test-Path $dir))
  {
    mkdir $dir
  }

  Move-Item -Path $item.FullName -Destination $destination

  $wshshell = New-Object -ComObject WScript.Shell
  $desktop = [System.Environment]::GetFolderPath('Desktop')
  $lnk = $wshshell.CreateShortcut($sourceDir + "\ShortcutName.lnk")
  $lnk.TargetPath = "$destination"
  $lnk.Save()
}
Community
  • 1
  • 1

2 Answers2

0

.lnk files are fine when you're using Explorer but they don't play well in Powershell or a command prompt.

What you need to do is create a symbolic link for the file. You can't do this in Powershell, but there is a command line utility called mklink that does it. I've wrapped it in a function so that you can call it:

function CreateLink
{
    param
    (
        [string] $LinkName,
        [string] $TargetFile
    )

    &"cmd.exe" /c mklink "$LinkName" "$TargetFile" | Out-Null
}

In your example you would call it like this:

CreateLink -LinkName $item.FullName -TargetFile $destination

When you look at the directory in Powershell the file will show up as being 0 bytes in size. Don't worry about that.

Sean
  • 60,939
  • 11
  • 97
  • 136
0

Thanks for your script Android Magic.

I have modified it to:

  1. Copy a set of files from source to destination
  2. It creates the identical folder structure on the destination, even if the folders are empty
  3. It then creates a symbolic link to the archived file. SymbolicLink support was added in Powershell v5.1. You have to run the script as Admin in order for the Symbolic Link creation to work.

I'd like to add a function to email if anything goes wrong and a summary of status, but that's for another day.

$sourceDir = "\\Fileserver1\IT\Vendor"
$archiveTarget = "\\FS-ARCHIVE\Archive\Fileserver1\IT\Vendor"
$rootArchivePath = "\\FS-ARCHIVE\Archive"

$dateToday = Get-Date
$date = $dateToday.AddYears(-3)

# Copy folder structure to Archive
Get-ChildItem -Path $sourceDir -Recurse | 
?{ $_.PSIsContainer } | 
Copy-Item -Destination {Join-Path $archiveTarget $_.Parent.FullName.Substring($sourceDir.length)} -Force

$items = Get-ChildItem $sourceDir -Recurse -Attributes !Directory |
         Where-Object {$_.LastAccessTime -le $date}
foreach ($item in $items)
{
  $withoutRoot = Split-Path -Path $item.FullName
  $destination = $rootArchivePath + $withoutRoot.Remove(0,1)
  $destFile = $destination + "\" + $item

  Move-Item -Force -Path $item.FullName -Destination $destination -Verbose

  New-Item -ItemType SymbolicLink -Path $withoutRoot -Name $item -Value $destFile -Force -Verbose

}
Adrian W
  • 4,563
  • 11
  • 38
  • 52