How to run powershell cmdlets one after the other - powershell

I have a sharepoint 2010 list designed with custom solution. It has 3 level folder hierarchy. In the last folder level multiple documents are present as attachments. I want to get all the document attachments from that folder and store it in my local drive, so that it can be migrated to a different platform.
Number of Attachments are around 350000.
My Tasks are:
Creating Folder in my drive.
Getting Attachment ids and create folder with id name, as inputs from a txt file.
Map network drive
Copy attachment from network drive to local folder.
Delete network drive.
These 5 steps are to be repeated for around 350000 attachments.
Kindly let me know if cmdlets can be executed properly one after the other.
$idsFile = "H:\D\Temp\testingid.txt"
$FileStore = "H:\D\Temp\Attachments"
foreach ($line in Get-Content $idsFile) {
$FileCount = 1
$thisappid = $line.Split("`t")
Write-Host $thisappid.GetValue(0)
$FPath = $FileStore + '/' + $thisappid.GetValue(1)
Write-Host $FPath
if (!(Test-Path $FPath)) {
Write-Host "Creating folder.."
$F1 = New-Item -Path $FileStore -Name $thisappid.GetValue(1) -ItemType "directory"
Write-Host $F1
$F2 = New-Item -Path $F1 -Name $thisappid.GetValue(0) -ItemType "directory"
} else {
Write-Host "Folder" $thisappid.GetValue(1) "Already exists"
$SPath = $FileStore + '/' + $thisappid.GetValue(1) + '/' + $thisappid.GetValue(0)
Write-Host $SPath
if (!(Test-Path $SPath)) {
$F2 = New-Item -Path $SPath -Name $thisappid.GetValue(0) -ItemType "directory"
Write-Host $F2
} else {
Write-Host "Folder" $thisappid.GetValue(0) "already exists"
Write-Host "Move to Next.."
}
}
Write-Host $thisappid.GetValue(0)
$id = $thisappid.GetValue(0) -as [int]
Write-Host $id
Write-Host $id.GetType()
net use Y: \\domainName/sites/SiteName/Lists/MyList/Attachments/$id
/Persistent:Yes
Start-Sleep -s 10
$name = Get-ChildItem -Path Y:\ -Name
Start-Sleep -s 10
Copy-Item -Path Y:\$name -Destination $dest
Start-Sleep -s 10
net use Y: /delete /y
Start-Sleep -s 10
$FileCount = $FileCount+1
Write-Host $FileCount
}

Related

backup www directory from local to network drive powershell

I built a script that copies files from the local C drive to a Network Drive.
I have a folder in C:\www\root called "images" or "C:\www\root\images"
The script creates a folder called "images" in the "F:\powershell_wwwroot\root_" + $TimeStamp" however the "images" directory is empty in the destination folder. The script copies everything from the C:\www\root\images\ folder to base destination folder "F:\powershell_wwwroot\root_" + $TimeStamp".
So I see everything from C:\www\root\images\ in F:\powershell_wwwroot\root_02_12_2021
however the F:\powershell_wwwroot\root_02_12_2021\images is empty. I would like to see everytying from "C:\www\root\images" in "F:\powershell_wwwroot \root_02_12_2021\images"
$TimeStamp = get-date -f dd_MM_yyyy
$Destination = "F:\powershell_wwwroot\root_" + $TimeStamp
New-Item -ItemType directory -Path $Destination -Force
gci "C:\www\root\" -recurse | %{
$file = $_.Fullname
Write-Host $file
Copy-Item -Path $file -Destination $Destination -Force
}
A ForEach-Loop for this shouldn't be needed, let Copy-Item handle it. The following should leave the Folder / File hierarchy intact.
$TimeStamp = Get-Date -Format dd_MM_yyyy
$Destination = "F:\powershell_wwwroot\root_" + $TimeStamp
New-Item -ItemType directory -Path $Destination -Force
$Source = "C:\www\root\"
Copy-Item -LiteralPath $source -Destination $destination -Recurse -Force
you can use either copy-item or bit-transfer. I wrote a script that uses the bits transfer cmdlet. If you update my script, to create the destination folder your home dry. If you have any issues regarding the script holler at me :o)
https://superuser.com/questions/1689980/start-bitstransfer-failing-to-send-files-to-remote-destination/1690801#1690801
Import-Module BitsTransfer
#Get Script Location Path
$ScriptPath = Get-Location
$ScriptPath = $ScriptPath.ToString()
$dirName=[System.IO.Path]::GetDirectoryName($ScriptPath)
#Build Source Server Location Path
#Source Server
$Sourceserver = $env:COMPUTERNAME
#Source Server Folder Path
$Sourcefolderpath = "C:\Temp"
#Switch Colon for Dollar Sign
$Sourcepath = $Sourcefolderpath.Replace(':','$')
#Build Target Folder Path
$ServerSourceFolderpathTest = "\\" + $SourceServer + "\" + $Sourcepath
#Print to screen to view path
#Write-Host $ServerSourceFolderpathTest
#Test Path
$testsourcefolderpath = Test-Path -LiteralPath $ServerSourceFolderpathTest
IF ($testsourcefolderpath -eq $False) {
Write-Host -Fore Red "Source Folder Path Cannot Be Established.
Path is - $testsourcefolderpath"
Write-Host "Script Will Exit"
Exit
} ELSE {
Write-Host -Fore Green "Source Folder Path Established.
Path Is - $testsourcefolderpath"
}
#Build Target Server Location Path
#Target Server
$Targetserver = $env:COMPUTERNAME
#Target Server Folder Path
$Targetfolderpath = "C:\Test"
#Switch Colon for Dollar Sign
$Targetpath = $Targetfolderpath.Replace(':','$')
#Build Target Folder Path
$ServerTargetFolderpathTest = "\\" + $TargetServer + "\" + $Targetpath
#Print to screen to view path
#Write-Host $ServerTargetFolderpathTest
#Test Path
$testTargetfolderpath = Test-Path -LiteralPath $ServerTargetFolderpathTest
IF ($testTargetfolderpath -eq $False) {
Write-Host -Fore Red "Target Folder Path Cannot Be Established.
Path is - $testTargetfolderpath"
Write-Host "Script Will Exit"
Exit
} ELSE {
Write-Host -Fore Green "Target Folder Path Established.
Path Is - $testTargetfolderpath"
}
#Build Source Target Paths for Bit Transfer
$SourceFolder = $ServerSourceFolderpathTest
$PreTargetFolder = $ServerTargetFolderpathTest
$Slash = "\"
$TargetFolder = $PreTargetFolder + $Slash
#Test Target Folder Path
#$TargetFolder
#Get All Text Files From Source Folder
$GetFiles = (gci $SourceFolder -Filter *.txt)
$GetFilesFileFullName = $GetFiles.FullName
#Test View All Full File Names
#$GetFilesFileFullName
ForEach($File in $GetFilesFileFullName) {
$Discript = "Backing Up $File from $Sourceserver to $Targetserver -- " + (Get-Date)
$Discript
Start-BitsTransfer -Source $File -Destination $TargetFolder -Display $Discript -Priority 'Low' -Asynchronous -WhatIf
}

Extract file from zips in sub folders

I'm relatively new to PowerShell and have only been doing "light" scripting to automate a few tasks at work.
Most of the time, I can Google and get the answer(s) I need, with maybe some minor tweaking/experimenting.
But I need some help with this one as I can't find the answer I'm looking so hoping someone here might be able to help me.
DETAILS:
I am provided a directory link on the network drive to either sub-folders containing ".zips" or a folder with ".zips" only.
The latter case works for my current script (will be provided further down) to do it's job but the former is where I'm struggling.
TL;DR - I need the script to go into each folder, extract each ".zip" into a "Temp" folder and then look for a "backup" image file (file type may vary) and then copy it out to the sub-folder and rename to the same as the ".zip" it was extracted from.
Again, my script works if I'm physically in the folder with the ".zip" files but not if the ".zip" files are in sub-folders as I can't get it recursively go into each folder and run the script.
EXAMPLE SETUP:
FolderA\FolderB\1.zip
FolderA\FolderB\2.zip
FolderA\FolderB\3.zip
FolderA\FolderC\1.zip
FolderA\FolderC\1.zip
FolderA\FolderC\1.zip
Script below:
#Current Directory of ".zip" files
$fileLocation = read-host "Type/Paste location of creatives"
#replace server path with drive letter
if (Test-Path \\server\path\* -PathType Leaf) {
$serverPathName = "\\server\path\"
$driveLetter = "D:\"
$fileLocation = ($fileLocation -replace [regex]::Escape($serverPathName),$driveLetter)
}
$fileLocation = Resolve-Path $fileLocation
Write-Output $fileLocation
#change directory to the one provided
$zipFilesPath = cd "$fileLocation"
$currentDirectory = pwd
#File type of backup
#Note: `n = new line
write-host "`nChoose Creative Backup File Type"
Write-Host "1. JPG"
Write-host "2. JPEG"
Write-Host "3. PNG"
Write-Host "4. GIF"
$typeFilter = Read-Host "`nType? 1/2/3/4"
if($typeFilter -eq '1'){
$typeFilter = 'jpg'
}
elseif($typeFilter -eq '2'){
$typeFilter = 'jpeg'
}
elseif($typeFilter -eq '3'){
$typeFilter = 'png'
}
elseif($typeFilter -eq '4'){
$typeFilter = 'gif'
}
else {
write-host "ERROR! Incorrect Input!"
Write-Host "Exiting Script..."
start-sleep -seconds 1.5
Exit
}
#Files Location
$ZipFilesPath = "$currentDirectory\*.zip"
#Unzip To Same Location
$UnzipPath = "$currentDirectory"
#Check if Temp Folder exists
$TempCheck = Test-Path "$currentDirectory\Temp"
If ($TempCheck -eq $false) {
#Create Temp Folder
New-Item -ItemType directory -Path "$currentDirectory\Temp" -Force
}
$TempPath = "$currentDirectory\Temp"
$Shell = New-Object -com Shell.Application
$Location = $Shell.NameSpace($TempPath)
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
$FileCounter = 1
#Clear Initilisation Vars from Console
clear
foreach ($ZipFile in $ZipFiles) {
#Get The Base Filename without the extension
$ZipFileActualName = [io.path]::GetFileNameWithoutExtension($ZipFile.FullName)
write-host File: $ZipFileActualName
$ZipFolder = $Shell.NameSpace($ZipFile.fullname)
$Location.Copyhere($ZipFolder.items(), 1040)
#Find and rename backups
$BackupFiles = Get-ChildItem $TempPath -Filter *backup*.$typeFilter -Recurse
$BackupFiles |% {Move-Item $_.Fullname $UnzipPath/$ZipFileActualName'_backup'.$typefilter}
#Clear Temp Folder
Get-ChildItem -Path "$currentDirectory\Temp" -Include *.* -File -Recurse | foreach { $_.Delete()}
#Move Along to Next File
$FileCounter++
}
#Delete Temp Folder
Remove-Item "$currentDirectory\Temp" -Force -Recurse
#Clear Console
clear
#Read-Host -Prompt “Press Enter to exit”
#start .\
I'm open to any suggestions provided or areas of improvement. If I need to completely change the code, I don't mind. Long as it works for both scenarios.
Thanks.
UPDATE
Modified script as per HAL9256's instruction:
#Current Directory of creatives
$fileLocation = read-host "Type/Paste location of creatives"
if (Test-Path \\server\path\* -PathType Leaf) {
$serverPathName = "\\server\path\"
$driveLetter = "D:\"
$fileLocation = ($fileLocation -replace [regex]::Escape($serverPathName),$driveLetter)
}
$fileLocation = Resolve-Path $fileLocation
Write-Output $fileLocation
$zipFilesPath = cd "$fileLocation"
$currentDirectory = pwd
#File type of backup
#Note: `n = new line
write-host "`nChoose Creative Backup File Type"
Write-Host "1. JPG"
Write-host "2. JPEG"
Write-Host "3. PNG"
Write-Host "4. GIF"
$typeFilter = Read-Host "`nType? 1/2/3/4"
if($typeFilter -eq '1'){
$typeFilter = 'jpg'
}
elseif($typeFilter -eq '2'){
$typeFilter = 'jpeg'
}
elseif($typeFilter -eq '3'){
$typeFilter = 'png'
}
elseif($typeFilter -eq '4'){
$typeFilter = 'gif'
}
else {
write-host "ERROR! Incorrect Input!"
Write-Host "Exiting Script..."
start-sleep -seconds 1.5
Exit
}
#Files Location
$ZipFilesPath = "$currentDirectory"
#Unzip To Same Location
$UnzipPath = "$currentDirectory"
#Check if Temp Folder exists
$TempCheck = Test-Path "$currentDirectory\Temp"
If ($TempCheck -eq $false) {
#Create Temp Folder
New-Item -ItemType directory -Path "$currentDirectory\Temp" -Force
}
$TempPath = "$currentDirectory\Temp"
$Shell = New-Object -com Shell.Application
$Location = $Shell.NameSpace($TempPath)
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
$FileCounter = 1
#Clear Initilisation Vars from Console
clear
foreach ($ZipFile in $ZipFiles) {
#Get The Base Filename without the extension
$ZipFileActualName = [io.path]::GetFileNameWithoutExtension($ZipFile.FullName)
write-host File: $ZipFileActualName
$ZipFolder = $Shell.NameSpace($ZipFile.fullname)
$Location.Copyhere($ZipFolder.items(), 1040)
#Find and rename backups
$BackupFiles = Get-ChildItem $TempPath -Filter *backup*.$typeFilter -Recurse
$BackupFiles |% {Move-Item $_.Fullname $upzipPath/$ZipFileActualName'_backup'.$typefilter}
#Clear Temp Folder
Get-ChildItem -Path "$currentDirectory\Temp" -Include *.* -File -Recurse | foreach { $_.Delete()}
#Move Along to Next File
$FileCounter++
}
#Delete Temp Folder
Remove-Item "$currentDirectory\Temp" -Force -Recurse
#Clear Console
clear
#Read-Host -Prompt “Press Enter to exit”
#start .\
That did what I need to do. But how can I modify my script so it stores the backups in their respective folder? So the backups extracted from "FolderB" stay in "FolderB", etc? Is there something I can do?
UPDATE 2
Final code - Thanks to help from HAL9256:
#Current Directory of creatives
$fileLocation = read-host "Type/Paste location of creatives"
if (Test-Path \\server\path\* -PathType Leaf) {
$serverPathName = "\\server\path\"
$driveLetter = "D:\"
$fileLocation = ($fileLocation -replace [regex]::Escape($serverPathName),$driveLetter)
}
$fileLocation = Resolve-Path $fileLocation
Write-Output $fileLocation
$zipFilesPath = cd "$fileLocation"
$currentDirectory = pwd
#File type of backup
#Note: `n = new line
write-host "`nChoose Creative Backup File Type"
Write-Host "1. JPG"
Write-host "2. JPEG"
Write-Host "3. PNG"
Write-Host "4. GIF"
$typeFilter = Read-Host "`nType? 1/2/3/4"
if($typeFilter -eq '1'){
$typeFilter = 'jpg'
}
elseif($typeFilter -eq '2'){
$typeFilter = 'jpeg'
}
elseif($typeFilter -eq '3'){
$typeFilter = 'png'
}
elseif($typeFilter -eq '4'){
$typeFilter = 'gif'
}
else {
write-host "ERROR! Incorrect Input!"
Write-Host "Exiting Script..."
start-sleep -seconds 1.5
Exit
}
#Files Location
$ZipFilesPath = "$currentDirectory"
#Unzip To Same Location
$UnzipPath = "$currentDirectory"
#Check if Temp Folder exists
$TempCheck = Test-Path "$currentDirectory\Temp"
If ($TempCheck -eq $false) {
#Create Temp Folder
New-Item -ItemType directory -Path "$currentDirectory\Temp" -Force
}
$TempPath = "$currentDirectory\Temp"
$Shell = New-Object -com Shell.Application
$Location = $Shell.NameSpace($TempPath)
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
$FileCounter = 1
#Clear Initilisation Vars from Console
clear
foreach ($ZipFile in $ZipFiles) {
#Get The Base Filename without the extension
$ZipFileActualName = [io.path]::GetFileNameWithoutExtension($ZipFile.FullName)
write-host File: $ZipFileActualName
$ZipFolder = $Shell.NameSpace($ZipFile.fullname)
$Location.Copyhere($ZipFolder.items(), 1040)
$DestinationDir = $ZipFile.DirectoryName.Replace($ZipFilesPath,$unzipPath)
#Find and rename backups
$BackupFiles = Get-ChildItem $TempPath -Filter *backup*.$typeFilter -Recurse
$BackupFiles |% {Move-Item $_.Fullname $DestinationDir/$ZipFileActualName'_backup'.$typefilter}
#Clear Temp Folder
Get-ChildItem -Path "$currentDirectory\Temp" -Include *.* -File -Recurse | foreach { $_.Delete()}
#Move Along to Next File
$FileCounter++
}
#Delete Temp Folder
Remove-Item "$currentDirectory\Temp" -Force -Recurse
#Clear Console
clear
#Read-Host -Prompt “Press Enter to exit”
#start .\
When you specify the path:
#Files Location
$ZipFilesPath = "$currentDirectory\*.zip"
Then trying to get the files:
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
What you essentially are saying is Get-Childitem and get only *.zip files. Because the path parameter has the wildcard filter, it will only get all the *.zip files in that directory and will not get any folders. Since you have no folders matching the *.zip wildcard, Get-Childitem won't have any folders to continue to recurse through.
The solution is to only give a base folder to the path parameter for the Get-Childitem to recurse through, and, correctly, use the -Include to apply the filter for the type. e.g.:
#Files Location
$ZipFilesPath = "$currentDirectory"
...
$ZipFiles = Get-Childitem $ZipFilesPath -Recurse -Include *.ZIP
EDIT:
To move the file to the same folder structure, when inside the loop, you simply use the replace function to replace the source Directory path (the first part of the Directory Name) with your destination base path. Then the sub folders will remain the same. e.g.
...
$DestinationDir = $ZipFile.DirectoryName.Replace($ZipFilesPath,$upzipPath)
...
$BackupFiles |% {Move-Item $_.Fullname $DestinationDir/$ZipFileActualName'_backup'.$typefilter}

Unable to delete zip folders older than 14 days

I am unable to delete zip folders older than 14 days from a directory. The rest of my script works fine, however the following code block is failing:
It has not thrown any errors, the path has been sanity checked, however, I placed old documents in to see if they are cleared up to no avail. It prints the statement that the folder path exists however does not delete anything from the folder.
if (!(Test-Path $folderpath)) {
New-Item -ItemType Directory -Path $folderpath
Write-Host "$folderpath created"
} else {
Write-Host "$folderpath already exists, will remove old items"
$HowOld = -14
Get-ChildItem $Path -Recurse |
where {$_.LastWriteTime -lt (Get-Date).AddDays($HowOld) -and -not $_.PSIsContainer} |
% {Remove-Item $_.FullName -Force -WhatIf}
}
Here is the full script for completeness:
#Get backup folder drive letter
$letter = [System.IO.DriveInfo]::getdrives() | Where-Object {$_.DriveType -eq 'Fixed' -and $_.Name -notlike '*C*'} | Select-Object -Property Name
[string] $drive = "$letter"
$Drive2 = $null
$Drive2 = $drive.Substring($drive.IndexOf('=')+1)
$BackupDrive = $Drive2.Substring(0, $Drive2.IndexOf('}'))
#Check the programname log path.
$logspath = "C:\ProgramData\programname\programname4.0\Logs"
If (!(test-path $logspath))
{
$IQlogspath = "C:\ProgramData\programname\iQSonar4.0\Logs"
}
Else
{
$IQlogspath = "C:\ProgramData\programname\programname4.0\Logs"
}
#check if backup folder exists, clean if exists and if not create it.
$folderpath = $BackupDrive + "programname_logs"
If(!(test-path $folderpath))
{
New-Item -ItemType Directory -Path $folderpath
write-host "$folderpath created"
}
Else
{
write-host "$folderpath already exists, will remove old items"
$HowOld = -14
get-childitem $Path -recurse | where {$_.lastwritetime -lt (get-date).adddays($HowOld) -and -not $_.psiscontainer} |% {remove-item $_.fullname -force -whatif}
}
#check if todays folder exists, if not create it
$todaysdate = (Get-Date).ToString('dd-MM-yyyy')
$todaysbackup = $folderpath + "\Logs_Backup_" + $todaysdate
$todaysbackupzip = $todaysbackup + ".zip"
If(!(test-path $todaysbackup))
{
New-Item -ItemType Directory -Path $todaysbackup
write-host "$todaysbackup created, now moving items"
#select and move files to backup folder
get-childitem -Path $IQlogspath |
where-object {$_.LastWriteTime -lt (get-date).AddDays(-7) -and $_.Name -notmatch "Service"} |
move-item -destination $todaysbackup
Start-Sleep -s 10
write-host "checking for zip"
If(Test-path $todaysbackupzip) {
write-host "$todaysbackupzip already exists, changing name"
$todaysbackupzip = $null
$todaysbackupzip = $folderpath + "\Logs_Backup_" + $todaysdate + ".re-run" + ".zip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
write-host "creating zip folder, $todaysbackupzip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
Else
{
write-host "$todaysbackup already exists, attempting to zip"
#check if zip backup folder already exists
If(Test-path $todaysbackupzip) {
write-host "$todaysbackupzip already exists, changing name"
$todaysbackupzip = $null
$todaysbackupzip = $folderpath + "\Logs_Backup_" + $todaysdate + ".re-run" + ".zip"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
Else
{
Start-Sleep -s 10
write-host "creating zip folder, $todaysbackupzip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($todaysbackup, $todaysbackupzip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}
}
#Get OS disk label
$OSDisk = Get-WmiObject Win32_OperatingSystem | Select-Object WindowsDirectory
[string] $drive = "$OSDisk"
$Drive2 = $null
$Drive2 = $drive.Substring($drive.IndexOf('=')+1)
$OSDrive = $Drive2.Substring(0, $Drive2.IndexOf('\'))
$OSDrive2 = "'$OSDrive'"
$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID=$OSDrive2"| Select-Object FreeSpace
[INT] $FreeSpace = $disk.FreeSpace /1GB
If ($FreeSpace -gt 5) {
write-host "no additional backup requirement, exiting script"
exit
}
Else {
write-host "Running one off clear"
$OneOff = $IQlogspath + "\Logs_One_Off_" + $todaysdate
$OneOffZip = $OneOff + ".zip"
If(!(test-path $OneOff))
{
New-Item -ItemType Directory -Path $OneOff
write-host "$OneOff created"
}
Else {
write-host "folder already exists"
}
#select and move files to backup folder
write-host "moving logs to $OneOff"
get-childitem -Path $IQlogspath |
where-object {$_.Name -notmatch "Service"} |
move-item -destination $OneOff
Start-Sleep -s 10
write-host "creating zip folder, $todaysbackupzip"
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($OneOff, $OneOffZip)
write-host "$todaysbackupzip created"
Remove-Item -Recurse -Force $todaysbackup
write-host "$todaysbackup removed"
exit
}

Powershell: Move files to folder based on Date Created

I'm not a coder but I've still attempted tweaking PS scripts found here and still can't get the behavior I desire. The tough part for me has been the 2 digit Day requirement (dd). After several noob attempts I would like some help.
I have a folder that contains hundreds of JPG's. I manually sort these JPG's into folders based on the date taken. Folder name examples are 2015.02.04, 2016.10.31, 2016.12.01.
1) I would like a script to scan my JPG folder.
2) For each file, scan the date
3) If the file was created June 1st, 2016 then it will be moved to .\2016.06.01
Help a brother out?
$Filepath = ""
$file = ""
$date = ""
$month = ""
$year = ""
$MonthPath = ""
$FilePath = Read-Host "Place the directory which contains the files."
Write-Warning "Note: This action can take several minutes, depending on the amount of files in $FilePath."
get-childitem $FilePath | % {
$file = $_.FullName
$date = Get-Date ($_.LastWriteTime)
$month = $date.month
$year = $date.year
$day = $date.day
$MonthPath = "$FilePath\$year.$month.$day"
Write-Verbose "month = $month"
Write-Verbose "Date = $date"
Write-Verbose "year = $year"
Write-Verbose "FilePath = $FilePath"
Write-Verbose "Filename = $file"
Write-Verbose "MonthPath = $MonthPath"
if(!(Test-Path -Path "$MonthPath" )){
Write-Verbose "Creating log location $MonthPath."
#Write-Host -backgroundcolor green -ForegroundColor black "Creating log location $MonthPath."
Write-Verbose "MonthPath inside path test = $MonthPath"
New-Item -ItemType directory -Path $MonthPath | Out-null
}
ELSE {
#Write-Host -backgroundcolor green -ForegroundColor black "Log location exists already exist $MonthPath"
Write-Verbose "Log location exists already exist $MonthPath"
}
move-item "$file" "$MonthPath" | Out-null
}
Write-Warning "All files are sorted now based upon year and month."
[DateTime]$start_time="2016-6-1 00:00:00"
[DateTime]$end_time="2016-6-1 23:59:59"
$des_folder = "C:\test\2016.06.1"
Get-ChildItem c:\test\*.jpg -Recurse | foreach {if($_.lastwritetime -ge $start_time -and $_.lastwritetime -le $end_time) { move-item $_.fullname $des_folder }}
Please ensure there is no name conflict .
You may change"c:\test" in "c:\test*.jpg" to the path you want to scan .
Also the value of variable "$des_folder" to the destination folder you want to store the matched pictures .
EDIT:
Get-ChildItem c:\test\test2\*.jpg -Recurse | foreach {
$x = $_.LastWriteTime.ToShortDateString()
$new_folder_name = Get-Date $x -Format yyyy.MM.dd
$des_path = "c:\test\test2\$new_folder_name"
if (test-path $des_path){
move-item $_.fullname $des_path
} else {
new-item -ItemType directory -Path $des_path
move-item $_.fullname $des_path
}
}
I ended up creating a script that does exactly what you're asking for here. You can find it in GitHub here, which will have the latest version of the code.
Here is the current implementation, edited for conciseness, removed unnecessary features, and tailored to the question's needs:
[string] $SourceDirectoryPath = 'C:\FilesToMove'
[string] $TargetDirectoryPath = 'C:\SortedFiles'
[System.Collections.ArrayList] $filesToMove = Get-ChildItem -Path $SourceDirectoryPath -File -Force -Recurse
$filesToMove | ForEach-Object {
[System.IO.FileInfo] $file = $_
[DateTime] $fileDate = $file.LastWriteTime
[string] $dateDirectoryName = $fileDate.ToString('yyyy.MM.dd')
[string] $dateDirectoryPath = Join-Path -Path $TargetDirectoryPath -ChildPath $dateDirectoryName
if (!(Test-Path -Path $dateDirectoryPath -PathType Container))
{
Write-Verbose "Creating directory '$dateDirectoryPath'."
New-Item -Path $dateDirectoryPath-ItemType Directory -Force > $null
}
[string] $filePath = $file.FullName
Write-Information "Moving file '$filePath' into directory '$dateDirectoryPath'."
Move-Item -Path $filePath -Destination $dateDirectoryPath
}
Note that it copies the file paths into an array before iterating over them. This is important for the cases where you are copying files to subdirectories of their current directory, otherwise Get-ChildItem could scan files twice, iterating over files that it just moved.
Expanded more to cover off duplicates
$jpg_files = Get-ChildItem "F:\*.jpg" -Recurse
foreach ($jpg in $jpg_files){
$x = $jpg.LastWriteTime.ToShortDateString()
$new_folder = Get-Date $x -Format yyyy-MM-dd
$des_path = "F:\Photos\$($new_folder)"
if (Test-Path $des_path){
if (Test-Path "$($des_path)\$($jpg.Name)"){
$index = 1
do {
$new_name = $des_path + "\" + $jpg.BaseName + " ($($index))" + $jpg.Extension
$index++
} While(Test-Path $new_name)
move-item $jpg.fullname -destination $new_name
}else {
move-item $jpg.fullname $des_path
}
}
else {
new-item -ItemType directory -Path $des_path
move-item $jpg.fullname $des_path
}
I would like to propose this variant based on last response for duplicates showing that multiple files can be selected and also that removing the absolute paths works and it will move the files that are bellow of your current prompt no mathers where the file is. Also add a missing }. Thanks to all that contributes to this thread, this helps a lot to organize the pictures and video!
$files = Get-ChildItem "*.jpg","*.mp4" -Recurse
foreach ($file in $files) {
$x = $file.LastWriteTime.ToShortDateString()
$new_folder = Get-Date $x -Format yyyy-MM
$des_path = "$($new_folder)"
if (Test-Path $des_path) {
if (Test-Path "$($des_path)\$($file.Name)") {
$index = 1
do {
$new_name = $des_path + "\" + $file.BaseName + " ($($index))" + $file.Extension
$index++
} While(Test-Path $new_name)
move-item $file.fullname -destination $new_name
}else {
move-item $file.fullname $des_path
}
}
else {
new-item -ItemType directory -Path $des_path
move-item $file.fullname $des_path
}
}

Piped dir within Foreach

I'm writing a script to delete pdf files older than 6 months in folder with the 'Email' prefix.
However, my second dir command within my foreach never runs, its code is blocked.
$Now = Get-Date;
$DaysTillDelete = "180";
$LastWrite = $Now.AddDays(-$DaysTillDelete);
$TargetFolder = "C:\Test EMDATA\EMDATA\";
$BackupPath = "\\SHPFS02\IT\EmPower Old";
$EmailFolders = #();
if(-Not(Test-Path -path ($TargetFolder + "\OldFiles" ))) {
mkdir -p ($TargetFolder +"\OldFiles");
}
$Network = Test-Path $BackupPath
#New-PSDrive -Name O -PSProvider FileSystem -Root "$BackupPath"; #-Credential $cred
Write-Host "Running Script"
dir $TargetFolder | %{
# Only delete files with the Email prefix
$name = $_.Name;
if ($_.Name.Length -le 5) {return;}
$id = $_.Name.SubString(0,5);
if ($id -eq "Email")
{
Write-Host "Found slip folder"
$EmailFolders += $TargetFolder + $_;
}
}
ForEach ($folder in $EmailFolders)
{
Write-Host $folder;
dir -path $folder -include *.pdf | %{
Write-Host "Checking" $name;
# Only select files older than 6 months
if( $_.LastWriteTime -le "$LastWrite")
{
$activeItem = Get-Item $TargetFolder + $_;
#Move files into oldfiles
Write-Host $TargetFolder
move-item -path $activeItem -destination ($TargetFolder + "OldFiles\");
if ($Network)
{
move-item -path $activeItem -destination "O:\";
}
Write-Host $_;
remove-item $activeItem;
Write-Host "Deleting" + $name;
}
}
}
The script works till line 31 but doesn't continue on past line 32 and being a fairly beginner PS user I can't see why.
Only use -include with the -recurse parameter.
http://technet.microsoft.com/en-us/library/hh849800.aspx
The Include parameter is effective only when the command includes the
Recurse parameter or the path leads to the contents of a directory,
such as C:\Windows*, where the wildcard character specifies the
contents of the C:\Windows directory.
What you want instead is the -filter parameter:
dir -path $folder -filter *.pdf