powershell - adding folder path with another path - powershell

$path = "c:\folder a"
$destFolder = "C:\"
$subFolder = "\folder c\folder d\"
$file = "file.txt"
$dir = Get-ChildItem $path | select -first 10 | Sort-Object -Property CreationTime
[array]::Reverse($dir)
$dir | format-table FullName
$fullPath = #()
ForEach ($i in $dir) {
$fullPath += $i + $subFolder + $file
}
$i = 0
while ($i -lt $fullPath.Count) {
$exists = Test-Path $fullPath[$i]
if ($exists){
Copy-Item -Path $fullPath[$i] -Destination $destFolder
break
}
$i++
}
having trouble getting &fullpath to work
edit:
&fullpath displays all the folder in the directory then adds the subfolder+file at the end.
I want it to take the 1 file path at a time from &dir and add the subfolder+file
sorry if I haven't explained it very well.
Im a total beginner at this kind of stuff

I think what you need is this:
$path = "c:\temp"
$destFolder = "C:\"
$subFolder = "\folder c\folder d\"
$file = "file.txt"
$childItems = Get-ChildItem $path | select -first 10 | Sort-Object -Property CreationTime -Descending
forEach ($item in $childItems)
{
$fullPath = Join-Path -Path $item.FullName -ChildPath "$subFolder$file"
if (Test-Path -Path $fullPath)
{
Copy-Item -Path $fullPath -Destination $destFolder
}
}

Related

Test-Path cmdlet fails only for one file out of 20

I want to get the duplicates from a folder structure and copy all of them to a single folder, while renaming (so they don't overwrite). I would like the first file from a duplicates group to be copied with it's original name, and for the rest to add "_X" at the end of the name.
I wrote a code that almost works, but at some point it just overwrites the first file copied. Only one file is being overwritten, the rest are renamed and copied like intended.
Get-ChildItem $SourcePath -Recurse -File -Force | Group-Object -Property Name | Where-Object {$_.Count -gt 1} | Select-Object -ExpandProperty Group |
ForEach-Object {
$SourceFile = $_.FullName
$FileName = $($_.BaseName + $_.Extension)
$DestFileName = Join-Path -Path $DestinationPath -ChildPath $FileName
if (Test-Path -Path $DestFileName) {
$DestinationFile = "$DestinationPath\" + $_.BaseName + "_" + $i + $_.Extension
$i+=1
} else {
$DestinationFile = $DestFileName
}
Copy-Item -Path $SourceFile -Destination $DestinationFile
}
I don't see the actual problem but you could rewrite the code without using Test-Path. Remove Select-Object -ExpandProperty Group too, then iterate over each group's elements. Increment a counter and append it to all file names except the first one.
Get-ChildItem $SourcePath -Recurse -File -Force | Group-Object -Property Name | Where-Object Count -gt 1 |
ForEach-Object {
$i = 0
foreach( $dupe in $_.Group ) {
$SourceFile = $dupe.FullName
$DestinationFile = Join-Path -Path $DestinationPath -ChildPath $dupe.BaseName
if( $i -gt 0 ) { $DestinationFile += "_$i" }
$DestinationFile += $dupe.Extension
Copy-Item -Path $SourceFile -Destination $DestinationFile
$i++
}
}

Powershell Unzip One Specific Folder in a File with Dynamic Name

I found a piece of code here that almost does what I need, which is extract just one folder from an archived file.
The only issue I have is that the archive name changes month on month, therefore I wanted to use a wildcard. Once a wildcard is specified (* in $zipfile), the script does not work for me.
I would be grateful for any suggestions.
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null
$zipfile = 'C:\ALL\Debtor*.zip'
$folder = 'tmp\st\sd'
$dst = 'C:\ALL\ZipOutput'
[IO.Compression.ZipFile]::OpenRead($zipfile).Entries | ? {
$_.FullName -like "$($folder -replace '\\','/')/*.*"
} | % {
$file = Join-Path $dst $_.FullName
$parent = Split-Path -Parent $file
if (-not (Test-Path -LiteralPath $parent)) {
New-Item -Path $parent -Type Directory | Out-Null
}
[IO.Compression.ZipFileExtensions]::ExtractToFile($_, $file, $true)
Try this out for size. Just use Get-ChildItem to locate the zip file in your ALL directory.
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null
$zipfile = Get-ChildItem -Path C:\ALL\ -Filter *.zip | Where-Object {$_.Name -like "Debtor*"} | Select-Object -ExpandProperty FullName
$folder = 'tmp\st\sd\'
$dst = 'C:\ALL\ZipOutput'
[IO.Compression.ZipFile]::OpenRead($zipfile).Entries | Where-Object {
$_.FullName -like "$($folder -replace '\\','/')/*.*"
} | ForEach-Object {
$file = Join-Path $dst $_.FullName
$parent = Split-Path -Parent $file
if(-not (Test-Path -LiteralPath $parent)) {
New-Item -Path $parent -Type Directory | Out-Null
}
[IO.Compression.ZipFileExtensions]::ExtractToFile($_, $file, $true)
}
I am also assuming that the archive name changes but there are not multiple archives with that name. If there are you will need to wrap everything in a Foreach($zip in $zipfile){ ... }

Exporting Object and strings to CSV using Powershell

The purpose of this code is to transfer files from one location to another and to log whether the transfer was a success or a failure.
Everything works except I am having issues with the log. I want the log to be in CSV format and there to be 3 columns: success/failure, from location, and to location. This is outputting the results all into rows with one column.
I've tried the Export-Csv option but that looks for objects/properties so only displays the length(I have strings too). Add-content works but there is only one column. Any suggestions?
#LOCATION OF CSV
$csv = Import-Csv C:\test2.csv
#SPECIFY DATE (EXAMPLE-DELETE FILES > 7 YEARS. 7 YEARS=2555 DAYS SO YOU WOULD ENTER "-2555" BELOW)
$Daysback = "-1"
#FILE DESTINATION
$storagedestination = "C:\Users\mark\Documents\Test2"
#LOG LOCATION
$loglocation = "C:\Users\mark\Documents\filetransferlog.csv"
$s = "SUCCESS"
$f = "FAIL"
$CurrentDate = Get-Date
foreach ($line in $csv) {
$Path = $line | Select-Object -ExpandProperty FullName
$DatetoDelete = $CurrentDate.AddDays($DaysBack)
$objects = Get-ChildItem $Path -Recurse | Select-Object FullName, CreationTime, LastWriteTime, LastAccessTime | Where-Object { $_.LastWriteTime -lt $DatetoDelete }
foreach ($object in $objects) {
try
{
$sourceRoot = $object | Select-Object -ExpandProperty FullName
Copy-Item -Path $sourceRoot -Recurse -Destination $storagedestination
Remove-Item -Path $sourceRoot -Force -Recurse
$temp = $s, $sourceRoot, $storagedestination
$temp | add-content $loglocation
}
catch
{
$temp2 = $f, $sourceRoot, $storagedestination
$temp2 | add-content $loglocation
}
}
}
All your | Select-Object -ExpandProperty are superfluous, simply attach the property name to the variable name => $Path = $line.FullName
Why calculate $DatetoDelete inside the foreach every time?
Output the success/fail to a [PSCustomObject] and gather them in a variable assigned directly to the foreach.
Untested:
$csv = Import-Csv C:\test2.csv
$Daysback = "-1"
$destination = "C:\Users\mark\Documents\Test2"
$loglocation = "C:\Users\mark\Documents\filetransferlog.csv"
$s = "SUCCESS"
$f = "FAIL"
$CurrentDate = Get-Date
$DatetoDelete = $CurrentDate.Date.AddDays($DaysBack)
$Log = foreach ($line in $csv) {
$objects = Get-ChildItem $line.FullName -Rec |
Where-Object LastWriteTime -lt $DatetoDelete
foreach ($object in $objects) {
$Result = $s
$sourceRoot = $object.FullName
try {
Copy-Item -Path $sourceRoot -Recurse -Destination $destination
Remove-Item -Path $sourceRoot -Recurse -Force
} catch {
$Result = $f
}
[PSCustomObject]#{
'Success/Fail' = $Result
Source = $sourceRoot
Destination = $destination
}
}
}
$Log | Export-Csv $loglocation -NoTypeInformation

Copy everything except files on the list

I am trying to copy all files recursively from a:\ to b:\, except those whose metadata is present in a:\list.txt. The list.txt pattern is LastWriteTimeYYYY-MM-DD HH:MM:SS,size,.fileextension, for example:
2001-01-31 23:59:59,12345,.doc
2001-01-31 23:59:59,12345,.txt
2001-01-31 23:59:00,456,.csv
...so any and all files, anywhere in the a:\ dir tree, matching these metadata should not be copied.
I seem to be having trouble with the Where-Object in order to exclude the items on the list.txt, but copy everything else:
$Source = "C:\a"
$Target = "C:\b"
$List = Import-Csv list.txt -Header LastWriteTime,Size,Name
$Hash = #{}
ForEach ($Row in $List){
$Key = ("{0},{1},.{2}" -F $Row.LastWriteTime,$Row.Size,$Row.Name.Split('.')[-1].ToLower())
IF (!($Hash[$Key])) {$Hash.Add($Key,$Row.Name)}
}
$Hash | Format-Table -Auto
Get-Childitem -Path $Source -Recurse -File | Where-Object {$Hash -eq $Hash[$Key]}| ForEach-Object {$Key = ("{0},{1},{2}" -F ($_.LastWriteTime).ToString('yyyy-MM-dd HH:mm:ss'),$_.Length,$_.Extension.ToLower())
#$Key
If ($Hash[$Key]){
$Destination = $_.FullName -Replace "^$([RegEx]::Escape($Source))","$Target"
If (!(Test-Path (Split-Path $Destination))){MD (Split-Path $Destination)|Out-Null}
$_ | Copy-Item -Destination $Destination
}
}
I propose you a simplification of your code :
$Source = "C:\a\"
$Target = "C:\b\"
New-Item -ItemType Directory $Target -Force | Out-Null
$List = Import-Csv list.txt -Header LastWriteTime,Length,Extension
Get-Childitem $Source -Recurse -File | %{
$File=$_
$exist=$List | where {$_.LastWriteTime -eq $File.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss') -and $_.Length -eq $File.Length -and $_.Extension -eq $File.Extension} | select -first 1
if ($exist -ne $null) {continue}
New-Item -ItemType Directory $File.DirectoryName.Replace($Source, $Target) -Force | Out-Null
Copy-Item $File.FullName $File.FullName.Replace($Source, $Target) -Force
}

Powershell Copy-Item Rename If File Exists

I am using this code I found on this site in a script to copy PST files and rename the duplicate. My question and the problem I am having with it is that when it renames the .pst it continues to increment the number.
For example, if it finds a file named "test.pst" it will copy it as is. If it finds another file also named "test.pst", it will copy it and rename it "test-1.pst" which is fine. However, if it finds two files named "test2.pst" it will copy the first one as "test2.pst" and copy and rename the second one to "test2-2.pst" instead of "test2-1.pst".
Do you have any suggestions on how I can modify my code so that it will start numbering each new duplicate file with 1 (test3-1.pst, test4-1.pst, etc)?
$csv = import-csv .\test.csv
foreach ($line in $csv) {
New-Item c:\new-pst\$($line.username) -type directory
$dest = "c:\new-pst\$($line.username)"
$i=1
Get-ChildItem -Path $line.path -Filter *.pst -Recurse | ForEach-Object {
$nextName = Join-Path -Path $dest -ChildPath $_.name
while(Test-Path -Path $nextName)
{
$nextName = Join-Path $dest ($_.BaseName + "_$i" + $_.Extension)
$i++
}
$_ | copy-Item -Destination $nextName -verbose
}
}
You'll need to reset the counter:
$csv = import-csv .\test.csv
foreach ($line in $csv) {
New-Item c:\new-pst\$($line.username) -type directory
$dest = "c:\new-pst\$($line.username)"
Get-ChildItem -Path $line.path -Filter *.pst -Recurse | ForEach-Object {
$i=1 # Note the position of the initializer
$nextName = Join-Path -Path $dest -ChildPath $_.name
while(Test-Path -Path $nextName)
{
$nextName = Join-Path $dest ($_.BaseName + "_$i" + $_.Extension)
$i++
}
$_ | copy-Item -Destination $nextName -verbose
}
}
Moving my comment to an answer. You need to move the $i = 1 line to inside your ForEach loop as such:
$csv = import-csv .\test.csv
foreach ($line in $csv) {
New-Item c:\new-pst\$($line.username) -type directory
$dest = "c:\new-pst\$($line.username)"
Get-ChildItem -Path $line.path -Filter *.pst -Recurse | ForEach-Object {
$i=1
$nextName = Join-Path -Path $dest -ChildPath $_.name
while(Test-Path -Path $nextName)
{
$nextName = Join-Path $dest ($_.BaseName + "_$i" + $_.Extension)
$i++
}
$_ | copy-Item -Destination $nextName -verbose
}
}