0

So I've been writing a script that will take all of the data that is stored in 238 spreadsheets and copy it into a master sheet, as well as 9 high level report sheets. I'm really not sure why, but after a specific document, the script ends prematurely without any errors being posted. It's very strange. I'll post some anonymized code below so maybe someone can help me find the error of my ways here.

As far as I can tell, the document that it exits after is fine. I don't see any data errors in it, and the info is copied successfully to the master document before powershell just calls it quits on the script completely.

I've tried changing the size of the data set by limiting only to the folder that contains the problem file. It still ends after the same file with no error output. I cannot upload the file due to company policy, but I really don't see anything different about the data on that one file when compared to any other file of the same nature.

Also, apologies in advance for the crappy code. I'm not a developer and have been relearning powershell since it's the only tool available to me right now.

$StartTime = Get-Date -Format g
Write-Host $StartTime
pushd "Z:\Shared Documents\IO"
$TrackTemplate = "C:\Users\USERNAME\Desktop\IODATA\MasterTemplate.xlsx"

# Initialize the Master Spreadsheet
$xlMaster = New-Object -ComObject Excel.Application
$xlMaster.Visible = $False
$xlMaster.DisplayAlerts = $False
$MasterFilePath = "C:\Users\USERNAME\Desktop\IODATA\Master.xlsx"
Copy-Item $TrackTemplate $MasterFilePath
$wbMaster = $xlMaster.Workbooks.Open($MasterFilePath)
$wsMaster = $wbMaster.Worksheets.Item(2)
$wsMaster.Unprotect("PASSWORD")
$wsMasterRow = 3

# Initialize L4 Document Object
$xlL4 = New-Object -ComObject Excel.Application
$xlL4.Visible = $False
$xlL4.DisplayAlerts = $False

# Initialize object for input documents
$xlInput = New-Object -ComObject Excel.Application
$xlInput.Visible = $False
$xlInput.DisplayAlerts = $False

# Arrays used to create folder path names
$ArrayRoot = @("FOLDER1","FOLDER2","FOLDER3","FOLDER4","FOLDER5","FOLDER6","FOLDER7","FOLDER8","FOLDER9")
$ArrayShort = @("SUB1","SUB2","SUB3","SUB4","SUB5","SUB6","SUB7","SUB8","SUB9")
# $counter is used to iterate inside the loop over the short name array.
$counter = 0
$FileNumber = 0
$TotalFiles = 238
$ArrayRoot | ForEach-Object {
    $FilePathL4 = "C:\Users\USERNAME\Desktop\IODATA\ROLLUP\" + $ArrayShort[$counter] + "_DOC_ROLLUP.xlsx"
    Copy-Item $TrackTemplate $FilePathL4
    $wbL4 = $xlL4.Workbooks.Open($FilePathL4)
    $wsL4 = $wbL4.Worksheets.Item(2)
    $wsL4.Unprotect("PASSWORD")
    $wsL4Row = 3
    If ($ArrayShort[$counter] -eq "SUB7") {$FilePath = "Z:\Shared Documents\IO\" + $_ + "\" + $ArrayShort[$counter] + " - DOC v2\"}
    Else {$FilePath = "Z:\Shared Documents\IO\" + $_ + "\!" + $ArrayShort[$counter] + " - DOC v2\"}
    Get-ChildItem -Path $FilePath | ForEach-Object {
        If ($_.Name -eq "SPECIFIC_DOC.xlsx") {Continue}
        $FileNumber += 1
        Write-Host "$FileNumber / $TotalFiles $_"
        $wbInput = $xlInput.Workbooks.Open($_.FullName)
        $wsInput = $wbInput.Worksheets.Item(2)
        $wsInputLastRow = 0

        #Find the last row in the Input document
        For ($i = 3; $i -le 10000; $i++) {
            If ([string]::IsNullOrEmpty($wsInput.Cells.Item($i,1).Value2)) {
                $wsInputLastRow = $i - 1
                Break
            }
            Else { Continue }
        }

        [void]$wsInput.Range("A3:AC$wsInputLastRow").Copy()
        Start-Sleep -Seconds 1
        [void]$wsMaster.Range("A$wsMasterRow").PasteSpecial(-4163)
        Start-Sleep -Seconds 1
        $wsMasterRow += $wsInputLastRow - 2
        [void]$wsL4.Range("A$wsL4Row").PasteSpecial(-4163)
        Start-Sleep -Seconds 1
        $wsL4Row += $wsInputLastRow - 2

        $wbInput.Close()
        $wbMaster.Save()
    }
    $counter += 1
    $wsL4.Protect("PASSWORD")
    $wbL4.Save()
    $wbL4.Close()
}
$wsMaster.Protect("PASSWORD")
$wbMaster.Save()
$wbMaster.Close()
$xlMaster.Quit()

$EndTime = Get-Date -Format g
$TimeTotal = New-Timespan -Start $StartTime -End $EndTime
Write-Host $TimeTotal
mklement0
  • 382,024
  • 64
  • 607
  • 775
darkstarohio
  • 13
  • 1
  • 6
  • You can download `Notepad++`, and then go to `View > Show Symbol > Show All Characters`. Compare the document loaded okay and the one with the problem. I am guessing it might be the **End of Line (EOL)** conversion. If that is the case, go to `Edit > EOL Conversion` to revise the problem file and try again. – ian0411 Sep 03 '17 at 21:00
  • Unfortunately, I cannot download Notepad++ due to restrictions on our work PCs. Would an EOL issue be causing this? All of these documents were generated by the same process at the same time. I also tried rebuilding the problem document and rerunning the script, now it quits without error on a document that previously worked fine. – darkstarohio Sep 03 '17 at 21:11
  • 3
    I found the solution. The Continue command cannot be used inside of a ForEach-Object Loop. I replaced it with Return and it's working fine now. – darkstarohio Sep 03 '17 at 22:24
  • 1
    To be fair to others: you found your own answer, post it as an answer so that other can find the answer when they have a similar question. (I think it will earn you points as well.) – Variatus Sep 04 '17 at 03:47

1 Answers1

1

To continue pipeline processing with the next input object, use return - not continue - in the script block passed to the ForEach-Object cmdlet.

The following simple example skips the 1st object output by Get-ChildItem and passes the remaining ones through:

$i = 0; Get-ChildItem | ForEach-Object{ if ($i++ -eq 0) { return }; $_ }

There is currently (PSv5.1) no direct way to stop the processing of further input objects - for workarounds, see this answer of mine.


By contrast, as you've discovered, break and continue only work as expected in the script block of a for / foreach statement, not directly in the script block passed to the ForeEach-Object cmdlet:

For instance, the following produces no output (using break would have the same effect):

$i = 0; Get-ChildItem | ForEach-Object{ if ($i++ -eq 0) { continue }; $_ }

The reason is that continue and break look for an enclosing for / foreach statement to continue / break out of, and since there is none, the entire command is exited; in a script, the entire script is exited if there's no enclosing for / foreach / switch statement on the call stack.

mklement0
  • 382,024
  • 64
  • 607
  • 775