Link to home
Start Free TrialLog in
Avatar of Blowfelt82
Blowfelt82

asked on

Add logging to form generated by powershell script.

I have a powershell script which includes a 'WriteToLog' function which basically just writes data to the output stream using the 'Write-Output' cmdlet. This used to work without any issue, however I have since introduced a custom form which is built by the script and displayed using the 'ShowDialog' cmdlet - once the form is displayed any calls to the 'WriteToLog' function do not seem to work any more?

Note: I have proven that the form is calling the 'WriteToLog' function successfully, but the 'Write-Output' is no longer working as expected. I reckon this is because the output is being sent to the output stream of the form and not the calling script but this is a complete guess.

So any ideas how I can dynamically get the output from a generated form in Powershell.

I assume this is because the
Avatar of Jeremy Weisinger
Jeremy Weisinger

Can you post the script and point out where it stops outputting (if possible)?
Avatar of Blowfelt82

ASKER

Unfortunately the script is on a secure server and I have no way of copying the scripts - sorry to be so unhelpful! I will try and get a rough draft of the code up ASAP.
Ok here is a very rough draft of the problem - at least recreates the problem I am facing:

  Function Log
  {
    [CmdletBinding()]
  
    Param ([Parameter(Mandatory=$true)][AllowEmptyString()][string]$LogMessage)
  
    Process{
      Write-Host "Writing to Log:"
      Write-Output  $LogMessage
    }
  }

    $objAForm           = New-Object System.Windows.Forms.Form
    $objBForm         = New-Object System.Windows.Forms.Form

  Function TestFunction()
  {
    Log "Test: In Function"
  }

  Function GenerateForm
  {

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

    # define WinForm object size variables

    $frmASizeHeight      = 180 
    $frmASizeWidth       = 250 
    $objATreeViewHeight  = 250 
    $objATreeViewWidth   = 250
    $objANextButtonX     = 127
    $objANextButtonY     = 115
    $objACancelButtonX   = 37
    $objACancelButtonY   = 115
    $objAButtonDimX      = 80
    $objAButtonDimY      = 24
    $returnValue        = 0

    # create a Windows Form object
  
    $objAForm.Text            = "FORM 1"
    $objAForm.Size            = New-Object System.Drawing.Size($frmASizeWidth, $frmASizeHeight) 
    $objAForm.KeyPreview      = $True
    $objAForm.ControlBox      = $True

    # Buttons

    $objACancelButton           = New-Object System.Windows.Forms.Button
    $objACancelButton.Location  = New-Object System.Drawing.Size($objACancelButtonX, $objACancelButtonY)
    $objACancelButton.Size      = New-Object System.Drawing.Size($objAButtonDimX,$objAButtonDimY)
    $objACancelButton.FlatStyle = "Flat"
    $objACancelButton.Text      = "Cancel"
    $objACancelButton.Add_Click(
    {
     $objAForm.Close() | Out-Null
    })

     Log "Test 1"

    $objANextButton           = New-Object System.Windows.Forms.Button
    $objANextButton.Location  = New-Object System.Drawing.Size($objANextButtonX, $objANextButtonY)
    $objANextButton.Size      = New-Object System.Drawing.Size($objAButtonDimX,$objAButtonDimY)
    $objANextButton.FlatStyle = "Flat"
    $objANextButton.Text      = "Next"
    $objANextButton.Add_Click(
    {
       TestFunction
       Log "Test 2"

    })

     Log "Test 3"

    $objAForm.Controls.Add($objACancelButton)
    $objAForm.Controls.Add($objANextButton)

    # Display form

    [void]$objAForm.ShowDialog()
  }

  GenerateForm

Open in new window


On my environment the log outputs Test 1 and Test 2 which are both outside the 'scope' of the GUI button event handler, this is correct. But the other tests originating from within the event handler code and/or the function it calls are not output? I have added the 'Writing to Log' message to prove that the Log function is being called correctly - which it is... Just looks as though the Write-Output cmdlet does not work correctly (or how I would like) when called via the GUI's event handler. Hopefully that should be enough - let me know if not!
Edit the above should read: Test 1 and Test 3
Ah, I see. You'll need to set a variable since that is not in the stream.
Could you provide an example with the code above, not sure exactly what is involved
Here's a rudimentary example.

  Function Log
  {
    [CmdletBinding()]
  
    Param ([Parameter(Mandatory=$true)][AllowEmptyString()][string]$LogMessage)
  
    Process{
      Write-Host "Writing to Log:"
      $LogMessage
    }
  }

    $objAForm           = New-Object System.Windows.Forms.Form
    $objBForm         = New-Object System.Windows.Forms.Form

  Function TestFunction()
  {
    Log "Test: In Function"
  }

  Function GenerateForm
  {

    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

    # define WinForm object size variables

    $frmASizeHeight      = 180 
    $frmASizeWidth       = 250 
    $objATreeViewHeight  = 250 
    $objATreeViewWidth   = 250
    $objANextButtonX     = 127
    $objANextButtonY     = 115
    $objACancelButtonX   = 37
    $objACancelButtonY   = 115
    $objAButtonDimX      = 80
    $objAButtonDimY      = 24
    $returnValue        = 0

    # create a Windows Form object
  
    $objAForm.Text            = "FORM 1"
    $objAForm.Size            = New-Object System.Drawing.Size($frmASizeWidth, $frmASizeHeight) 
    $objAForm.KeyPreview      = $True
    $objAForm.ControlBox      = $True

    # Buttons

    $objACancelButton           = New-Object System.Windows.Forms.Button
    $objACancelButton.Location  = New-Object System.Drawing.Size($objACancelButtonX, $objACancelButtonY)
    $objACancelButton.Size      = New-Object System.Drawing.Size($objAButtonDimX,$objAButtonDimY)
    $objACancelButton.FlatStyle = "Flat"
    $objACancelButton.Text      = "Cancel"
    $objACancelButton.Add_Click(
    {
     $objAForm.Close() | Out-Null
    })

     Log "Test 1"

    $objANextButton           = New-Object System.Windows.Forms.Button
    $objANextButton.Location  = New-Object System.Drawing.Size($objANextButtonX, $objANextButtonY)
    $objANextButton.Size      = New-Object System.Drawing.Size($objAButtonDimX,$objAButtonDimY)
    $objANextButton.FlatStyle = "Flat"
    $objANextButton.Text      = "Next"
    $objANextButton.Add_Click(
    {
       TestFunction
       $global:testResults = Log "Test 2"

    })
   
    
     Log "Test 3"

    $objAForm.Controls.Add($objACancelButton)
    $objAForm.Controls.Add($objANextButton)

    # Display form

    [void]$objAForm.ShowDialog()
  }

  GenerateForm
  #results of test 2
  Write-Output $testResults

Open in new window

Unfortunately I am not sure this solution is what I need, the logging is only updated when the form is closed - and only handles a single line of output. I need a way to dynamically log from the event handler if possible?
ASKER CERTIFIED SOLUTION
Avatar of Jeremy Weisinger
Jeremy Weisinger

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for your help, not the way I wanted it to work but managed to get logging working by using a global variable to capture the GUI input and then perform the processing outside of the form scripting as per your recommendation. Thanks for your help.