Search code examples
powershell

PowerShell StandardOutput Redirect Issue


I am trying to use ghostscript to get the number of pages in a PDF. I am getting this error:

Select-Object : Exception getting "StandardOutput": "StandardOut has not been redirected or the process hasn't started yet."
At C:\Temp\Gainesville\EHADocumentExtractor\EHA_Extractor_ghostscript.ps1:156 char:101
+ ... Window -PassThru | Select-Object -wait -ExpandProperty StandardOutput
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidResult: (System.Diagnostics.Process (gswin64c):PSObject) [Select-Object], GetValueInvocationException
    + FullyQualifiedErrorId : PropertyEvaluationExpand,Microsoft.PowerShell.Commands.SelectObjectCommand

Below is my script

$gsPath = "C:\Program Files\gs\gs9.53.3\bin\gswin64c.exe"
  $pdfPath = "C:\Temp\Test.pdf"
  $gsCommands = @"
-q -dNODISPLAY -c \"($pdfPath) (r) file runpdfbegin pdfpagecount = quit\"
"@
    #$pageCount = & $gsPath -c $gsCommand 2>&1
    $pageCount = Start-Process -FilePath $gsPath -ArgumentList $gsCommands -NoNewWindow -PassThru | Select-Object -wait -ExpandProperty StandardOutput
Write-Host $pageCount

I am not sure how to solve this issue. In a C# program, I can just change the RedirectStandardOutput of the Process object, but I am not sure how to solve this in PowerShell.


Solution

  • You are attempting to get number of pages from a remote PDF. You are using old suggestions (I hope not from a ChatBot).

    Artifex have had to change some command line abilities, to reduce exploitation by rogue PDF exploits. Thus you need to ensure that folder is in the permissions list. Also the normal requirement for filenames is case specific and postscript style. (/ or \\)

    Thus the shortest current program command line via Windows shell, will be similar to:-

    gs.lnk -q -Ic:\temp -dNODISPLAY -c "(c:/temp/test.pdf) (r) file runpdfbegin pdfpagecount = quit"
    or
    gs.lnk -q -Ic:\temp -dNODISPLAY -c "(c:\\temp\\test.pdf) (r) file runpdfbegin pdfpagecount = quit"
    

    Where gs.lnk is my route to GSWIN32C.exe. Thus a minimal expected result of

    1
    

    If running cmd from the PowerShell console it is exactly the same but prefix with shell> cmd /r.

    enter image description here

    To redirect output to a file rather than console we can use

    PS > cmd /r gs.lnk -q -Ic:\temp -dNODISPLAY -c "(c:/temp/test.pdf) (r) file runpdfbegin pdfpagecount = quit" 1>c:\temp\count.txt
    PS > cmd /r type c:\temp\count.txt
    1
    PS >
    

    Beware you will need extra PowerShell parameters in some versions to get a result that matches the one provided directly in native CMD as conout. I had to mess about with that redirection as it was corrupted to UTF16 in my version of PowerShell.

    However you mentioned using c# and thus the shortest program line should be

    int page_number = m_ghostscript.GetPageCount("my_document.pdf");
    

    As per the docs https://ghostscript.readthedocs.io/en/latest/LanguageBindingsCSharp.html#getpagecount