Search code examples
powershellinvoke-command

How to save a table to a log file without replacing the information


I am trying to get a shadow storage information from remote computers. I could get the information and store in a variable as table.

But every time the log file is being overwrite by the new information.

My script:

$computerList = Get-Content "C:\Check_ShadowStorage\ServersList.txt"
foreach($computer in $computerList)
{
    $a = Invoke-Command -ComputerName $computer -Credential $credential -ScriptBlock {@(vssadmin list shadowstorage | Select-String -Context 0,5 '^Shadow Copy Storage' | 
Select @{Label="Shadow Copy Storage"; Expression={$_.Line.Trim("'").SubString(12)}}, 
   @{Label="Volume"; Expression={$_.Context.PostContext[0].Trim().SubString(13,2)}},
   @{Label="Used Shadow Copy"; Expression={$_.Context.PostContext[2].Trim().SubString(32)}},
   @{Label="Allocated Shadow Copy"; Expression={$_.Context.PostContext[2].Trim().SubString(32)}},
   @{Label="Maximum Storage"; Expression={$_.Context.PostContext[4].Trim().SubString(35)}}) |
      Format-Table Volume, 'Used Shadow Copy', 'Allocated Shadow Copy', 'Maximum Storage'}

$a | Out-File "C:\Check_ShadowStorage\Output.log"
}

The output I am wishing to have is something like:

                       Server A
Volume Used Shadow Copy Allocated Shadow Copy Maximum Storage
------ ---------------- --------------------- ---------------
S:     0 bytes (0%)     0 bytes (0%)          89.3 GB (10%)  
D:     8.48 GB (0%)     8.48 GB (0%)          93.0 GB (10%)  
C:     4.97 GB (8%)     4.97 GB (8%)          5.83 GB (10%)  

                       Server B
Volume Used Shadow Copy Allocated Shadow Copy Maximum Storage
------ ---------------- --------------------- ---------------
S:     0 bytes (0%)     0 bytes (0%)          89.3 GB (10%)  
D:     8.48 GB (0%)     8.48 GB (0%)          93.0 GB (10%)  
C:     4.97 GB (8%)     4.97 GB (8%)          5.83 GB (10%) 

And so on.


Solution

  • The issue with your code is that you're overwriting your output file because:

    $a | Out-File "C:\Check_ShadowStorage\Output.log"
    

    Is inside the foreach instead of outside. To fix it, you could change the foreach for a ForEach-Object and use the pipeline:

    $computerList | ForEach-Object {
        # no assignment to `$a` needed here
        Invoke-Command -ComputerName $_ -Credential $credential -ScriptBlock {
            # same code here
        }
    } | Out-File 'C:\Check_ShadowStorage\Output.log'
    

    What you should do instead is not use Format-Table, output objects from your Invoke-Command and then pass them to Export-Csv to have structured output instead of plain text files.

    $computerList = Get-Content 'C:\Check_ShadowStorage\ServersList.txt'
    Invoke-Command $computerList {
        vssadmin list shadowstorage |
            Select-String -Context 0, 5 '^Shadow Copy Storage' |
            ForEach-Object {
                [pscustomobject]@{
                    'Volume'                = $_.Context.PostContext[0].Trim().SubString(13, 2)
                    'Used Shadow Copy'      = $_.Context.PostContext[2].Trim().SubString(32)
                    'Allocated Shadow Copy' = $_.Context.PostContext[2].Trim().SubString(32)
                    'Maximum Storage'       = $_.Context.PostContext[4].Trim().SubString(35)
                    'Shadow Copy Storage'   = $_.Line.Trim("'").SubString(12)
                }
            }
    } | Select-Object PSComputerName, * -ExcludeProperty RunspaceId |
        Export-Csv C:\Check_ShadowStorage\Output.csv -NoTypeInformation