Import-Csv - Different Results Between a Scheduled Job vs Manual Invocation

I have a script that goes out and retrieves a CSV file and outputs a modified version of that dataset. The issue I am facing is since moving this script from a Windows Scheduled Task to PowerShell Universal, the script does not retrieve the entire contents of the CSV file. When it runs as part of the scheduled jobs in PowerShell Universal, it returns a varying list of incomplete data. There are normally over 1400 entries in the CSV file, however the script will return different amounts each time when run as part of the schedule. I even added a check and second Import-Csv command, but it still doesn’t return the entire CSV file. I’ve tried modifying the environment from Posh 5.1 to Pwsh 7.1.3, to no avail.

Automatic Job Results:
July 5 - 162 (2nd pass: 535)
June 28 - 331 (2nd pass: 765)
June 21 - 234 (2nd pass: 259)
June 14 - 61 (2nd pass: 92)

If I run it manually, I’m getting the entire CSV:
July 5 - 1479 (confirmed a new line was added)
June 28 - 1478
June 21 - 1478
June 14 - 1478

Is there any obvious explanation why the automated task would behave differently? I am using the same “Run As” account as the scheduled task when performing the manual invocation.

Product: PowerShell Universal
Version: 1.5.19

Now that’s a new one…

Can you share how you are importing the CSV data? Is it just with Import-CSV?

Yup, just using Import-Csv cmdlet. One detail is the target is in another AD forest that we have a one-way Forest trust. But I can run the same job over and over with the same service account using the Manual Invocation without issue. It’s only when the job runs as part of that schedule. The specific line is just:

$AllPrinters = Import-Csv $SrcFile.FullName -ErrorAction Stop | Sort-Object Name

And here’s pretty much the entire sanitized PS1:

# Convert Printer Report

# Static Email info:
$StaticSmtpParams = @{
    "SmtpServer" = "smtp.domain.com"
    "To" = "User@domain.com"
    "From" = "SvcAcct@domain.com"
}

# Specify lookback date
$DateThreshold = (Get-Date).AddHours(-6)
Write-Information "DateThreshold is [$DateThreshold]"
# Get latest CSV from $SrcPath
Try{
    Write-Information "Attempting to get CSV file from <share site>"
    $SrcPath = "\\Other-AD-Forest.com\share\PrinterReport"
    $SrcFiles = Get-ChildItem $SrcPath -Filter *.csv -File -ErrorAction Stop
    $SrcFile = $SrcFiles | Sort-Object LastWriteTime -Descending | Select-Object -First 1
    Write-Information "CSV file retrieved from <share site>"
} Catch {
    Write-Information "Failed to 'Get-ChildItem' on <share site> Share"
    Write-Information "$($Error[0])"
    $MailParams = @{
        "Subject" = "Warning: Unable to access <share site> Directory"
        "Body" = "Access denied to <share site> Printer Report file"
    }
    Send-MailMessage @StaticSmtpParams @MailParams
}

If($SrcFile.LastWriteTime -gt $DateThreshold){
    Write-Information "New file detected, attempting to process CSV file"
    # Creates array to store objects
    $Array = [System.Collections.Generic.List[PSObject]]::new()
    Try{
        # Import CSV and filter out known bad entries
        $AllPrinters = Import-Csv $SrcFile.FullName -ErrorAction Stop | Sort-Object Name
        Write-Information "Total printers in list is [$($AllPrinters.Count)]"
        If($AllPrinters.Count -lt '1000'){ # Added for testing auto/scheduled results as it is not returning full list
            $AllPrinters = Import-Csv $SrcFile.FullName -ErrorAction Stop | Sort-Object Name
            Write-Information "On second pass, total printers imported is [$($AllPrinters.Count)]"
            If($AllPrinters.Count -lt '1000'){
                $MailParams = @{
                    "Subject" = "<share site> Printer Script Count Low"
                    "Body" = "<share site> Printer Report file failed to import correctly"
                }
                Send-MailMessage @StaticSmtpParams @MailParams
            }
        }
        $FilteredPrinters = $AllPrinters.Where({$_.Name -notmatch "(^canon|^microsoft|^zdesigner)"})

        # Iterate over each entry and normalize data
        Foreach($Entry in $FilteredPrinters){
            # Update 'IP' to remove extraneous data
            switch -regex ($Entry.IP) {
                "_9100$" {
                    $IP = $Entry.IP -replace "_9100"
                }
                "^IP_" {
                    $IP = $Entry.IP -replace "^IP_"
                }
                Default {
                    $IP = $Entry.IP
                }
            }

            # Get the department prefix of printer (e.g. 'DEPT001PR' --> 'DEPT')
            $Prefix = $Entry.Name -replace " ?\d.*"
            # Build object and add to $Array
            $Obj = [PSCustomObject]@{
                'DeptPrefix' = $Prefix.ToUpper()
                'Hostname' = $Entry.Name -replace "\.domain\.com$"
                'IPAddress' = $IP
            }
            $Array.Add($Obj)
        }
    } Catch {
        Write-Information "Error importing CSV file"
        Write-Information "$($Error[0])"
    }

Can you do me a favor and try to add a whoami to the top of that script? I want to make sure that when it’s scheduled it’s actually running as the correct account.

Will do. Does that get redirected to the Information stream by default or will I need to do anything special beyond literally issuing the whoami command?

And the job only runs on Monday mornings. As there is a timing of when the printer file gets created, so I’ll follow up next week.

You should be able to just include whoami directly in the script and it’ll appear in the information stream and job log. And that timing sounds good. Thanks.

@adam, here is the output from this morning (same issue):

I ran it again just now manually and got expected result:

Any other debugging or things you can think of?

Do those users have the same permissions? It seems like it’s running as two different accounts.

What if you manually run as svc-printrpt?

@adam, I was inconsistent with blacking out the information, but it shows the same account. Here is the job outputs that hopefully better shows the whoami output is the same between the automated schedule and when I manually executed the script using the same Run As account.

Ah, ok. I gotcha. Man, that’s weird. The only other thing I can think of is this is a timing thing.

Have you tried scheduling this at different times with the same result?

@adam, so it turns out the vendor updated the report schedule on their side and didn’t tell anyone. Instead of executing at 7AM PST, it was executing at 8AM PST, the exact same time our Universal job was scheduled. Looks like their report file hadn’t finished by the time our script was calling the Import-Csv, and also why re-running the job only a couple minutes later worked. The vendor was/is supposed to communicate changes like this to us for this exact reason. So thanks for troubleshooting and fixing an issue that had nothing to do with the product.

Related, even though the job was scheduled, it showed the identity as me instead of “admin” like I normally see:

I edited the schedules.ps1 file directly, but is that expected? Or if I recycle the AppPool or restart the server should it revert and correctly assign the ID as “admin” on future runs?