Unacress
Unacress

Reputation: 17

Collect all XML files and move each to different folder in loop using index

I have a folder with naming convention of todays date YYYYMMDD. The folder contains multiple XML files as well as PDF files.

I want to read the folder content to find out how many XML files are in it. Once I know how many XML files I have, I need to create as many new folders as I have XML files and place them into the same source directory with naming convention YYYYMMDD_ExceptionN.

The I take all PDF files and copy them into each YYYYMMDD_ExceptionN folder (the pdf files are doubliceted which is okay).

Next, I need to copy the: first XML file from the source folder into the new target folder YYYYMMDD_Exception1 second XML file from the source folder into the new target folder YYYYMMDD_Exception2 third XML file from the source folder into the new target folder YYYYMMDD_Exception3....

until I have copied all XML files.

Source folder name: YYYYMMDD Source folder content:

I have managed so far to create all the YYYYMMDD_ExceptionN folders and copy all PDF files into each of the folders. However, I cannot get the XML file 1 to folder 1, XML file 2 to folder 2 etc.

Where am I going wrong? The XML files are not copied.

$Source="C:\temp\"
$TodaysDate = (Get-Date).AddDays(-0).ToString('yyyyMMdd')
$TodaysFilePath = Join-Path $Source $TodaysDate 

# Count total numbers of XML files
$TotalXMLfiles = Get-ChildItem -Path $TodaysFilePath -recurse -filter *.xml |Where-Object {$_.LastWriteTime} | Measure-Object | ForEach-Object{$_.Count}
$TotalXMLfiles
$XMLfiles = Get-ChildItem -Path $TodaysFilePath -recurse -filter *.xml
$XMLfiles


# Multiple XML files exist in folder
 For ($i = 1; $i -le $TotalXMLfiles; ++$i) {

    $ExceptionFilePath = $TodaysFilePath + "_Exception" + $i
    $ExceptionFilePath

    Get-Item –Path $TodaysFilePath | Copy-Item -Destination $ExceptionFilePath -Filter *.pdf -Recurse
    Get-Item –Path $TodaysFilePath -Filter *.xml | Select-Object -Index $i | Copy-Item -Destination $ExceptionFilePath -Recurse -Force
}

Expected outcome: Destination folder 1 name: YYYYMMDD_Exception1 Destination folder 1 content:

Destination folder 2 name: YYYYMMDD_Exception2 Destination folder 2 content:

Destination folder 3 name: YYYYMMDD_Exception3 Destination folder 3 content:

Destination folder 4 name: YYYYMMDD_Exception4 Destination folder 4 content:

Upvotes: 0

Views: 31

Answers (2)

sirtao
sirtao

Reputation: 2720

So, COMPLETE REWRITE because of the comment.

[CmdletBinding(SupportsShouldProcess)]
param (
    [parameter(ValueFromPipelineByPropertyName)]
    [ValidateNotNullOrWhiteSpace()]
    #+! WARNING: here some hard-coding for easier testing.
    #+! WARNING: remember to remove it in production
    [string]$SourceDirectory = 'c:\temp',
    [parameter(ValueFromPipelineByPropertyName)]
    [switch]$Force
)
    
process {
    $Source = $SourceDirectory
    Write-Verbose "Source : $Source"

    $TodayDate = (Get-Date -Verbose).ToString('yyyyMMdd')
    Write-Verbose "TodayDate: $TodayDate"

    if ($Force) {
        Write-Verbose 'Force'
        $TodayDirectory = New-Item -ItemType Directory -Path $Source -Name $TodayDate -Force -Verbose
    }
    else {
        Write-Verbose 'Not Force'
        $TodayDirectory = Join-Path -Path $Source -ChildPath $TodayDate -Verbose
        
        if ( -not ( Test-Path -PathType Container -Path $TodayDirectory -Verbose )) {
            $TodayDirectory = New-Item -ItemType Directory -Path $Source -Name $TodayDate -Verbose
        }
    }
    Write-Verbose "TodayDirectory: $TodayDirectory"

    # Get all the XML files in the directory
    $XmlFileList = Get-ChildItem -Path $TodayDirectory -File -Filter '*.xml'

    $Enumerator = 0

    # internal .foreach is much more efficient than | Foreach-Object, unless you want\need to use it in parallel
    $XmlFileList.foreach({

            # apparently 'continue' does not work in method Foreachs
            # so have a variable
            $KeepGoing = $true


            $NewDirName = '{0}_Exception{1}' -f $_.BaseName, ++$Enumerator
            Write-Verbose "NewDirName: $NewDirName"

            if ($Force) {
                $NewDir = New-Item -ItemType Directory -Path $TodayDirectory -Name $NewDirName -Force -Verbose
            }
            else {
                $NewDir = Join-Path -Path $TodayDirectory -ChildPath $NewDirName -Verbose
                
                # if the directory already exists, skips to next iteration
                if (Test-Path -PathType Container -Path $NewDir -Verbose) {
                    Write-Host 'Directory already existing, moving to next one'
                    $KeepGoing = $false
                }
                else {
                    # create the new directory and save its value for later use
                    $NewDir = New-Item -ItemType Directory -Path $TodayDirectory -Name $NewDirName -Verbose
                }
            }

            if ($KeepGoing) {
                # copy the XML file to the new directory
                Copy-Item -Path $_.FullName -Destination $NewDir

                # copy all the PDF files from the $TodayDirectory directory to the new directory
                # Join-Path is necessary because the -Filter parameter here is a bit buggy
                Copy-Item -Path (Join-Path -Path $TodayDirectory -ChildPath '*.pdf') -Destination $NewDir 
            }
        })
}

OLD ANSWER:

You are overthinking. You don't actually need to specific number of files, you can get it dynamically.
Have some commented code.

$Source = 'C:\temp\'
$TodaysDate = (Get-Date).ToString('yyyyMMdd')
$TodaysFilePath = Join-Path -Path $Source -ChildPath $TodaysDate


# Get all the XML files in the directory
$XmlFileList = Get-ChildItem -Path "$TodaysFilePath" -File -Filter '*.xml'

 # internal .foreach is much more efficient than | Foreach-Object, unless you want\need to use it in parallel
$XmlFileList.foreach({
        # Get the new name and increase the Numerator
        $NewName = '{0}_{1}' -f $_.BaseName , ++$Enumerator

        # create the new directory and save its value for later use
        $NewDir = New-Item -ItemType Directory -Path $_.DirectoryName -Name $NewName 

        # copy the XML file to the new directory
        Copy-Item -Path $_.FullName -Destination $NewDir 

        # copy all the PDF files from the $TodaysFilePath directory to the new directory
        # Join-Path is necessary because the -Filter parameter here is a bit buggy
        Copy-Item -Path (Join-Path -Path $TodaysFilePath -ChildPath '*.pdf') -Destination $NewDir
    })

Upvotes: 0

Jana
Jana

Reputation: 109

This should do it.

$Source="C:\temp\"
$TodaysDate = (Get-Date).AddDays(-0).ToString('yyyyMMdd')
$TodaysFilePath = Join-Path $Source $TodaysDate 

# Count total numbers of XML files
$TotalXMLfiles = Get-ChildItem -Path $TodaysFilePath -recurse -filter *.xml |Where-Object {$_.LastWriteTime} | Measure-Object | ForEach-Object{$_.Count}


# Multiple XML files exist in folder
 For ($i = 1; $i -le $TotalXMLfiles; ++$i) {

    $ExceptionFilePath = $TodaysFilePath + "_Exception_" + $i
    Get-Item –Path $TodaysFilePath | Copy-Item -Destination $ExceptionFilePath -Filter *.pdf -Recurse -Force
    

#   The Select-Object command uses the Index parameter to select events from the array of events in the $A variable. 
#   The index of the first event is 0. The index of the last event is the number of items in $A minus 1.
    $XMLindex=$i-1
    
    # Get all the XML files in the directory
    $XmlFileList = Get-ChildItem -Path "$TodaysFilePath" -File -Filter '*.xml'
#   Only move the one XML file we need for the Exception folder we are currently creating in this loop
    Get-Item –Path $XmlFileList.FullName | Select-Object -Index $XMLindex| Copy-Item -Destination $ExceptionFilePath -Recurse
   
}

Upvotes: 1

Related Questions