I currently have the following script that im running in PowerShell. I want to get a list of files in the directory of where the PS script resides, i want all files where the lastmodifieddate is more than 30 days ago and then move them. Im not sure what im doing wrong here.
param (
[Parameter(Mandatory=$true)][string]$destinationRoot
)
$path = (Get-Item -Path ".\").FullName
Get-ChildItem $path\* -Include *.xlsx|
Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)}
Foreach-Object {
$content = $path + "\" + $_.Name
$year = (Get-Item $content).LastWriteTime.year.ToString()
$monthNumber = (Get-Item $content).LastWriteTime.month
$month = (Get-Culture).DateTimeFormat.GetMonthName($monthNumber)
$destination = $destinationRoot + "\" + $year + "\" + $month
New-Item -ItemType Directory -Force -Path $destination
Move-Item -Path $content -Destination $destination -force
}
I use -f for format string
Not necessary to use $path
Use -File to exclude directory and -Filter for filter extension
You can rectify your code like this :
param (
[Parameter(Mandatory=$true)][string]$destinationRoot
)
Get-ChildItem -File -Filter "*.xlsx" | Where LastWriteTime -lt (Get-Date).AddDays(-10) | %{
$destination= "{0}\{1:yyyy\\MMMM}" -f $destinationRoot, $_.LastWriteTime
New-Item -ItemType Directory -Force -Path $destination
Move-Item $_.FullName -Destination $destination -Force
}
Related
Trying to get my copy-item to copy everything in directory except a subfolder. I was able to exclude in the folder and files, but not subfolders.
I tried using get-children and the -exclude in the copy-item but didn't exclude them as I hope
$exclude = "folder\common"
Get-ChildItem "c:\test" -Directory |
Where-Object{$_.Name -notin $exclude} |
Copy-Item -Destination 'C:\backup' -Recurse -Force
Hoping that the common folder will exist but nothing in it would be copy.
Thanks for the help
I think this should do what you need:
$sourceFolder = 'C:\test'
$destination = 'C:\backup'
$exclude = #("folder\common") # add more folders to exclude if you like
# create a regex of the folders to exclude
# each folder will be Regex Escaped and joined together with the OR symbol '|'
$notThese = ($exclude | ForEach-Object { [Regex]::Escape($_) }) -join '|'
Get-ChildItem -Path $sourceFolder -Recurse -File |
Where-Object{ $_.DirectoryName -notmatch $notThese } |
ForEach-Object {
$target = Join-Path -Path $destination -ChildPath $_.DirectoryName.Substring($sourceFolder.Length)
if (!(Test-Path -Path $target -PathType Container)) {
New-Item -Path $target -ItemType Directory | Out-Null
}
$_ | Copy-Item -Destination $target -Force
}
Hope that helps
I think using the -exclude parameter on Get-ChildItem would work:
$exclude = 'Exclude this folder','Exclude this folder 2','Folder3'
Get-ChildItem -Path "Get these folders" -Exclude $exclude | Copy-Item -Destination "Send folders here"
Here is an example:
$exclude= 'subfolderA'
$path = 'c:\test'
$fileslist = gci $path -Recurse
foreach ($i in 0..$fileslist){ if( -not ($i.Fullname -like "*$($exlusion)*")){ copy-item -path $i.fullname -Destination 'C:\backup' -Force } }
I have a folder hierarchy with a lot of files.
I need to copy all folders and only selected files. For this purposes I write script:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181"
$files = Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" }
$Destination = "D:\test\"
Copy-Item $files -Destination $Destination -recurse
When I execute variable $files, it returns correct path:
But when I execute Copy-Item it returns not full path:
Perhaps my approach is wrong. If so, how to copy entire folder structure, and only selected files (in this case system.serviceModel.client.config file)?
UPD1 Ok, I've found, how to copy only folders:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181\"
$Destination = "D:\test\"
Copy-Item $path $Destination -Filter {PSIsContainer} -Recurse -Force
But how to copy only selected files, preserving their location? What needs to be in $Destination variable?
$files = Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" } | % { Copy-Item -Path $_.FullName -Destination $Destination }
This code would keep the directory structure the same too
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181\"
$Destination = "D:\test\"
$fileName = "system.serviceModel.client.config"
Get-ChildItem -Path $path -Recurse | ForEach-Object {
if($_.Name -like $fileName) {
$dest = "$Destination$(($_.FullName).Replace($path,''))"
$null = New-Item $dest -Force
Copy-Item -Path $_.FullName -Destination $dest -Force
}
}
To copy the whole folder structure AND files with a certain name, below code should do what you want:
$Source = 'D:\Drop\SOA-ConfigurationManagement - Test\181'
$Destination = 'D:\test'
$FileToCopy = 'system.serviceModel.client.config'
# loop through the source folder recursively and return both files and folders
Get-ChildItem -Path $Source -Recurse | ForEach-Object {
if ($_.PSIsContainer) {
# if it's a folder, create the new path from the FullName property
$targetFolder = Join-Path -Path $Destination -ChildPath $_.FullName.Substring($Source.Length)
$copyFile = $false
}
else {
# if it's a file, create the new path from the DirectoryName property
$targetFolder = Join-Path -Path $Destination -ChildPath $_.DirectoryName.Substring($Source.Length)
# should we copy this file? ($true or $false)
$copyFile = ($_.Name -like "*$FileToCopy*")
}
# create the target folder if this does not exist
if (!(Test-Path -Path $targetFolder -PathType Container)) {
$null = New-Item -Path $targetFolder -ItemType Directory
}
if ($copyFile) {
$_ | Copy-Item -Destination $targetFolder -Force
}
}
try this
$path = 'D:\Drop\SOA-ConfigurationManagement - Test\181\'
$Destination = 'D:\test\'
$files = Get-ChildItem -Path $path -Recurse -File | where Name -like "*system.serviceModel.client.config*" | %{
$Dir=$_.DirectoryName.Replace($path, $Destination)
$NewPAthFile=$_.FullName.Replace($path, $Destination)
#create dir if not exists
New-Item -Path $Dir -ItemType Directory -Force -ErrorAction SilentlyContinue
#copy file in new dir
Copy-Item $_.FullName $NewPAthFile
}
With minimal changes I'd suggest the following:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181"
$files = Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" }
$Destination = "D:\test\"
$files | % { $_ | Copy-Item -Destination $Destination -recurse }
You can even put the whole copy on one line:
$path = "D:\Drop\SOA-ConfigurationManagement - Test\181"
$Destination = "D:\test\"
Get-ChildItem -Path $path -Recurse | ? { $_.Name -like "system.serviceModel.client.config" } | % { $_ | Copy-Item -Destination $Destination -recurse }
Copy-Item can find the path from the stream of input objects but it doesn't seem to be able to take a collection of System.IO.FileInfo objects as an argument to Path.
Trying to get my copy-item to copy everything in directory except a subfolder. I was able to exclude in the folder and files, but not subfolders.
I tried using get-children and the -exclude in the copy-item but didn't exclude them as I hope
$exclude = "folder\common"
Get-ChildItem "c:\test" -Directory |
Where-Object{$_.Name -notin $exclude} |
Copy-Item -Destination 'C:\backup' -Recurse -Force
Hoping that the common folder will exist but nothing in it would be copy.
Thanks for the help
I think this should do what you need:
$sourceFolder = 'C:\test'
$destination = 'C:\backup'
$exclude = #("folder\common") # add more folders to exclude if you like
# create a regex of the folders to exclude
# each folder will be Regex Escaped and joined together with the OR symbol '|'
$notThese = ($exclude | ForEach-Object { [Regex]::Escape($_) }) -join '|'
Get-ChildItem -Path $sourceFolder -Recurse -File |
Where-Object{ $_.DirectoryName -notmatch $notThese } |
ForEach-Object {
$target = Join-Path -Path $destination -ChildPath $_.DirectoryName.Substring($sourceFolder.Length)
if (!(Test-Path -Path $target -PathType Container)) {
New-Item -Path $target -ItemType Directory | Out-Null
}
$_ | Copy-Item -Destination $target -Force
}
Hope that helps
I think using the -exclude parameter on Get-ChildItem would work:
$exclude = 'Exclude this folder','Exclude this folder 2','Folder3'
Get-ChildItem -Path "Get these folders" -Exclude $exclude | Copy-Item -Destination "Send folders here"
Here is an example:
$exclude= 'subfolderA'
$path = 'c:\test'
$fileslist = gci $path -Recurse
foreach ($i in 0..$fileslist){ if( -not ($i.Fullname -like "*$($exlusion)*")){ copy-item -path $i.fullname -Destination 'C:\backup' -Force } }
I am fairly new to powershell and have been tasked at cleaning up an archive server. I am trying to create a script to move files into a Year\Month folder structure by looking at it's LastWriteTime in Powershell.
I have the below however I do not know how to get it to look at the month the file was edited?
$Path = "D:\Data"
$NewPath = "D:\ArchiveData"
$Year = (Get-Date).Year
$Month = (Get-Date).Month
New-Item $NewPath\ -name $CurrentYear -ItemType Directory
New-Item $NewPath\$Year -Name $Month -ItemType Directory
Get-ChildItem -path $Path | Where-Object {$_.LastWriteTime -Contains (Get-Date).month} | Move-Item -Destination "$NewPath\$Year\$Month"
Any ideas of how I could do this would be appreciated?
Thanks
-contains is used to see if an array contains an item; it's not suitable here.
-eq is what you need. As per your variable $Month, you will need to get only the part you care about (i.e. the month):
($_.LastWriteTime).Month -eq (Get-Date).month
I think I would approach this from the other end. Directories can be created when needed.
When you are satisfied that the files would be moved correctly, remove the -WhatIf from the Move-Item cmdlet.
$Path = 'C:\src\t'
$NewPath = 'C:\src\tarch'
Get-ChildItem -File -Path $Path |
ForEach-Object {
$Year = $_.LastWriteTime.Year
$Month = $_.LastWriteTime.Month
$ArchDir = "$NewPath\$Year\$Month"
if (-not (Test-Path -Path $ArchDir)) { New-Item -ItemType "directory" -Path $ArchDir | Out-Null }
Move-Item -Path $_.FullName -Destination $ArchDir -WhatIf
}
I have a Problem with my Powershell Script. ;(
I want to delete/ move/ compare with Powershell.
Here my Idea:
If I start the Script I remove all empty folder from A. After that I want Move all Data from A to B that x Days older. (Here is my first problem)
If I make copy it works fine.
A other Idea is to compare A and B and only the diffrend to copy or move. (But I don't know how I can do this)
Here is my Code:
function removeFiles($source,$destination){
$elements = Get-ChildItem $source -Recurse
foreach($element in $elements){
if(($element.PSIsContainer) -and (!(Get-ChildItem -Recurse -Path $element.FullName))){
Write-Host "DELETE: " $element.FullName
Remove-Item $element.FullName -Confirm:$false
}
}
}
function copyFiles($source,$destination,$days){
$elements = Get-ChildItem $source -Recurse
$lastwrite = (Get-Date).AddDays(-$days)
foreach($element in $elements){
if($element.creationTime -le $lastwrite){
$targetFile = $destination + $element.FullName.SubString($source.Length)
if($element.PSIsContainer){
Write-Host "COPY FOLDER : " $element.FullName
Copy-Item $element.FullName -Destination $targetFile
}else{
Write-Host "COPY FILE : " $element.FullName
Copy-Item $element.FullName -Destination $targetFile
}
}
}
}
function moveFiles($source,$destination,$days){
Get-ChildItem -Path $source -Recurse | Where-Object {$_.LastWriteTime -lt (get-date).AddDays(-2)} | Move-Item -Destination $destination
}
CLS
$Source = "C:\Users\tarasov_w\Downloads"
$Destination = "C:\Users\tarasov_w\Desktop\ps_test"
$LogFile = "C:\Users\tarasov_w\Desktop\$(get-date -format 'MMddyyyy').txt"
$Days = 1
Start-Transcript $LogFile -noclobber
Write-Host "Start..."
removeFiles -source $Source -destination $Destination
#copyFiles -source $Source -destination $Destination -days $Days
moveFiles -source $Source -destination $Destination -days $Days
Write-Host "Fertig!"
UPDATE:
function compareFiles($source,$destination){
$folderA = Get-ChildItem $source -Recurse
$folderB = Get-ChildItem $destination -Recurse
$diff = Compare-Object -ReferenceObject $folderA -DifferenceObject $folderB -PassThru
foreach($element in $diff){
$element_fullname = $element.FullName
if($element.PSIsContainer){
# ????
}
}
}