-1

Here is the code I am currently using:

# Don't include "\" at the end of $NewSource - it will stop the script from
# matching first-level subfolders
$ignore = "somename"
$files = gci $NewSource -recurse | Where {
    $_.Extension -match "zip||prd" -and $_.FullName -notlike $ignore
}
foreach ($file in $files) {
    $NewSource = $file.FullName
    # Join-Path is a standard Powershell cmdLet
    $destination = Join-Path (Split-Path -Parent $file.FullName) $file.BaseName
    Write-Host -Fore green $destination
    $destination = "-o" + $destination
    # Start-Process needs the path to the exe and then the arguments passed
    # separately. You can also add -wait to have the process complete before
    # moving to the next
    Start-Process -FilePath "C:\Program Files\7-Zip\7z.exe" -ArgumentList "x -y $NewSource $destination" -Wait
}

However, once it is finished I need to go back through the new directories and unzip my .prd files that are created only after unzipping the .zip archives. Need some help here as my tries aren't working and currently unzip and overwrite all the previously unzipped .prd and .zip files.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
RadFox
  • 419
  • 1
  • 4
  • 17

1 Answers1

1

I already told you that $_.Extension -match "zip||prd" matches all extensions, because of the empty string between the two | characters in the regular expression (all strings contain the empty string).

Also, the -notlike and -like operators behave exactly like the -ne and -eq operators when comparing a value with a pattern that doesn't have wildcards in it, so your second condition will match all files whose full name isn't exactly "somename".

Change this:

$ignore = "somename"
$files = gci $NewSource -recurse | Where {
    $_.Extension -match "zip||prd" -and $_.FullName -notlike $ignore
}

into this:

$ignore = "*somename*"
$files = gci $NewSource -recurse | Where {
    $_.Extension -match "zip|prd" -and $_.FullName -notlike $ignore
}

and the code should do what you expect.

As an alternative you could build a list of the paths you want to ignore

$ignore = 'C:\path\to\first.zip',
          'C:\other\path\to\second.zip',
          'C:\some\file.prd',
          ...

and use the -notin (PowerShell v3 or newer) or -notcontains operator to exclude those files:

$_.FullName -notin $ignore
$ignore -notcontains $_.FullName

As a side note, I'd use the call operator and splatting instead of Start-Process for invoking 7zip.exe:

$destination = Join-Path (Split-Path -Parent $file.FullName) $file.BaseName
$params      = 'x', '-y', $NewSource, "-o$destination"
& "${env:ProgramFiles}\7-Zip\7z.exe" @params

To also extract .prd files that were extracted from the zip archives add another step to your loop.

foreach ($file in $files) {
    ...
    & "${env:ProgramFiles}\7-Zip\7z.exe" @params
    Get-ChildItem $destination | Where-Object {
        $_.Extension -eq 'prd'
    } | ForEach-Object {
        # extract matching file here, procedure is the
        # same as with the files in the outer loop
    }
}

You may want to wrap the code for building the destination path and extracting the file in a function that reads paths from the pipeline and calls itself recursively if the destination path contains .prd files.

function Invoke-Unzip {
    [CmdletBinding()]
    Param(
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [ValidateScript({Test-Path -LiteralPath $_})]
        [string]$FullName
    )

    $newSource = $FullName
    ...
    & "${env:ProgramFiles}\7-Zip\7z.exe" @params
    Get-ChildItem $destination |
        Where-Object { $_.Extension -eq 'prd' } |
        Invoke-Unzip
}
Community
  • 1
  • 1
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328