Link to home
Start Free TrialLog in
Avatar of sirbounty
sirbountyFlag for United States of America

asked on

Some slight tweaks on my powershell instance

I'm running the following inside my visual studio project and I'm looking to obtain two things:

1) I have to import a pssession to utilize some exchange cmdlets.  I do this with $session = path to server, etc... and then
import-pssession $session -allowclobber -disablenamechecking -verbose:$false |out-null
But yet, in my capture of verbose output, it's continually displaying the typical verbose output for this:
VERBOSE: Importing function 'Get-...', etc, etc...

How can I supress these messages?

2) The other component of this is that when my powershell script completes, I'm using
exit $exitCode
I'd like to grab that exit code, but it doesn't seem that my current code picks it up.

Here's the relevant snippet:
     PowerShellInstance.AddScript(CommandString)
            Dim outputCollection As New PSDataCollection(Of PSObject)()
            'outputCollection.DataAdded += outputCollection_DataAdded  <<< Not sure if this is part of my problem.  It was in the source, but I couldn't get it working in vb.net (converted from c#)

            ' the streams (Error, Debug, Progress, etc) are available on the PowerShell instance.
            ' we can review them during or after execution.
            ' we can also be notified when a new item is written to the stream (like this):
            'PowerShellInstance.Streams.[Error].DataAdded += Error_DataAdded
'changed above to:
            AddHandler PowerShellInstance.Streams.Error.DataAdded, AddressOf Error_DataAdded
            AddHandler PowerShellInstance.Streams.Verbose.DataAdded, AddressOf Verbose_DataAdded

            Try
                Dim result As IAsyncResult = PowerShellInstance.BeginInvoke(Of PSObject, PSObject)(Nothing, outputCollection)
                Console.Write(vbTab & "Waiting for pipeline to finish")
                While result.IsCompleted = False
                    Threading.Thread.Sleep(2500)
                End While
                Console.Write("Execution is: )
                Console.WriteLine(PowerShellInstance.InvocationStateInfo.State.ToString())
            Catch ex As Exception
                Console.WriteLine("Execution failed.  Exception is " & ex.Message)
            End Try
        End Using

Open in new window



Output that I don't want looks like this: ('Waiting for pipeline to finish', is expected)

        Waiting for pipeline to finishVERBOSE: Loading module from path 'C:\Users\xxxxxx
\AppData\Local\Temp\2\tmp_zrnqd2ou.xwd\tmp_zxnrd2ou.xwd.psd1'.
VERBOSE: Importing function 'Add-ADPermission'.
VERBOSE: Importing function 'Add-AvailabilityAddressSpace'.
VERBOSE: Importing function 'Add-ContentFilterPhrase'.
VERBOSE: Importing function 'Add-DatabaseAvailabilityGroupServer'.
VERBOSE: Importing function 'Add-DistributionGroupMember'.
VERBOSE: Importing function 'Add-FederatedDomain'.
VERBOSE: Importing function 'Add-IPAllowListEntry'.
VERBOSE: Importing function 'Add-IPAllowListProvider'.
VERBOSE: Importing function 'Add-IPBlockListEntry'.
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

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
Avatar of sirbounty

ASKER

Assigning it to a variable didn't work. :(
Bugs me that I can't suppress that.  Trimming the commands helped, but I can feel it taunting me...

I've set the event handler - I thought correctly - I mirrored the others (didn't know what to cast it as, so I guessed).
Still not seeing the exit code - does this look correct?
Private Sub output_DataAdded(sender As Object, e As DataAddedEventArgs)
        Dim records = DirectCast(sender, PSDataCollection(Of IDataRecord))
        Console.WriteLine("DATA: " & records(e.Index).ToString())
    End Sub

    Private Sub Verbose_DataAdded(sender As Object, e As DataAddedEventArgs)
        Dim records = DirectCast(sender, PSDataCollection(Of VerboseRecord))
        Console.WriteLine("VERBOSE: " & records(e.Index).ToString())
    End Sub

    Private Sub Error_DataAdded(sender As Object, e As DataAddedEventArgs)
        Dim records = DirectCast(sender, PSDataCollection(Of ErrorRecord))
        Console.WriteLine("ERROR: " & records(e.Index).ToString())
    End Sub

Open in new window

Tried this too - only other thing that seemed somewhat logical by comparison:

Dim records = DirectCast(sender, PSDataCollection(Of InformationalRecord))

Still no dice
I believe that exit $exitCode will only return the value, not output it.

I wonder if you need a Write-Host call:

        Write-Host "From PowerShell: Exit.ps1 exited with exit code $LastExitCode"
Is the Output_DataAdded event being raised.  If so, should be able to find out the type of object that the collection holds?
Also, you are attaching an event handler to the Error_DataAdded event.  Is that event raised?
I tried a write-host yesterday - complained about host something or nother and sounded like I needed some adjustments to allow that.

Is the Output_DataAdded event being raised.  If so, should be able to find out the type of object that the collection holds?
Checking that now...
No, I haven't added an error_dataadded handler, but I will..
I don't see 'data' streams available, but I wonder if I shouldn't be grabbing something from the instance here?

AddHandler PowerShellInstance.Streams.Error.DataAdded, AddressOf Error_DataAdded
AddHandler PowerShellInstance.Streams.Verbose.DataAdded, AddressOf Verbose_DataAdded
AddHandler outputCollection.DataAdded, AddressOf outputCollection_DataAdded
I see this code:

Private Sub Error_DataAdded(sender As Object, e As DataAddedEventArgs)
        Dim records = DirectCast(sender, PSDataCollection(Of ErrorRecord))
        Console.WriteLine("ERROR: " & records(e.Index).ToString())
    End Sub

Open in new window

output_dataadded is not being raised...yet
Bah - you're correct.  I completely forgot I added that.
The error has been raised a couple of times while testing, so that seems to be working....
Reference question:

https://www.experts-exchange.com/questions/28672280/launching-a-powershell-script-from-visual-studio-2010.html

The code had this, which doesn't reference any stream:

 
          // prepare a new collection to store output stream objects
            PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
            outputCollection.DataAdded += outputCollection_DataAdded;

Open in new window

and it is used here:

IAsyncResult result = PowerShellInstance.BeginInvoke<PSObject, PSObject>(null, outputCollection);

Open in new window


I am thinking that this whole output data collection event handling is useless, since you already have the output collection to inspect.
There is a note from the posted link:

if your scripts utilize write-error, write-debug, write-progress, etc. (all thread-safe collections), you can review these during or after execution to check for items logged there.
You may be right (usually are :^) - My problem is I'm having to deploy the exe to the server to test, so it's taking a little longer than I'd like, and I can't simply step through it to find out how I might be able to use that result...
But, still plugging away...thanks.
This might also be helpful:

HOW TO: Call .PS1 script from Managed code using Remote Powershell(Exchange 2010)
http://blogs.msdn.com/b/akashb/archive/2010/03/26/how-to-call-ps1-script-from-managed-code-using-remote-powershell-exchange-2010.aspx
I'll have a look at that later - have to head out now (should have two hours ago!)

I did check the outputCollection.Count (it was 0)
and tried iterating any items therein
                    For i As Int16 = 0 To outputCollection.Count - 1
                        Console.WriteLine(outputCollection.Item(i))
                    Next
but that didn't give me anything when I had no errors, and when I forced an error.

I did get a couple of raised Error events from it, but I'll have to dive into that later.
Thanks - I'll post an update when I can, either this evening or first thing tomorrow.
function Resolve-Error ($ErrorRecord=$Error[0])
{
   $ErrorRecord | Format-List * -Force
   $ErrorRecord.InvocationInfo |Format-List *
   $Exception = $ErrorRecord.Exception
   for ($i = 0; $Exception; $i++, ($Exception = $Exception.InnerException))
   {   "$i" * 80
       $Exception |Format-List * -Force
   }
}
So far, I've tried:

For Each p As PSObject In outputCollection
  Console.WriteLine(p.BaseObject.ToString)
Next
(nothing)
For Each final As PSObject In PowerShellInstance.EndInvoke(result)
  Console.WriteLine(final.BaseObject.GetType().FullName)
  Console.WriteLine(final.BaseObject.ToString)
 Next
That throws an object ref error.

That last function you posted - that's supposed to do what?
My error codes come from an internal table in an xml file - still applicable?
Hate to say it, but I'm going to give up on this one...
I just wanted to retrieve the exit code from the script so that I could pass it back to the vs project for reporting to the engineer staff.  I can accomplish it with much less work within the powershell script.

Thanks for the guidance and support!