windowspowershellstreamwriter

"WriteLine" stop writing a file. (Windows PowerShell)


I am trying to create a script for the university, that sorts the number of processes in the system by their handles number and saves them in a file. So far so good, sounds easy. But when I thought I had it finished, I realized that "WriteLine" stops writing when a few processes are missing and leaves the output incomplete. I have already checked by debugging that the process list is OK, but I can't figure out what is causing the problem.

Here is the code and the output:

# Comprobación de la existencia del directorio C:\Temp
if (-not (Test-Path -Path "C:\Temp" -PathType Container)) {
    Write-Host "El directorio C:\Temp no existe. Abortando la ejecución del script."
    exit
}

# Solicitar el nombre del fichero de salida y cargarlo en la variable $Fichero
$Fichero = Read-Host "Introduzca el nombre del fichero de salida"

# Generación de una línea en blanco en la consola
Write-Host ""

# Guardar en el array $Procesos todos los procesos en ejecución ordenados por su número de handles
$Procesos = Get-Process | Sort-Object -Property HandleCount

# Creación del fichero informativo

    # Abrir o crear el archivo en C:\Temp\$Fichero.txt para escritura
    $handle = [System.IO.File]::Open("C:\Temp\$Fichero.txt", 'OpenOrCreate', 'ReadWrite')
    $writer = New-Object System.IO.StreamWriter($handle)

    ######## Procesos entre 0 y 100 ########
    # Escribir en el fichero el intervalo de procesos
    $writer.WriteLine("######## Procesos entre 0 y 100 ########")

    # Escribir en el fichero una cabecera apropiada para la tabla de procesos
    $writer.WriteLine("{0,-10} {1,-40} {2,20}", "Id", "Nombre", "Número de handles")
    $writer.WriteLine("{0,-10} {1,-40} {2,20}", "==" * 4, "==" * 10, "==" * 19)

    # Escribir en el fichero informativo los procesos cuyo Nº de handles se encuentre entre 0 y 100
    # Para ello, se utilizará un bucle foreach.
    foreach ($p in $Procesos) {
        if ($p.HandleCount -ge 0 -and $p.HandleCount -le 100) {
            $Linea = "{0,-10} {1,-40} {2,20}" -f $p.Id, $p.ProcessName, $p.HandleCount
            $writer.WriteLine($Linea)
        }
    }

    $writer.WriteLine("")

    ####### Procesos entre 101 y 1000 ########
    # Escribir en el fichero el intervalo de procesos
    $writer.WriteLine("####### Procesos entre 101 y 1000 ########")

    # Escribir en el fichero una cabecera apropiada para la tabla de procesos
    $writer.WriteLine("{0,-10} {1,-40} {2,20}", "Id", "Nombre", "Número de handles")
    $writer.WriteLine("{0,-10} {1,-40} {2,20}", "==" * 4, "==" * 10, "==" * 19)

    # Escribir en el fichero informativo los procesos cuyo Nº de handles se encuentre entre 101 y 1000
    foreach ($p in $Procesos) {
        if ($p.HandleCount -ge 101 -and $p.HandleCount -le 1000) {
            $Linea = "{0,-10} {1,-40} {2,20}" -f $p.Id, $p.ProcessName, $p.HandleCount
            $writer.WriteLine($Linea)
            Write-Host $Linea
         }
      }


####### Procesos de 1001 o mas ########
    # Escribir en el fichero el intervalo de procesos
    $writer.WriteLine("####### Procesos de 1001 o mas ########")

    # Escribir en el fichero una cabecera apropiada para la tabla de procesos
    $writer.WriteLine("{0,-10} {1,-40} {2,20}", "Id", "Nombre", "Número de handles")
    $writer.WriteLine("{0,-10} {1,-40} {2,20}", "==" * 4, "==" * 10, "==" * 19)

    # Escribir en el fichero informativo los procesos cuyo Nº de handles se encuentre de 1001 o mas
    foreach ($p in $Procesos) {
        if ($p.HandleCount -ge 1001) {
            $Linea = "{0,-10} {1,-40} {2,20}" -f $p.Id, $p.ProcessName, $p.HandleCount
            $writer.WriteLine($Linea)
            Write-Host $Linea
         }
      }
    Write-Host "Fin"
    $writer.WriteLine("Final")


    $handle.Close()

The output in the file:

And the real output I want:

Thanks for your help.

I have tried to do it through:

Add-Content $path "###################### Processes between 0 and 100 handles #####################"


# Write in the file an appropriate header for the process table.
 Add-Content $path ('{0,-25} {1,-25} {2,25}' -f "Id", "Name", "Number of handles")

 Add-Content $ruta ("=============================================================================")

# Write in the info file the processes whose number of handles is between 0 and 100.
# between 0 and 100. To do this, a foreach loop will be used.

# Inside the loop body, the information # corresponding to each process will be generated in the variable $Line.
# corresponding to each process. Extended string formatting will be used to # format each line appropriately.
# will be used to format each line appropriately.
foreach($linea in $Processes)
{
    if(($linea.handles -ge 0) -and ($linea.handles -le 100)){
        $id=$linea.Id
        $name=$linea.Name
        $nHandles=$$linea.Handles
        Add-Content $path ('{0,-25} {1,-25} {2,25}' -f $id,$name,$nHandles)
    }

And this works but i need to do it with the other form.


Solution

  • The issue with your code is that you're calling $handle.Close() closing the FileStream but without calling $writer.Dispose() first which will ensure the remaining buffer to be written to your file.

    StreamWriter buffers data until it reaches a limit and writes that buffered data as a whole (default buffer size is 1024 chars, see streamwriter.cs). This is not the case if for example we enable AutoFlush.

    It is also recommended to use .Dispose() instead as this method already calls .Close() internally. The following pattern would be the way you should do it implementing a try / catch / finally.

    try {
        $Procesos = Get-Process | Sort-Object -Property HandleCount
        $handle = [System.IO.File]::Open("$pwd\test.txt", 'OpenOrCreate', 'ReadWrite')
        $writer = New-Object System.IO.StreamWriter($handle)
        # do stuff here...
    }
    catch {
        # error handling here
        Write-Error -Exception $_
    }
    finally {
        # dispose stuff
        if($writer) {
            $writer.Dispose()
        }
    
        if($handle) {
            $handle.Dispose()
        }
    }