locked
I have to publish powershell script output on MVC view RRS feed

  • Question

  • User1875266088 posted

    I wrote a script which gives us server inventory in HTML using powershell but as per new requirement I have to put the html output using MVC on web page

    ref for script: it looks https://gallery.technet.microsoft.com/scriptcenter/Get-server-inventory-report-be505436 

    In controller I try to call script using (https://stackoverflow.com/questions/34313963/execute-powershell-script-from-c-sharp-mvc-web-application) but no success on view how to publish columns as per script output

    The controller code looks like :-

    PowerShell powershell = PowerShell.Create();
                        RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
                        Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration)
                        using (Runspace runspace = RunspaceFactory.CreateRunspace())
                        {
                            runspace.Open();
                            RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
                            scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
                            powershell.Runspace = runspace;
                           powershell.Commands.AddScript("Add-PsSnapin Microsoft.SharePoint.PowerShell");
                            System.IO.StreamReader sr = new System.IO.StreamReader(scriptfilepath);
                            powershell.AddScript(sr.ReadToEnd());
                            //powershell.AddCommand("Out-String");
                            var results = powershell.Invoke();
                            if (powershell.Streams.Error.Count > 0)
                            {
                                // error records were written to the error stream.
                                // do something with the items found.
                            }
                        }

    in scriptfilepath I have called script as  (.\Get-Server_Inventory.ps1 -ComputerName servername -Credential $Credential -Nomail)

     The script looks as below :-

    <# 
    browse report on browser 
     
    for local 
    .\Get-Server_Inventory.ps1 -ComputerName localhost -Nomail 
     
     
    for other server than local add $credetial and replace code (-ComputerName $computername) with (-ComputerName $computername -Credential $Credential)  
    .\Get-Server_Inventory.ps1 -ComputerName servername -Credential $Credential -Nomail 
     
     
    send report on email (comment out and fillup your details in email section) 
    .\Get-Server_Inventory.ps1 -ComputerName localhost  
     
    #> 
     
    [CmdletBinding()] 
     
        Param( 
        [string[]]$ComputerName=$env:COMPUTERNAME, 
        [System.Management.Automation.PSCredential]$Credential, 
        [switch]$Nomail, 
        $Outfile ="$env:temp\out.html", 
        $EmailTo="$env:USERNAME@yourcompany.com" 
     
        ) 
       
     
    function Get-Information { 
     
    param($computername) 
     
    $osx = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername 
    $csx =Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computername 
    $bios =Get-WmiObject -Class Win32_BIOS -ComputerName $computername 
    $disk=Get-WmiObject -Class Win32_DiskDrive -ComputerName $computername 
     
    $properties = [ordered]@{ 
    ‘RegisteredUser’=$osx.RegisteredUser 
    'SystemDirectory'=$osx.SystemDirectory 
    'SerialNumber'=$osx.SerialNumber 
    ‘OS Version’=$osx.version 
    ‘OS Build’=$osx.buildnumber 
    ‘RAM’=$csx.totalphysicalmemory 
    ‘Processors’=$csx.numberofprocessors 
    ‘BIOS Serial’=$bios.serialnumber  
    'Partitions'=$disk.Partitions 
    'DeviceID'=$disk.DeviceID 
    'Model'=$disk.Model 
    'Size'=$disk.Size 
    'Caption'=$disk.Caption 
    } 
     
    $singleserver = New-Object -TypeName PSObject -Property $properties 
    echo $singleserver 
     
    } 
     
     
    $maintable = Get-Information –ComputerName $ComputerName | ConvertTo-Html -As LIST -Fragment -PreContent "<h2>$($ComputerName) Info</h2>"| Out-String 
     
    $subtable = Get-WmiObject -Class Win32_LogicalDisk -Filter ‘DriveType=3’ -ComputerName $ComputerName | Select DeviceID,  
    @{l="Freespace in MB";e={[math]::round($_.FreeSpace/1024/1024, 0)} }, 
    @{l="Size in MB";e={[math]::round($_.FreeSpace/1024/1024, 0)} } | ConvertTo-Html -Fragment -PreContent ‘<h2>Disk Info</h2>’ | Out-String 
     
    $head=@' 
    <!--mce:0--> 
    '@ 
     
    $report=ConvertTo-HTML -head $head -PostContent $maintable,$subtable -PreContent “<h1>Inventory on $($ComputerName)</h1>” 
     
     
        if ($nomail) 
        { 
            [System.IO.File]::Delete($Outfile) 
            $report| Out-File -FilePath $Outfile 
            Invoke-Expression -Command $Outfile 
        } 
        else 
        { 
        <# 
            $From = "d87c09e4a2-90269b@inbox.mailtrap.io" 
            $To = $EmailTo 
            $CC="abc@gmail.com" 
            $Subject = "Photos of Drogon" 
            $Body = "<h2>Guys, look at these pics of Drogon!</h2><br><br>" 
            $Body += “He is so cute!”  
            $SMTPServer = "smtp.mailtrap.io" 
            $SMTPPort = "587" 
            $Attachment=$Outfile 
            Send-MailMessage -From $From -to $To -Cc $Cc -Subject $Subject -Body $Body -BodyAsHtml -SmtpServer $SMTPServer -Port $SMTPPort -UseSsl  -Attachments $Attachment -Credential (Get-Credential) 
        #> 
        }
     
    Thursday, March 26, 2020 7:40 PM

Answers

  • User409696431 posted

    Are you saying that

    var results = powershell.Invoke();

    returns HTML in the variable 'results', and you simply want to display that HTML in the View?

    You can certainly add a variable to a model that you are using (but you haven't shown us anything about your View or Model, so I can't be more specific.)

    You could also pass a string to the View using ViewBag - not the best option if you already have a model you can add it to, but you can use it, and you can certainly use it to demonstrate proof of concept.

    If you simply want to pass one string of HTML and display it somewhere in the View,

    ...
    string ResultsHTML = ""; //Create a variable available outside your using section, default to empty
    using (Runspace runspace = RunspaceFactory.CreateRunspace())
    {
       ...
      var results = powershell.Invoke();
      if (powershell.Streams.Error.Count > 0)
      {
         ResultHTML=results;  //If no errors, put the results into the variable
      }
    }
    ViewBag.Results=ResultsHTML;  //Pass the results to the page
    ...
    
    
    


    And in the View, where you want to display the HTML:

    @Html.Raw(ViewBag.Results)



    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 29, 2020 12:30 AM

All replies

  • User753101303 posted

    Hi,

    Assuming the current problem is doing something with "results" see https://social.msdn.microsoft.com/Forums/vstudio/en-US/18287936-2d8c-4ba8-a3f5-46caf7b4c62c/c-with-powershell-and-pscustomobject?forum=csharpgeneral

    Invoke returns a collection of objects (PowerShell is entirely object based) and the output you see in PS is just those objects being displayed.

    Not directly related but as it seems you are using mainly WMI you could also try https://docs.microsoft.com/en-us/windows/win32/wmisdk/connecting-to-wmi-remotely-with-c- to use WMI directly from C# without going through PowerShell.

    Thursday, March 26, 2020 8:12 PM
  • User1875266088 posted

    I have tried, unfortunately I am unable to post code here but my custom cmdlet gives output in html file this cmdlet is not at all fired with variables passing in it from controller 

    Do I create any model for that, do you have any example MVC or video which create MVC app and publish result in view of powershell some complex cmdlet better than above 

    Friday, March 27, 2020 4:42 PM
  • User409696431 posted

    Are you saying that

    var results = powershell.Invoke();

    returns HTML in the variable 'results', and you simply want to display that HTML in the View?

    You can certainly add a variable to a model that you are using (but you haven't shown us anything about your View or Model, so I can't be more specific.)

    You could also pass a string to the View using ViewBag - not the best option if you already have a model you can add it to, but you can use it, and you can certainly use it to demonstrate proof of concept.

    If you simply want to pass one string of HTML and display it somewhere in the View,

    ...
    string ResultsHTML = ""; //Create a variable available outside your using section, default to empty
    using (Runspace runspace = RunspaceFactory.CreateRunspace())
    {
       ...
      var results = powershell.Invoke();
      if (powershell.Streams.Error.Count > 0)
      {
         ResultHTML=results;  //If no errors, put the results into the variable
      }
    }
    ViewBag.Results=ResultsHTML;  //Pass the results to the page
    ...
    
    
    


    And in the View, where you want to display the HTML:

    @Html.Raw(ViewBag.Results)



    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, March 29, 2020 12:30 AM
  • User1875266088 posted

    @Kathy- adding in view and controller receptively, there is no error but code is not shown any output on view 

    my script is scr.ps1 contains code Get-Process or Get-Process|where{$_.CPU -le 0.08} both give output on my shell but not on view html

    @Html.Raw(ViewBag.Results)
    string ResultHTML = string.Empty;
    PowerShell powershell = PowerShell.Create();
    RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
    Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
    using (runspace = RunspaceFactory.CreateRunspace())
    {
    runspace.Open();
    
    RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
    scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
    
    powershell.Runspace = runspace;
    powershell.Commands.AddScript("Add-PsSnapin Microsoft.SharePoint.PowerShell");
    
    StreamReader sr = new System.IO.StreamReader("E:\\Himanshu\\repos\\TestApp\\Scripts\\scr.ps1");
    powershell.AddScript(sr.ReadToEnd());
    powershell.AddCommand("Out-String");
    
    var results = powershell.Invoke();
    
    if (powershell.Streams.Error.Count > 0)
    {
    ViewBag.Result = ResultHTML;
    
    }
    }
    
    return View();

    Tuesday, April 21, 2020 2:13 PM
  • User409696431 posted

    In my example, I assigned the results of your powereshell to the string variable ResultHTML, and passed that to the page using ViewBag.

    string ResultsHTML = ""; //Create a variable available outside your using section, default to empty
    using (Runspace runspace = RunspaceFactory.CreateRunspace())
    {
       ...
      var results = powershell.Invoke();
      if (powershell.Streams.Error.Count > 0)
      {
         ResultHTML=results;  //If no errors, put the results into the variable
      }
    }
    ViewBag.Results=ResultsHTML; 

    In your code, you use ResultsHTML, but don't assign any value to it.  It will remain string.Empty and display nothing on the page.

    string ResultHTML = string.Empty;
    ...
    var results = powershell.Invoke();
    
    if (powershell.Streams.Error.Count > 0)
    {
    ViewBag.Result = ResultHTML;
    
    }

    Tuesday, April 21, 2020 2:24 PM
  • User1875266088 posted

    @kathy-- I have post wrong code by mistake, I have tried this one too but output is coming in ViewBag.Result but not transfer on view do I need to add anything in view other than @Html.Raw(ViewBag.Results) this, I have tried these two controllers and both give output at controller (first one weird output and another one is not gives output on view at all) also no error shown 

            public ActionResult Token()
            {
    
                // Clean the Result TextBox
                string ResultHTML = "";
    
                // Initialize PowerShell engine
                var shell = PowerShell.Create();
    
    
                // Add the script to the PowerShell object
                shell.Commands.AddScript("E:\\Himanshu\\repos\\TestApp\\Scripts\\scr.ps1");
    
                // Execute the script
                var results = shell.Invoke();
    
                // display results, with BaseObject converted to string
                // Note : use |out-string for console-like output
                if (results.Count > 0)
                {
                    // We use a string builder ton create our result text
                    var builder = new StringBuilder();
                    foreach (var psObject in results)
                    {
                        // Convert the Base Object to a string and append it to the string builder.
                        // Add \r\n for line breaks
                        builder.Append(psObject.BaseObject.ToString() + "\r\n");
                    }
    
                    // Encode the string in HTML (prevent security issue with 'dangerous' caracters like < >
                    ResultHTML = Server.HtmlEncode(builder.ToString());
                }
    
                ViewBag.Results = ResultHTML;
                return View();
            }
            public ActionResult Token()
            {
                ViewBag.Title = "Token";
                    string ResultHTML = string.Empty;
                PowerShell powershell = PowerShell.Create();
                RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
                Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
                using (runspace = RunspaceFactory.CreateRunspace())
                {
                    runspace.Open();
                    RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
                    scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted");
                    powershell.Runspace = runspace;
                    powershell.Commands.AddScript("Add-PsSnapin Microsoft.SharePoint.PowerShell");
                    StreamReader sr = new System.IO.StreamReader("E:\\Himanshu\\repos\\TestApp\\Scripts\\scr.ps1");
                    powershell.AddScript(sr.ReadToEnd());
                    powershell.AddCommand("Out-String");
                    var results = powershell.Invoke();
                    if (powershell.Streams.Error.Count > 0)
                    {
                        ViewBag.Result = results;
                    }
                    return View();
                }
    
            }




    Tuesday, April 21, 2020 4:55 PM
  • User409696431 posted

    Well, did you use ViewBag.Result or ViewBag.Results?  They are different.  Whichever one you defined in your .cs file needs to be the name used in your view.

    Tuesday, April 21, 2020 5:12 PM
  • User1875266088 posted

    I am using ViewBag.Results, it gives on output on view as data type "System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]" 

    Tuesday, April 21, 2020 5:25 PM
  • User409696431 posted

    So the code you just posted for the second case was wrong?  It shows ViewBag.Result in the .cs file, not ViewBag.Results.

    And if your powershell results is an HTML string, you don't need to further process it, as you are trying to do in the first case.  Is it an HTML string or not?

    Use the debugger and walk through the code and see what your Invoke result is, and what value you are putting in ResultHTML.

    Tuesday, April 21, 2020 5:48 PM
  • User1875266088 posted

    Finally this works 

    PowerShell shell = PowerShell.Create();
                shell.Commands.AddScript("E:\\Himanshu\\repos\\TestApp\\ScriptInt\\out\\scr.ps1 -ComputerName localhost -Nomail");
                var results = shell.Invoke();
                if (results.Count > 0)
                {
                    var builder = new StringBuilder();
                    foreach (var psObject in results)
                    {
                        builder.Append(psObject.BaseObject.ToString() + "\r\n");
                    }
                    ViewBag.Results = Server.HtmlEncode(builder.ToString());//output continuously
                }
                return View();

    Wednesday, April 22, 2020 8:09 AM
  • User1875266088 posted

    I have added small piece of code on GitHub, I am thankful to your prompt help 

    Wednesday, April 22, 2020 7:32 PM