Problem getting error displayed to HTML Output

This topic contains 7 replies, has 2 voices, and was last updated by Profile photo of Ed O'Connor Ed O’Connor 5 months, 4 weeks ago.

  • Author
    Posts
  • #38871
    Profile photo of Ed O'Connor
    Ed O’Connor
    Participant

    Hi Everyone,

    I am trying to create a script that runs a command (in this case gets the DSC Status of multiple nodes) and outputs it to a HTML file (using the ConvertTo-HTML command. Everything works fine if the command runs correctly. My issue is that if a DSC process is running on the box (or not configured at all) it expectedly throws a error. I want this error to be outputed to the HTML report but can't figure out how to get it to work. Here is what I came up with:

    function Write-HTML
    {
    
          [CmdletBinding(SupportsShouldProcess=$True)]
    param([Parameter(Mandatory=$false,
          ValueFromPIPeline=$true)]
          [string]$FilePath = "C:\temp\DSCStatusCheck.html",
          [string[]]$Computername = $env:COMPUTERNAME,
    $Css='table{margin:auto; width:95%}
                  Body{background-color:Green; Text-align:Center;}
                    th{background-color:black; color:white;}
                    td{background-color:Grey; color:Black; Text-align:Center;}
         ' )
    
    Begin{ Write-Verbose "HTML report will be saved $FilePath" }
    Process{
    
    Function GetDSCStatus
    {
    
    $Nodes = Get-ADComputer -SearchBase "OU=DSC Managed Nodes,OU=SERVERS,OU=NYC,OU=Americas,DC=lab2,DC=mckinsey,DC=com" -Filter * | Select-Object Name
    
    $DSCStatus = Foreach ($Node in $Nodes.name)
                        {
                            Try
                            {
                                Test-DSCConfiguration -computername $node –detailed | select-object PSComputerName,InDesiredState,@{ Name = "Resources In Desired State" ; Expression = {$_.ResourcesInDesiredState}},@{ Name = "Resources Not In Desired State" ; Expression = {$_.ResourcesNotInDesiredState}} -ErrorAction STOP
                            }
                            Catch
                            {
                                $_ 
                            }
                        }
                  
                    
                    
               
    
    
    #$DSCData | ConvertTo-Html -Fragment -PreContent "DSC Status" | Out-String
    $DSCStatus | ConvertTo-Html -Fragment -PreContent "DSC Status" | Out-String
    }
    
    $DSCOutput = GetDSCStatus
    
    $Report = ConvertTo-Html -Title "DSC Status Check" `
                             -Head "PowerShell ReportingDSC Status ReportThis report was ran: $(Get-Date)" `
                             -Body "$DSCOutput $Css" }
    
    End{ $Report | Out-File $Filepath ; Invoke-Expression $FilePath }
    
    }
    
    Write-HTML 
    
    

    The part I am talking about is the $DSCStatus variable. I thought the Try/Catch would do what I wanted but it is not. No matter what I just get the error in my powershell window and not in the HTML Report.

    Any help or suggestions on how I can accomplish this is appreciated.

    Thanks, Ed

  • #38875
    Profile photo of Don Jones
    Don Jones
    Keymaster

    So... a couple of things, because I might not be understanding whassup.

    So your Try/Catch simply not working? That might be because you're not specifying an -ErrorAction for Test-DSCConfiguration, so it'll default to Continue, which doesn't produce a catch-able exception. Review "The Big Book of PowerShell Error Handling" (free, Resources/ebooks menu here) to understand how -ErrorAction works.

    However, that said, you can't simply spew an error record into the pipeline at the same time as normal objects. ConvertTo-HTML won't know what to do with it. Really, ConvertTo-HTML needs its input to be a series of uniform objects. My suggestion, in the event of an error, would be to construct a custom PSObject having the same properties – PSComputerName,InDesiredState,Name, whatever. Add a field both to your "success" and "error" objects named "ErrorMessage." In your non-error objects, it'll be blank. But you can insert the error message in your error objects, and leave the other properties blank. This will fill the pipeline with consistent-looking objects, which ConvertTo-HTML can handle.

    On a piece of paper, draw a table. Populate the column headers the way you want this to be – PSComputerName,InDesiredState, etc. Draw a grid with several blank rows, all neatly divvied up into those columns.

    Now, how is an error supposed to appear in that grid? Like, what do you want the physical output of this table to look like? I'm not sure you've considered that, which is why you've kind of headed down the bad path, maybe?

  • #38880
    Profile photo of Ed O'Connor
    Ed O’Connor
    Participant

    Hi Don,

    As always thanks.

    I did have a -ErrorAction Stop on the TestDSCConfiguration command.

    The way I thought about this working/being displayed was for any servers that report back a DSC status it shows the columns I specified in the Test-DSCConfiguration command in a single grid (which it does). I had given too much thought to the display of the error in the report (i.e. Cannot Invoke the Test-DSCConfiguration cmdlet...) as I was concentrating on just being able to view it in the report somehow (ugly or whatever) and clean it up later. Right now I just want the error to show in the report somehow. I understand it will not show as one nice grid at this time.

    What am I missing just to get that?

  • #38882
    Profile photo of Don Jones
    Don Jones
    Keymaster

    Well, if Test-DSCConfiguration with -EA Stop isn't throwing an error, then you'll need to work around that first, obviously. So let's test that in as standalone a fashion as possible – can you get it to trap an error, even just in a pilot script that only attempts one non-existent computer?

  • #38883
    Profile photo of Ed O'Connor
    Ed O’Connor
    Participant

    Ok, when we are talking error isn't the red text that comes up in the powershell window when running the command an error? I do see the error in the powershell window when running the script/command.

    "
    Cannot invoke the Test-DscConfiguration cmdlet. The Test-DscConfiguration cmdlet is in progress and must return before Test-DscConfiguration can be invoked. Use -Force option if that is available to cancel the current operation.
    + CategoryInfo : NotSpecified: (root/Microsoft/...gurationManager:String) [], CimException
    + FullyQualifiedErrorId : MI RESULT 1
    + PSComputerName : LAB-DSC-03

    "

    Or is the error that is being captured (hopefully) via the Try/Catch with ErrorAction Stop something else?

  • #38886
    Profile photo of Don Jones
    Don Jones
    Keymaster

    The red error text is not the same as a catch-able exception. This is where that "Big Book of PowerShell Error Handling" (which is only about 30 pages, honestly) would be a good foundation for you to understand what the shell's doing. I'd start there – without the right foundation, we're not going to get you through this ;).

  • #38888
    Profile photo of Don Jones
    Don Jones
    Keymaster

    BUT – that specific error IS NOT A CATCHABLE EXCEPTION.

    It's very clear in what it's telling you – you've just run Test-DscConfiguration, and you can't run it again until it's finished. It's not failing, it's busy. You're simply looping to the next computer before the first one is done.

    You probably need to experiment with adding Start-Sleep so your script can give Test- time to finish.

  • #42083
    Profile photo of Ed O'Connor
    Ed O’Connor
    Participant

    Hi, I just wanted to update this with a copy of the script that checks DSC status and reports back (DSC Compliant, Not Compliant, or any errors that may get thrown) as well as e-mails it to specified users/groups.

    
    function DSCStatusReport
    {
    
          [CmdletBinding(SupportsShouldProcess=$True)]
    param([Parameter(Mandatory=$false,
          ValueFromPIPeline=$true)]
          [string]$FilePath = "C:\temp\DSCStatusReport.html",
          [string[]]$Computername = $env:COMPUTERNAME,
    $Css='table{margin:auto; width:95%}
                  Body{background-color:SteelBlue; Text-align:Center;}
                    th{background-color:black; color:white;}
                    td{background-color:Grey; color:Black; Text-align:Center;}
         ' )
    
    Begin{ Write-Verbose "HTML report will be saved $FilePath" }
    Process{
    
    Function GetDSCStatus
    {
    
    
    $Nodes = $null
    $DSCStatus = $null
    $DSCDate = $null
    $DSCAll = $null
    
    $Nodes = Get-ADComputer -SearchBase "OU=DSC Managed Nodes,OU=SERVERS,OU=NYC,OU=Americas,DC=lab2,DC=test,DC=com" -Filter * | Select-Object Name
    
    $DSCStatus =  Foreach ($Node in $Nodes.name)
                            {
                                Try 
                                {
                                    Test-DSCConfiguration -computername $Node –detailed -ErrorAction STOP  | select-object PSComputerName,InDesiredState,@{ Name = "Resources In Desired State" ; Expression = {$_.ResourcesInDesiredState}},@{ Name = "Resources Not In Desired State" ; Expression = {$_.ResourcesNotInDesiredState}}
                                }
                                Catch 
                                {
                                    $_ | Select-Object @{ Name = "PSComputerName" ; Expression = {$($Node)}},@{ Name = "InDesiredState" ; Expression = {("$_.Exception").substring(0,170)}},@{ Name = "Resources In Desired State" ; Expression =  {"NA"}},@{ Name = "Resources Not In Desired State" ; Expression = {"NA"}}
                                }
                    }
                            
    
                    
                    
                
                  
                    
                    
               
    
    $DSCData = if($DSCStatus.Exception -like "*") 
                {[pscustomobject]@{ 'PSComputerName' = "$($Node)"; "InDesiredSate"= "$($DSCStatus.Exception)";"Resources In Desired State" = "$($DSCStatus.Exception)";"Resources Not In Desired State" = "$($DSCStatus.Exception)" }}
                Else {$DSCStatus}
                
    $DSCAll = $DSCData,$DSCStatus
    
    #$DSCData | ConvertTo-Html -Fragment -PreContent "DSC Data" | Out-String
    $DSCStatus | ConvertTo-Html -Fragment -PreContent "DSC Status" | Out-String
    #$DSCAll | ConvertTo-Html -Fragment -PreContent "DSC All" | Out-String
    }
    
    $DSCOutput = GetDSCStatus
    
    $Report = ConvertTo-Html -Title "DSC Status Check" `
                             -Head "PowerShell ReportingDSC Status ReportThis report was ran: $(Get-Date)" `
                             -Body "$DSCOutput $Css" }
    
    
    
    End{ $Report | Out-File $Filepath ; Invoke-Expression $FilePath }
    
    
    
    }
    
    DSCStatusReport 
    
    send-mailmessage -from "DSCAdmin@test.com" -to "edward_oconnor@test.com" -subject "Sample DSC Status Report" -body "Sample DSC Status Report attached! This is a sample of the report I have create that can run as a task and reports the status of DSC. Unlike the Pre-DSC check this one will report if DSC is functioning." -Attachments "C:\temp\DSCStatusReport.html" -smtpServer mailhub.test.com
    
    
    
    
    • This reply was modified 5 months, 4 weeks ago by Profile photo of Ed O'Connor Ed O'Connor.

You must be logged in to reply to this topic.