PowerShell Script (foreach-loop problems) - powershell

I have a short question, but I am standing on the wall for too long now, so I have to ask you....
The situation is:
I have a special filetype, in different folders and subfolders.
I already managed to find the files, write them into a TXT-File and I also managed to split the path so I can name a ZIP-File with the Folder-Name and Date.
But the only thing I do not get is how to only zip the special file of folder1 in a Zip-archiv "folder1-date.zip" and the file of folder2 in a Zip-archiv "folder2-date.zip".
Code part looks like this:
[string[]]$dirs = (Split-Path (Split-Path -Path $output -Parent) -Leaf | Foreach-Object { $i++; $_ })
[string[]]$arrayFromFile = Get-content -Path 'C:\TEMP\output.txt'
foreach ($file in $arrayFromFile) {
foreach ($dir in $dirs){
#
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip }
}
The Problem is, that every file with the extension found is in every ZIP-Archiv (logic because it is a foreach in a foreach) but I can not find the right way to do it....
Thank you for the help!

This will get the desired outcome and not have to save output to a text file.
$origin = "C:\TEMP\"
$filetyp = ".stl, .vol, .pct, .tif"
$destination = "C:\Daten\zipstore\"
$date = $(Get-Date -Format d)
$fileNames = Get-ChildItem "$origin" -Recurse | Where {$_.extension -eq ".stl"} | ForEach-Object { $_.FullName }
foreach ($file in $fileNames) {
$dir = (Split-Path (Split-Path -Path $file -Parent) -Leaf)
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip
}

Thank you for the answer! Here you have the whole code:
# Variablen Definition:
#
$origin = "C:\TEMP\"
$filetyp = ".stl, .vol, .pct, .tif"
$destination = "C:\Daten\zipstore\"
$date = $(Get-Date -Format d)
#
#
# Auslesen aller Files die bestimmte Dateiendung haben:
#
Get-ChildItem "$origin" -Recurse | Where {$_.extension -eq ".stl"} | ForEach-Object { $_.FullName } > C:\TEMP\output.txt
#
#
# Remove filename, keep path to file / split and only keep last directory:
#
$output = Get-content C:\TEMP\output.txt
$i = 0
#
[string[]]$dirs = (Split-Path (Split-Path -Path $output -Parent) -Leaf | Foreach-Object { $i++; $_ })
#
#
# Create ZIP-Archiv:
#
[string[]]$arrayFromFile = Get-content -Path 'C:\TEMP\output.txt'
foreach ($file in $arrayFromFile) {
foreach ($dir in $dirs){
#
Compress-Archive -Path $file -CompressionLevel Optimal -Update -DestinationPath $destination\$dir-$date.zip }
}
#
#
# Delete files not needed anymore:
Remove-Item -Path $origin -Include *.txt -Recurse -Force
#
Maybe this helps!

Related

How I can do this powershell script better?

When I move FenrirFS profile to another, paths in directories become wrong.
So I decided to make a ps script to resolve it.
$wdir = "files" # constant part of path
$path = $PSScriptRoot # path to script
$pfix = "Target=" # prefix of path
$files = Get-ChildItem -Path $path -Filter *.alias | Where { ! $_.PSIsContainer } | Select -Expand Name
foreach ($file in $files)
{
$filec = Get-Content $file
$nlin = 0 # counter of line
foreach ($line in $filec)
{
if($line.Contains($pfix))
{
$nline = $pfix + $path + '\' + $wdir + ($line -split $wdir)[1]
$filec[$nlin] = $filec[$nlin].replace($line,$nline)
$filec | Set-Content $file
break
}
$nlin++
}
}
It's work, but I have a lot of files, which I should replace.
And $filec | Set-Content $file a little bit dumby, cuz I need to replace only one line.
Example of file:
Target=E:\home\prj\polygon\ps\files\NoDigital\godTech_2.JPG
DisplayName=godTech_2.JPG
WorkDir=
Arguments=
ShowCmd=0
ps script is located in the directory with aliases.
p.s. powershell 5.1
You could use the much faster switch for that:
$wdir = "files" # constant part of path
$path = $PSScriptRoot # path to script
$pfix = "Target=" # prefix of path
$files = Get-ChildItem -Path $path -Filter '*.alias' -File | ForEach-Object {
$content = switch -Regex -File $_.FullName {
"^$pfix" {
$oldPath = ($_ -split '=', 2)[-1].Trim()
$childPath = Join-Path -Path $wdir -ChildPath ($oldPath -split $wdir, 2)[-1]
# output the new path
"$pfix{0}" -f (Join-Path -Path $path -ChildPath $childPath)
}
default { $_ }
}
$content | Set-Content -Path $_.FullName -Force
}

Archive files from a folder which are older than one week to a sub folder using powershell

I have tried below powershell script to move files older than 7 days from Newfolder to Archive_folder. The script is moving the entire path to the Archive_folder (means its creating folders \Users\529817\New folder in to Archive_folder and then copying files and not zipping the folder) , I need help in copying only files from NewFolder to Archive_folder and zip that folder.
$ArchiveYear = "2018"
$ArchiveMonth = "10"
$ArchiveDay = "10"
$SourcePath = "C:\Users\529817\New folder"
$TargetPath = "C:\Users\529817\New folder\Archive_folder"
$YourDirToCompress = "C:\Users\529817\New folder"
$ZipFileResult = "C:\Users\529817\New folder\Archive_folder\$ArchiveDay$ArchiveMonth.zip"
Get-ChildItem $YourDirToCompress -Directory |
#where { $_.Name -notin $DirToExclude} |
Compress-Archive -DestinationPath $ZipFileResult -Update
$Days = "7"
$LogPath = "C:Users\529817\Temp"
$Date = Get-Date -format yyyy-MM-dd_HH-mm
$TargetFolder = "$TargetPath\$Date"
$LogFile = "$LogPath\ArchiveLog-$date.txt"
$TargetZipFile = "$TargetPath\$Date.zip"
$Activity = "Move files older than $Days days from $SourcePath to $TargetFolder"
Write-Verbose $Activity
$OldFiles = Get-Childitem -Path $SourcePath -recurse | Where-Object {$_.LastWriteTime -lt (get-date).AddDays( - $days)}
$Total = $Oldfiles.Count
$Current = 0
$OldFiles | ForEach {
$Current ++
$Filename = $_.fullname
Write-Progress -Activity $Activity -Status $FileName -PercentComplete ($Current / $Total * 100)
$Split = $FileName -split '\\'
$DestFile = $split[1..($split.Length - 1)] -join '\'
$DestFile = "$TargetFolder\$DestFile"
Try {
$null = New-Item -Path $DestFile -Type File -Force
$Null = Move-Item -Path $FileName -Destination $DestFile -Force -ErrorAction:SilentlyContinue
"Successfully moved $filename to $targetfolder" | add-content $LogFile
}
Catch {
$Err = $_.Exception.Message
Write-Error $Err
"Error moving $filename`: $Err " | add-content $LogFile
}
}
You have two problems here:
Your zip file isn't going where you want it to go
Instead, all of the items which should be in the zip are going where the zip should go.
Let's figure out why this is happening so you can do what you need to get it working.
Problem 1
You have line 10 which looks like this:
Compress-Archive -DestinationPath $ZipFileResult -Update
This creates the Zip file but you don't actually do anything with this file, as in we don't see this $ZipFileResult used again in the code. This is why your zip file isn't showing up where you want it to be.
Problem 2
The end of this script has this big block where you are expressly copying the files to the directory,right where you don't want them.
Try {
$null = New-Item -Path $DestFile -Type File -Force
$Null = Move-Item -Path $FileName -Destination $DestFile -Force -ErrorAction:SilentlyContinue
"Successfully moved $filename to $targetfolder" | add-content $LogFile
}
If you only want to move the Zip file, then you can shorten this whole script. Delete everything from line 19 and on down, which begins with this line.
$OldFiles = Get-Childitem -Path $SourcePath -recurse | Where-Object {$_.LastWriteTime -lt (get-date).AddDays( - $days)}
And instead, add a Move-Item command to copy that $ZipFileResult file over to whichever directory you want it to go.
Finally, there are a number of lines which don't do anythign and can be deleted, like this line $TargetZipFile = "$TargetPath\$Date.zip"

Why doesn't this create a file on the destination server?

I recently did a storage migration and we had about 700 files that failed to migrate out of around 7 million (we need to purge some files, I know). I wrote the script below that is supposed to look at the corresponding file on the destination, compare the date values and if the file doesn't exist or has an older date, it's supposed to copy it over. Unfortunately, it's not copying it over. I don't get any errors but the file doesn't land on the destination. What am I doing wrong?
Also, I originally tried to grab the entire directory but it choked on the volume of files so that's why it parses each directory in turn instead.
$toplvl = "D:\Users\"
$folders = Get-ChildItem -Path $toplvl -Directory
$file = ""
$folders | ForEach-Object {
$original = $_.FullName
$dest = $_.FullName.Replace("D:","\\NewFileServer\D$")
$OutputFile = $_.FullName.Replace($toplvl,"D:\filelist-")
$FirstFind=0 #used to create a header in the output file
# Get all files under $original, filter out directories
$filelist = Get-ChildItem -Recurse $original | Where-Object { -not $_.PsIsContainer }
Write-Host $original #write directories to host to track progress
$filelist | ForEach-Object {
## Check if the file (from $original) exists with the same path in $dest
If (Test-Path ($_.FullName.Replace($original,$dest) ) ) {
## the file from $original has a match in $dest
$file = Get-Childitem -Path $_.FullName.Replace($original,$dest)
If ($_.LastWriteTime -gt $file.LastWriteTime) {
## file from $original is newer than $dest
If ( -Not ($FirstFind)) {Add-Content -Path $OutputFile -Value "Original File, Date"}
$FirstFind = 1
Add-Content -Path $OutputFile -Value $_.FullName -NoNewline
Add-Content -Path $OutputFile -Value "," -NoNewline
Add-Content -Path $OutputFile -Value $_.LastWriteTime
Copy-Item -Path $_.FullName -Destination $file.FullName
}
else {
## file from $original is same or older than $dest; can remove else statement
}
}
else {
## the file from $original is missing from $dest
If ( -Not ($FirstFind)) {Add-Content -Path $OutputFile -Value "Original File, Date"}
$FirstFind = 1
Add-Content -Path $OutputFile -Value $_.FullName -NoNewline
Add-Content -Path $OutputFile -Value "," -NoNewline
Add-Content -Path $OutputFile -Value $_.LastWriteTime
Copy-Item -Path $_.FullName -Destination $_.FullName.Replace($original,$dest)
}
}
}
Hopefully I didn't mess this up copying it over - it's my first time posting and I'm still figuring out the formatting.

Moving Files to Folder Based on Filename

I have several thousand files in a single directory. Many of these files need to be grouped together in their own directory based off a part of the filename. I need a part of the filename to be the destination folder name. I put dashes around the part of the filename I need the directory to be named.
For instance, the following files are located in a single directory:
filea-123-.PDF
fileb-123-.PDF
filec-456-.PDF
filed-123-.PDF
file3-456-.PDF
I need all files with "-123-" to be moved to a folder called "123". Likewise, I need all files with "-456-" to be moved to a folder called "456" and so on.
Here is what I have so far:
$dir = "C:\convert"
$filelist = (Get-Item $dir).GetFiles()
foreach ($file in $filelist)
{
$newdir = $file.Name -match '-\d+-'
Move-Item $file -Destination "C:\convert\$matches[0]"
}
I've also tried this:
$dir = "C:\convert"
$filelist = (Get-Item $dir).GetFiles()
foreach ($file in $filelist)
{
$pieces = $file-split"-"
$start = $pieces.Count*-1
$folder = $pieces[$Start..-2]-join" "
$destination = "C:\convert\{0}" -f $folder
if (Test-Path $destination -PathType Container)
{
Move-Item -Path $filename -Destination $destination
}
}
Try this
$dir = "C:\convert"
$filelist = #(Get-ChildItem $dir)
ForEach ($file in $filelist){
# Gets the '123' part
$folder = $file.Name.Split("-")[1]
#Test if folder exists.
Set-Location ($dir+'\'+$folder)
#If no folder, create folder.
if(!$?){ mkdir ($dir+'\'+$folder) }
#Move item keeping same name.
Move-Item $file.FullName ($dir+'\'+$folder+'\'+$file.Name)
}
}
Use a capturing group in your regular expression for extracting the number from the filename:
Get-ChildItem $dir -File | Where-Object {
$_.Name -match '-(\d+)-.pdf$'
} | ForEach-Object {
Move-Item $_.FullName ('{0}\{1}' -f $dir, $matches[1])
}
or like this, since Move-Item can read directly from the pipeline:
Get-ChildItem $dir -File | Where-Object {
$_.Name -match '-(\d+)-.pdf$'
} | Move-Item -Destination {'{0}\{1}' -f $dir, $matches[1]}
I like Ansgars approach, If the sub folders still have to be created:
Get-ChildItem -Path $dir -Filter "*-*-.PDF" |
Where-Object Name -match '-(\d+)-.pdf$' |
ForEach-Object {
$DestDir = Join-Path $dir $matches[1]
If (!(Test-Path $DestDir)) {mkdir $DestDir|Out-Null}
$_|Move-Item -Destination $DestDir
}

Copy Wav files older than 3 months to archive, creating year\month paths

I was hoping someone can help me out with this script which is currently baffling me, I'm not very good at powershell ;)
What I'm trying to achieve is a script that will scan folders and subfolders of my source, looking for *.wav files older than 60 days and then move them to an archive destination, creating a folder structure of \year\month
This is what i've got
$SourceDir = "d:\test"
$DestinationDir = "e:\test"
$files = get-childitem $SourceDir *.wav
foreach ($file in $files)
{
$Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
where-object {$_.LastWriteTime -lt (get-date).AddDays(-61)} | move-item $file.fullname $Directory
}
The script runs without error but doesn't move files :/
--
Following on from Keiths comments below, my script looks as so:
$SourceDir = "d:\test\"
$DestinationDir = "e:\test\"
$date = (get-date).AddDays(-91)
$files = get-childitem -literalpath $SourceDir *.wav
foreach ($file in $files)
{
$Directory = $DestinationDir + "" + $file.CreationTime.Date.ToString('yyyy') + "\" + $file.CreationTime.Date.ToString('MM-MMM')
if (!(Test-Path $Directory))
{
New-Item $directory -type directory
}
if ($file.LastWriteTime -lt $date) {
Write-Host $file
move-item -LiteralPath $file.fullname -Destination $Directory
}
}
And is working perfectly! Thanks Keith
Where-Object is never at the beginning of a pipeline. It requires input to populate the $_ variable you usually use to compare against. Replace that line with:
if ($file.LastWriteTime -lt (get-date).AddMonths(-3)) {
move-item $file.fullname $Directory
}
Although I would compute the date outside the loop:
$date = (get-date).AddMonths(-3)
And use that inside the loop:
...
if ($file.LastWriteTime -lt $date) {
Move-Item -LiteralPath $file.fullname -Destination $Directory
}
...