Search code examples
powershellpowershell-2.0powershell-3.0powershell-4.0powershell-remoting

Local script output is saved on remote server if using invoke-command


Hello everyone and thank you for the help you are providing here,

I have the script bellow who is checking the list of process and memory then create a nice HTML file as a report, this script was working fine in my local machine, once i added a loop + Invoke-Command and a list_server.txt to get process info for each server in list, I found out that the html file is saved in C:/$server?documents for each server from the list. I want to save the HTML results in the local machine from which I run the script.

This is my script :

$serversname = Get-Content -Path Server_list.text

Foreach ($servername in $serversname)

{
    invoke-command -scriptblock {

$Header = @"

<style>
h1 {

        font-family: Arial, Helvetica, sans-serif;
        color: #e68a00;
        font-size: 28px;
        text-align:center;
        margin: 0 auto;

    }

    
    h2 {

        font-family: Arial, Helvetica, sans-serif;
        color: #000099;
        font-size: 16px;
        text-align:center;
        margin: 100 auto;

    }
table {
        width:50%;
        margin-left:auto; 
        margin-right:auto;
}

table {
        font-size: 12px;
        border: 0px; 
        font-family: Arial, Helvetica, sans-serif;
    } 
    
    td {
        padding: 4px;
        margin: 0px;
        border: 0;
    }
    
    th {
        background: #395870;
        background: linear-gradient(#49708f, #293f50);
        color: #fff;
        font-size: 11px;
        text-transform: uppercase;
        padding: 10px 15px;
        vertical-align: middle;
    }
    tbody tr:nth-child(even) {
        background: #f0f0f2;
    }
    p {

        font-family: Arial, Helvetica, sans-serif;
        color: #ff3300;
        font-size: 12px;
        text-align:center;
        margin: 0 auto;
    }
</style>
"@

$properties=@(
    @{Name="Process Name"; Expression = {$_.name}}, 
    @{Name="Memory (MB)"; Expression = {[Math]::Round(($_.WorkingSet / 1mb ),2)}}
)  

#Getting all process

$ComputerName = "<h1>Nom du serveur : $env:computername</h1>"
$ProcessInfo = Get-process  | Select-Object $properties | Sort-Object  -Property "Memory (MB)" -Descending |  ConvertTo-Html -Head $Header  -PreContent "<h2>Informations sur les processus</h2>"
$Report = ConvertTo-HTML -Body " $ComputerName $ProcessInfo" -Title "Informations sur les processus Genetec" -PostContent "<p>Date de creation : $(Get-Date)<p>"
$Report | Out-File .\log.html

#Getting only Firefox process

$ProcessInfo_firefox = Get-process firefox | Select-Object $properties | Sort-Object  -Property "Memory (MB)" -Descending |  ConvertTo-Html -Head $Header  -PreContent "<h2>Informations sur les processus Firefox</h2>"
$Report = ConvertTo-HTML -Body " $ComputerName $ProcessInfo_firefox" -Title "Informations sur les processus Firefox" -PostContent "<p>Date de creation : $(Get-Date)<p>"
$Report | Out-File .\log_firefox.html

#Getting only Firefox process with more than 200Mb memory 

$ProcessInfo_firefox_plus200 =  Get-Process firefox   | Select-Object @{Name="Process Name"; Expression = {$_.name}},@{Name="Memory (MB)"; Expression = {[Math]::Round(($_.WorkingSet / 1mb ),2)}} | where {$_.'Memory (MB)' -gt 300} | ConvertTo-Html -Head $Header  -PreContent "<h2>Informations sur les processus Firefox qui utilise plus que 200mb de RAM</h2>"
$Report = ConvertTo-HTML -Body " $ComputerName $ProcessInfo_firefox_plus200" -Title "Informations sur les processus Firefox qui utilise plus que 200mb de RAM" -PostContent "<p>Date de creation : $(Get-Date)<p>"
$Report | Out-File .\log_firefox_plus200.html


} -computername $servername

}

Also please I have a second question, As you can see my script is generating an HTML file for each server, Can I somehow put all process tables in one HTML file not separately, Thank you so much.


Solution

  • In my opinion, I would never build the HTML report on the remote servers. But following your example code and given your "question" (I want to save the HTML results in the local machine from which I run the script.). This is what I would do, I have also enhanced your code a bit.

    There is also no need to use foreach loops when invoking commands on remote servers unless there is a specific need for this. In your example, I don't see any particular or specific need to do each server at a time. Powershell allows you to invoke the same command on an array of servers, pretty similar as what it would do if all invocations would have been done using the -AsJob switch followed by a Wait-Job.

    $style = @"
    <style>
    h1 {
        font-family: Arial, Helvetica, sans-serif;
        color: #e68a00;
        font-size: 28px;
        text-align:center;
        margin: 0 auto;
    }
    
    h2 {
        font-family: Arial, Helvetica, sans-serif;
        color: #000099;
        font-size: 16px;
        text-align:center;
        margin: 100 auto;
    }
    
    table {
        width:50%;
        margin-left:auto; 
        margin-right:auto;
        font-size: 12px;
        border: 0px; 
        font-family: Arial, Helvetica, sans-serif;
    }
    
    td {
        padding: 4px;
        margin: 0px;
        border: 0;
    }
        
    th {
        background: #395870;
        background: linear-gradient(#49708f, #293f50);
        color: #fff;
        font-size: 11px;
        text-transform: uppercase;
        padding: 10px 15px;
        vertical-align: middle;
    }
    
    tbody tr:nth-child(even) {
            background: #f0f0f2;
    }
    
    p {
        font-family: Arial, Helvetica, sans-serif;
        color: #ff3300;
        font-size: 12px;
        text-align:center;
        margin: 0 auto;
    }
    </style>
    "@
    
    $servers = Get-Content -Path Server_list.text|?{$_}|%{$_.trim()}
    
    $session=@()
    
    $servers|%{
        if(Test-Connection $_ -Quiet -Count 1)
        {
            $session+=New-PSSession $_
        }
    }
    
    $sblock={
    
    $header=$using:style
    
    $properties=@(
        @{Name="Process Name"; Expression = {$_.name}}, 
        @{Name="Memory (MB)"; Expression = {[Math]::Round(($_.WorkingSet / 1mb ),2)}}
    )  
    
    #Getting all process
    
    $ComputerName = "<h1>Nom du serveur : $env:computername</h1>"
    $ProcessInfo = Get-process  | Select-Object $properties | Sort-Object  -Property "Memory (MB)" -Descending |  ConvertTo-Html -Head $Header  -PreContent "<h2>Informations sur les processus</h2>"
    $processReport = ConvertTo-HTML -Body " $ComputerName $ProcessInfo" -Title "Informations sur les processus Genetec" -PostContent "<p>Date de creation : $(Get-Date)<p>"
    
    #Getting only Firefox process
    
    $ProcessInfo_firefox = Get-process firefox | Select-Object $properties | Sort-Object  -Property "Memory (MB)" -Descending |  ConvertTo-Html -Head $Header  -PreContent "<h2>Informations sur les processus Firefox</h2>"
    $firefoxReport = ConvertTo-HTML -Body " $ComputerName $ProcessInfo_firefox" -Title "Informations sur les processus Firefox" -PostContent "<p>Date de creation : $(Get-Date)<p>"
    
    #Getting only Firefox process with more than 200Mb memory 
    
    $ProcessInfo_firefox_plus200 =  Get-Process firefox | Select-Object @{Name="Process Name"; Expression = {$_.name}},@{Name="Memory (MB)"; Expression = {[Math]::Round(($_.WorkingSet / 1mb ),2)}} | where {$_.'Memory (MB)' -gt 300} | ConvertTo-Html -Head $Header  -PreContent "<h2>Informations sur les processus Firefox qui utilise plus que 200mb de RAM</h2>"
    $firefoxPlus200Report = ConvertTo-HTML -Body " $ComputerName $ProcessInfo_firefox_plus200" -Title "Informations sur les processus Firefox qui utilise plus que 200mb de RAM" -PostContent "<p>Date de creation : $(Get-Date)<p>"
    
    [PSCustomObject]@{
        processReport = $processReport
        firefoxReport = $firefoxReport
        firefoxPlus200Report = $firefoxPlus200Report
    }
    
    }
    
    $results=invoke-command -Session $session -ScriptBlock $sblock
    
    Remove-PSSession $session
    
    #Here you have the report of your first server
    $results[0].processReport
    $results[0].firefoxReport
    $results[0].firefoxPlus200Report
    
    #The Results variable will contain the reports of all servers, you can use this variable to loop over each server