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
Blowfelt82Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jeremy WeisingerSenior Network Consultant / EngineerCommented:
Can you post the script and point out where it stops outputting (if possible)?
0
Blowfelt82Author Commented:
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.
0
Blowfelt82Author Commented:
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!
0
Simplify Active Directory Administration

Administration of Active Directory does not have to be hard.  Too often what should be a simple task is made more difficult than it needs to be.The solution?  Hyena from SystemTools Software.  With ease-of-use as well as powerful importing and bulk updating capabilities.

Blowfelt82Author Commented:
Edit the above should read: Test 1 and Test 3
0
Jeremy WeisingerSenior Network Consultant / EngineerCommented:
Ah, I see. You'll need to set a variable since that is not in the stream.
0
Blowfelt82Author Commented:
Could you provide an example with the code above, not sure exactly what is involved
0
Jeremy WeisingerSenior Network Consultant / EngineerCommented:
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

0
Blowfelt82Author Commented:
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?
0
Jeremy WeisingerSenior Network Consultant / EngineerCommented:
How are you capturing the Write-Output? Are you just redirecting the stdout?

There might be a way to get the Write-Output cmdlet to write to the main pipeline but I don't know how.

You may need to start writing to a log file instead. That way when it's in the form you can write to the log file as it seems that the new thread the form runs in doesn't write it's stdout to the console.  

Another option would be to build an output variable and then write the output at the end of the script.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Blowfelt82Author Commented:
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.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.