I have a script that reorganizes files in C:\Year\Month\"StoreFiles" to "C:\Store\Date\"StoreFiles" based on modified date.
#Variables
$StoreName = "aStore"
$SourceDir = "C:\Source"
$TargetDir = "C:\$StoreName"
# Create Folder based on Store List
if(-Not (Test-Path -Path $TargetDir)) {
New-Item -ItemType Directory -Path $TargetDir
}
# Search & create folders based on date
Get-ChildItem "$SourceDir\*$StoreName*" -Recurse | ForEach-Object {
$x = $_.LastWriteTime.ToShortDateString()
$new_folder_name = Get-Date $x -Format MMM-yyyy
$des_path = "$TargetDir\$new_folder_name"
if (Test-Path $des_path) {
Copy-Item $_.FullName $des_path
} else {
New-Item -ItemType Directory -Path $des_path
Copy-Item $_.FullName $des_path
}
}
Works great however the modified date isn't ideal. Can I use the original folder path of "C:\Year\Month\"StoreFiles" and use it as dates for the new output?
In a sense I am trying to do the following:
"C:\Year\Month\"StoreFiles" to "C:\Store\Month-Year\"StoreFiles"
Maybe I should assign the folder path as a variable and use it accordingly for the new output?
Or is there another way I should think about doing this.
try Something like this
$dirroot="C:\temp\Root"
$store="C:\store"
Get-ChildItem $dirroot -file -Recurse |
where FullName -match ([Regex]::Escape($dirroot) + "\\\d{4}\\\d{1,2}\\" + [Regex]::Escape($_.Name)) |
% {
$elements=$_.FullName.Replace($dirroot, '').Split('\')
New-Item -ItemType Directory -Path "$store\$($elements[2])-$($elements[1])" -Force
Copy-Item $_.FullName "$store\$($elements[2])-$($elements[1])\$($elements[3])"
}
Cann't you use something like this?
$DateInfo = '' | select-object -Property 'Year', 'Month'
$File = 'c:\2014\may\filename.txt'
$TopFolderpath = [io.Path]::GetDirectoryName($File)
$TopFolderName = [io.Path]::GetFileName($TopFolderpath)
$DateInfo.Month = $TopFolderName
$Subfolderpath = [io.Path]::GetDirectoryName($TopFolderpath)
$SubFolderName = [io.Path]::GetFileName($Subfolderpath)
$DateInfo.Year = $SubFolderName
$DateInfo
Related
So far I have tried the following script:
$SourceFolder = "D:\WORK\JetLetter\LKY\LKY_jV_004\"
$TargetFolder = "D:\WORK\JetLetter\LKY\LKY_jV_004\Final\"
Get-ChildItem -Path $SourceFolder -Filter *.pdf |
ForEach-Object {
$ChildPath = Join-Path -Path $_.Name.Replace('.pdf','') -ChildPath $_.Name
[System.IO.FileInfo]$Destination = Join-Path -Path $TargetFolder -ChildPath $ChildPath
if( -not ( Test-Path -Path $Destination.Directory.FullName )){
New-Item -ItemType Directory -Path $Destination.Directory.FullName
}
Copy-Item -Path $_.FullName -Destination $Destination.FullName
}
This creates a folder for every pdf in the folder.
I need it create a single folder based on the 5 digit in the name and move those files into the new folder.
For example: I could have 10 pdf's that have the number "30565" in them and the new folder should be named "30565"
Here are some file names to explain:
LKY_20974_Pr01_1-5000.pdf
to
D:\WORK\JetLetter\LKY\LKY_jV_004\Final\20974
LKY_20974_Pr02_5001-10000.pdf
to
D:\WORK\JetLetter\LKY\LKY_jV_004\Final\20974
LKY_20974_Pr03_10001-15000.pdf
to
D:\WORK\JetLetter\LKY\LKY_jV_004\Final\20974
I have tried to include an else block to the best answer script and haven't had much success. I did however create a separate script that will archive the files before creating a new file. I just have to run it before the main powershell script.
$SourceDir = 'D:\WORK\JetLetter\LKY\LKY_jV_004_9835'
$DestDir = 'D:\WORK\JetLetter\LKY\#Print_Production_Files'
$ArchiveDir = 'D:\WORK\JetLetter\LKY\#Print_Production_Files\#archive'
$Filter = '*.pdf'
$FileList = Get-ChildItem -LiteralPath $SourceDir -Filter $Filter -File
foreach ($FL_Item in $FileList)
{
# this presumes the target dir number is ALWAYS the 2nd item in the split string
$TargetDir = $FL_Item.BaseName.Split('_')[1]
$FullTargetDir = Join-Path -Path $DestDir -ChildPath $TargetDir
if (Test-Path -LiteralPath $FullTargetDir)
{
# the "$Null =" is to suppress unwanted output about what was done
$null = Move-Item -Path $FullTargetDir -Destination $ArchiveDir -Force
}
}
This has made the files and folders a lot more organized.
i think this does what you want done. [grin] the comments seem adequate, but if you have any questions, please ask.
$SourceDir = 'c:\temp\JetLetter\LKY\LKY_jv_004'
$DestDir = 'c:\temp\JetLetter\LKY\LKY_jv_004\Final'
$Filter = '*.pdf'
#region >>> make the dirs and sample files to work with
# remove the entire "#region/#endregion" block when you are ready to work with real data
# make the dirs
$Null = mkdir -Path $SourceDir, $DestDir -ErrorAction 'SilentlyContinue'
# make the test files
$SampleFiles = #(
'LKY_11111_Pr11_1-11111.pdf'
'LKY_22222_Pr22_2-22222.pdf'
'LKY_22222_Pr22_2222-2222.pdf'
'LKY_33333_Pr33_3-3333.pdf'
'LKY_33333_Pr33_33333-33333.pdf'
'LKY_55555_Pr55_5-5555.pdf'
'LKY_77777_Pr77_7-77777.pdf'
'LKY_77777_Pr77_77777-77777.pdf'
'LKY_99999_Pr99_9-99999.pdf'
)
foreach ($SF_Item in $SampleFiles)
{
# the "$Null =" is to suppress unwanted output about what was done
$Null = New-Item -Path $SourceDir -Name $SF_Item -ItemType 'File' -ErrorAction 'SilentlyContinue'
}
#endregion >>> make the dirs and sample files to work with
$FileList = Get-ChildItem -LiteralPath $SourceDir -Filter $Filter -File
foreach ($FL_Item in $FileList)
{
# this presumes the target dir number is ALWAYS the 2nd item in the split string
$TargetDir = $FL_Item.BaseName.Split('_')[1]
$FullTargetDir = Join-Path -Path $DestDir -ChildPath $TargetDir
if (-not (Test-Path -LiteralPath $FullTargetDir))
{
# the "$Null =" is to suppress unwanted output about what was done
$Null = New-Item -Path $FullTargetDir -ItemType 'Directory'
}
$NewFullFileName = Join-Path -Path $FullTargetDir -ChildPath $FL_Item.Name
# leave the file in the source dir if it already is in the final target dir
# you may want to save the not-copied info to a file for later review
if (-not (Test-Path -LiteralPath $NewFullFileName))
{
# the "Move-Item" cmdlet on win7ps5.1 is wildly unreliable
# so i used copy & then remove
$Null = Copy-Item -LiteralPath $FL_Item.FullName -Destination $NewFullFileName
Remove-Item -LiteralPath $FL_Item.FullName
}
else
{
Write-Warning (' {0} already exists in {1}' -f $FL_Item.Name, $FullTargetDir)
Write-Warning ' The file was not moved.'
Write-Warning ''
}
}
screen output only exists for "not moved" files. again, you may want to save the list to a $Var or to a file for later work.
one of the moved files ...
C:\Temp\JetLetter\LKY\LKY_jv_004\Final\22222\LKY_22222_Pr22_2222-2222.pdf
I'm supposed to move data from an old server to a new one while changing the structure.
Example:
old: "C:\test\old\Data\Werkstatt\06. Aufträge\companyA\200031_Signs"
new: "C:\test\new\Data\06. Aufträge\companyA\200031_companyA_Signs"
In the old structure, the orders of a company are in a single folder.
In the new structure, all orders are to be migrated directly under the orders folder. The name consists of the order number + separator + company name + name.
current task is the folders that were successfully copied from "C:\test\old\Data\Werkstatt\06. Aufträge\%company%\" in the folder "C:\test\old\Data\Werkstatt\06. Aufträge\%company%\Z_Transfered" to move.
I tried:
$sourcepath = "C:\test\old\Data\Werkstatt\06. Aufträge"
$basepath = "C:\test\new\Data\06. Aufträge"
$Orders = Get-ChildItem -Path $sourcepath -Directory -Recurse -Depth 1
ForEach ($Order in $Orders ) {
if ($Order.name.StartsWith("20")){
$NewFolderName = "{0}\{1}" -f ($BasePath),($order.Name.insert(6,"_" + $order.parent.Name))
$NewFolder = New-Item -Path $NewFolderName -ItemType "directory"
Copy-Item -Path "$($Order.FullName)\*" -Destination $NewFolder -Recurse -Force
#under construction
$MoveFolderName = Join-Path -path $sourcepath -ChildPath $order.parent | Join-Path -ChildPath "Z_Transfered"
if (-not (Test-Path $MoveFolderName))
{
New-Item -Path $MoveFolderName -ItemType "directory"
}
$MoveFolder = $MoveFolderName +"\" + $order.name
Move-Item -Path "$($Order.FullName)\*" -Destination $MoveFolder
$error > $sourcepath"\error.log"
}
}
I adapted the code I got yesterday. Currently I have one more error in the code.
Copy content to the right place works now.
Currently he creates the folder Z_Transfered below the customer folder. The problem seems to be with Move-Item.
Currently, the folder is not moved to Z_Transfered, only the files under the customer folder are moved and, unfortunately, also renamed. Can someone help me here please?
You can get the parentfolder of a folder by putting .parent to the pathobject > $path.parent. And you can even get the grandparent that way > $path.parent.parent.
So all that is left is a little string manipulation to get the new folder name:
$sourcepath = "d:\test\Data\Orders" # Adjust this
$BasePath = "d:\test\Data\Orders" # Adjust this
$Orders = Get-ChildItem -Path $sourcepath -Directory -Recurse -Depth 2
ForEach ($Order in $Orders ) {
if ( $Order.parent.parent.Name -eq "Orders" ){
$NewFolderName = "{0}\{1}" -f ($BasePath),($order.Name.replace("_","_$($Order.parent)_"))
$NewFolder = New-Item -Path $NewFolderName -ItemType "directory"
Move-Item -Path "$($Order.FullName)\*" -Destination $NewFolder -WhatIf
}
}
In Powershell 5 Get-ChildItem got the -Depth parameter so you can limit it to search only two levels below your $sourcepath. The replace will look for _ in the foldername so make sure thery all contain only one.
it works :)
many thanks for your help.
The script works now as I need it.
$sourcepath = "C:\test\old\Data\Werkstatt\06. Aufträge"
$basepath = "C:\test\new\Data\06. Aufträge"
$Orders = Get-ChildItem -Path $sourcepath -Directory -Recurse -Depth 1
ForEach ($Order in $Orders ) {
if ($Order.name.StartsWith("20")){
$NewFolderName = "{0}\{1}" -f ($BasePath),($order.Name.insert(6,"_" + $order.parent.Name))
$NewFolder = New-Item -Path $NewFolderName -ItemType "directory"
Copy-Item -Path "$($Order.FullName)\*" -Destination $NewFolder -Recurse -Force
$MoveFolderName = Join-Path -path $sourcepath -ChildPath $order.parent | Join-Path -ChildPath "Z_Transfered"
if (-not (Test-Path $MoveFolderName))
{
$MoveFolder = New-Item -Path $MoveFolderName -ItemType "directory"
}
Move-Item -path "$($Order.FullName)\" -Destination $MoveFolderName -force
$error > $sourcepath"\error.log"
}
}
Basically, I have a CSV file with a lot of columns. Let's say it looks like this:
_username, platform_
username1, platformX1
username2, platformY
username3, platformX2
username4, platformX2
..., ...
I would like to write a script that goes through the file and for each platform, it creates a file with the specific username in a different folder, so I would have:
\platformX1\username1.file
\platformY\username2.file
\platformX2\username3.file, username4.file
etc etc...
I know I should use foreach with an if placed somewhere, but powershell is new for me, and I don't really know how to start it.
Here's something similar tweaked to what you want to do.
This created files of a specific size in your directory
$data = get-content "C:\Data\masteFile.csv"
$drcty = "C:\Data"
foreach($line in $data)
{
$a,$b = $line.Split("{,}")
$parent = $drcty+"\"+$a+"\"
$filename = $parent + $b.TRIM() +".txt"
write-host $filename
New-Item -ItemType directory -Path $parent
fsutil file createnew $filename 2000
}
this seems to do what you want. [grin]
# fake reading in a CSV file
# in real life, use Import-CSV
$InStuff = #'
_UserName, Platform_
username1, platformX1
username2, platformY
username3, platformX2
username4, platformX2
'# | ConvertFrom-Csv
$DestDir = $env:TEMP
$Extension = 'txt'
foreach ($IS_Item in $InStuff)
{
$TargetPath = Join-Path -Path $DestDir -ChildPath $IS_Item.Platform_
if (-not (Test-Path -LiteralPath $TargetPath))
{
# "$Null = " will supress unwanted output from New-Item
$Null = New-Item -Path $TargetPath -ItemType Directory
}
$FileName = $IS_Item._UserName, $Extension -join '.'
$FullFileName = Join-Path -Path $TargetPath -ChildPath $FileName
if (-not (Test-Path -LiteralPath $FullFileName))
{
# "$Null = " will supress unwanted output from New-Item
$Null = New-Item -Path $FullFileName -ItemType File
}
}
i think what it does is apparent, but i know i get ahead of where i otta be at times. so, if there are any questions, please feel free to ask ... [grin]
This worked for me.
$ErrorActionPreference = "Stop"
#Path of the CSV file resides
$csvData = Import-Csv -Path "$env:USERPROFILE\Desktop\data.csv"
$DestinationFolder = "C:\Stuffs"
foreach($record in $csvData)
{
$destPlatformFolder = $DestinationFolder + "\" + $record.platform_
if(-not(Test-Path -Path $destPlatformFolder)){
New-Item -Path $destPlatformFolder -ItemType Directory -Force | Out-Null
}
$destinationFile = $destPlatformFolder + "\" + $record._username
New-Item -Path $destinationFile -ItemType File -Force | Out-Null
}
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
}
we are having folder/sub folder structure for our application.
Whenever we are adding new modules, we have to copy the folder structures exactly without copying files.
How to copy the folders and subfolders in the hierarchy but leaving the files alone?
This is a bit 'hacky' as Powershell doesn't handle this very well... received wisdom says to use xCopy or Robocopy but if you really need to use Powershell, this seems to work OK:
$src = 'c:\temp\test\'
$dest = 'c:\temp\test2\'
$dirs = Get-ChildItem $src -recurse | where {$_.PSIsContainer}
foreach ($dir in $dirs)
{
$target = ($dir.Fullname -replace [regex]::Escape($src), $dest)
if (!(test-path $target))
{
New-Item -itemtype "Directory" $target -force
}
}
$source = "<yoursourcepath>"
$destination = "<yourdestinationpath>"
Get-ChildItem -Path $source -Recurse -Force |
Where-Object { $_.psIsContainer } |
ForEach-Object { $_.FullName -replace [regex]::Escape($source), $destination } |
ForEach-Object { $null = New-Item -ItemType Container -Path $_ }