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:
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.
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()
}
}