简体   繁体   中英

Multiple ForEach with Arrays in Powershell

I am trying to generate two data files (first for each) and generate just one document to each file (second for each). I can generate the two data files just fine, however, it creates 2 documents and assigns it to each file. I just need it to assign one document to one file, then the other document to another file. I've struggled and haven't been able to come up with a solution (novice developer). What can I do to accomplish this?

$filepath="C:\files\pdf\"
$data_files = Get-ChildItem $filepath
$filesss=$data_files | Write-Output

$Data2= $filesss -split "`n"
$i2=0
$var=@()

$gravy= Get-Content "C:\files\temp.txt"
$ia=0
$data44=@()


foreach  ($item2 in $Data2)
         {

          $headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
          $headers.Add("Accept", 'application/pdf')

          $fileName="C:\files\pdf\$item2"
          $fileContent = get-content -Raw $fileName
          $fileContentBytes = [System.Text.Encoding]::Default.GetBytes($fileContent)
          $fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)



foreach($id in $gravy){

                        $data44= ConvertTo-Json @{
                             encrypted="false";
                             allowSaveBinaryData="true";
                             binaryData="$fileContentEncoded"
                             divider="Expense Report";
                             extension="pdf";
                             name="$fileContentEncoded";
                             relProjectId="31";
                            }

           $var2[$i2]="https://XXXXXXX.com/v4/documents/$id/?guid=$AUTHtemp&fbsite=https://API/"

           Invoke-RestMethod -headers $headers -ContentType 'application/json' -Method PUT -body $data44 -Uri $var2 

           $ia++
                       }
$i2++ }

Ok, I've moved some things outside of your loop, removed one loop entirely, and changed it to a For loop. Here's what was happening, and why I changed it.

Original (simplified):

ForEach($file in $files){
    <load file>
    ForEach($id in temp.txt){
        <Generate a document>
    }
}

So let's say you have FileA.pdf and FileB.pdf to process, and temp.txt has 2 lines 'ID1' and 'ID2'. Actual content is immaterial, number of lines matters more.

So the outer loop kicks off, and loads up the data for FileA.pdf.
Then the inner loop starts up, takes the data for FileA.pdf, and uses 'ID1' to make a file.
Finished with the first item in temp.txt, it moves to the next (it's a loop, that's what loops do). It takes the data for FileA.pdf, and uses 'ID2' to make a file.
The inner loop has finished everything in temp.txt, so we now return to the outer loop.
The outer loop now loads up the data for FileB.pdf.
Then the inner loop starts up again, takes the data for FileB.pdf, and uses 'ID1' to make a file.
The inner loop moves to the next item in temp.txt, uses the data from FileB.pdf, and uses 'ID2' to generate another file.
Inner loop is done, back to outer loop, it too is done, script complete.

The problem is that the inner loop processes everything in temp.txt for each iteration of the outer loop, so 2 pdfs x 2 ids in temp.txt = 4 files total.

Now, with a For loop we use a number, base it off how many items are in temp.txt, and use that number to iterate through both the list of documents, and the IDs. Here's what I wrote up:

#Define the path to PDF files
$filepath="C:\files\pdf"
#Get list of PDF files
$data_files = Get-ChildItem $filepath
#Import the gravy! MMmm... gravy
$gravy= Get-Content "C:\files\temp.txt"

#Setup variables that won't change per file
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("Accept", 'application/pdf')
$data44=@{}

#Loop through items in the gravy file, and load 1 pdf per item
for ($i = 0; $i -lt $gravy.count; $i++)
{
    #Get raw string data from PDF file
    $fileContent = get-content -Raw $data_files[$i].FullName
    #Convert the raw data to bytes
    $fileContentBytes = [System.Text.Encoding]::Default.GetBytes($fileContent)
    #Encode the bytes as a Base64String for uploading
    $fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)

    #Get the id to use for this file
    $id = $gravy[$i]

    #Prep body to POST ...seriously though, you set the name to be the Base64 encoded string? Do you use binary in casual conversation as well?
    $data44= ConvertTo-Json @{
        encrypted="false";
        allowSaveBinaryData="true";
        binaryData="$fileContentEncoded"
        divider="Expense Report";
        extension="pdf";
        name="$fileContentEncoded";
        relProjectId="31";
    }

    #Define the URI to POST to
    $var2="https://XXXXXXX.com/v4/documents/$id/?guid=$AUTHtemp&fbsite=https://API/"

    #Post the data to the REST API
    Invoke-RestMethod -headers $headers -ContentType 'application/json' -Method PUT -body $data44 -Uri $var2 

}

I added some comments to try and help make sense of things. Let me know if that works for you, or if you have any specific questions about how it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM