0

Some time ago, @Magoo was nice enough to help me in working out a FOR /F command to archive files into 7-zip:

Using FOR or FORFILES batch command to individually archive specific files

Since then I've expanded it somewhat and want to do more elaborate things with it. However, to keep this question simple, I've included the basics to try and get this working, which I haven't had much success at.

I'm rather new to PowerShell and I have some specific reasons to use this instead of batch files, moving forward. I understand that some more experienced users may note that I will have a reduction in performance by using such statements in PowerShell, but it isn't an important issue for me.

$env:Path += ";C:\Program Files\7-Zip"
$sourcedir = read-host "Enter the directory to archive: "
foreach ($aname in {
  'cmd /c dir /s/b /a-d "$sourcedir\*.iso" '
  'cmd /c dir /s/b /a-d "$sourcedir\*.daa" '
  'cmd /c dir /s/b /a-d "$sourcedir\*.nrg" '
  'cmd /c dir /s/b /a-d "$sourcedir\*.flp" '}
  ) {
     IF NOT EXIST $aname.7z (
       echo 7z a -t7z "$aname.7z" "$aname" -mx9 -mmt >> Z:\test\7z-log.txt
       ECHO "$aname" archived.
     ) ELSE (
       ECHO "$aname" archive file already exists.
        )
  }

I got into some trouble with the IF EXIST statement and even when I removed the IF and had a one-line ECHO just to simplify it even more, but I couldn't get it to output what I wanted.

So, I tried a different approach:

$env:Path += ";C:\Program Files\7-Zip"
$sourcedir = read-host "Enter the directory to archive: "
$dir_iso = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.iso" }
$dir_daa = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.daa" }
$dir_nrg = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.nrg" }
$dir_flp = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.flp" }
foreach ($aname in $dir_iso,$dir_daa,$dir_nrg,$dir_flp) {
       ECHO "$aname" archived.
       }

But what this did, is clumped each item of each type together, then appended "archived" to that set. Something like:

C:\folder1\iso1.iso C:\folder1\iso2.iso C:\folder1\iso3.iso archived.
C:\folder2\image.nrg archived.
C:\folder3\app1.flp C:\folder3\app2.flp archived.

instead of:

C:\folder1\iso1.iso archived.
C:\folder1\iso2.iso archived.
C:\folder1\iso3.iso archived.
C:\folder2\image.nrg archived.
C:\folder3\app1.flp archived.
C:\folder3\app2.flp archived.

I'm having a real hard time with getting this to work. Can anyone help?

Thanks.

3 Answers 3

0

Use write-host instead of echo. Multidimensional array, so you'll need an inner loop.

foreach ($aname in $dir_iso,$dir_daa,$dir_nrg,$dir_flp) {
  foreach ($bname in $aname) {
       write-host "$bname" archived.
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

Another possibility; this pipes the commands together rather than storing each in a separate variable.

Get-Item $sourcedir\* | 
Where {$_.Extension -like ".iso" -or $_.Extension -like ".daa" -or $_.Extension -like ".nrg" -or $_.Extension -like ".flp"} | 
Foreach-Object {
    if (-Not (Test-Path "$_.BaseName.7z")) 
    { 
        Write-Host $_.FullName not yet archived.
    }
    else
    {
        Write-Host $_.FullName already archived.
    }
}

1 Comment

If you were going to do that you could simply use match as well. $_.Extension -match "(iso|daa|nrg|flp)$". Filters might be better for performance depending on how big the file structure is.
0

The first thing I see here is you are using this to get file information from the filesystem

$dir_iso = ForEach-Object { cmd /c dir /s/b /a-d "$sourcedir\*.iso" }

More specifically cmd /c dir /s/b /a-d "$sourcedir\*.iso". This would translate easily to Get-ChildItem

$dir_iso = Get-ChildItem -Path $sourcedir -Filter "*.iso" -Recurse -File | Select-Object -ExpandProperty FullName
  • Path is the file path of the folder you are checking
  • Filter you want only files ending with .iso
  • Recurse all subdirectories are checked
  • File returns only files and not directories (PowerShell 3.0 or higher!. There is a simple equivalent if this is an issue. )
  • Select-Object -ExpandProperty FullName would just return the full path of the files found in an array.

IF EXIST could be replaced by Test-Path

If(Test-Path "$aname.7z"){
   Do stuff...
}

As for the ForEach loop foreach ($aname in $dir_iso,$dir_daa,$dir_nrg,$dir_flp) there are a couple good approaches with this but the simplest transistion would be

$dir_iso + $dir_daa + $dir_nrg + $dir_flp | ForEach-Object{
    Do Stuff
}

I would probably build the file collection in one variable to begin with to avoid the to concat the arrays together

$files = Get-ChildItem -Path $sourcedir -Recurse -File | Where-Object{$_.Extension -match "(iso|daa|nrg|flp)$" } | Select-Object -ExpandProperty FullName

$files | ForEach-Object{
    Write-Host "$_"
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.