Output saved in Log file but nothing in CLI with Tee-Object ?!

Hi,

I have the below script which passes an error to a function.

Function WriteLog {
    param(
        [Parameter(Mandatory = $true)][string] $ErrorMessage,
        [Parameter(Mandatory = $false)]
        [ValidateSet("INFO","ERROR")]
        [string] $ErrorLevel = "INFO"
    )
    Add-Content -Path $logFilePath -Value "$(getDateTime) [$ErrorLevel] $ErrorMessage" | Tee-Object -FilePath $logFilePath -Append
}

WriteLog -ErrorLevel ERROR -ErrorMessage "$("`n" + $_.Exception.Message + "`n" + $_.CategoryInfo + "`n" + "$($_.InvocationInfo.ScriptLineNumber): $($_.InvocationInfo.Line)")"

The error logs fine into the log file but the Tee-Object does not show anything on the CLI.

CLI OUTPUT

19 Mar 2024 23:03:23:30 Configuring Networking
Rename-Netadapter : No MSFT_NetAdapter objects found with property 'Name' equal to 'Ethernet0'.  Verify the value of
the property and retry.
At C:\Users\Administrator\Desktop\a\DC-AFR-ADDC.ps1:488 char:13
+             Rename-Netadapter -name $ethernetNIC0 -newname $ethernetN ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Ethernet0:String) [Rename-NetAdapter], CimJobException
    + FullyQualifiedErrorId : CmdletizationQuery_NotFound_Name,Rename-NetAdapter

19 Mar 2024 23:03:23:33 Ethernet0 Adapter Renamed DC-AFR-ADDC
PS C:\Users\Administrator\Desktop\a>

LOG FILE OUTPUT

19 Mar 2024 23:03:23:30 [INFO] 19 Mar 2024 23:03:23:30 Configuring Networking
19 Mar 2024 23:03:23:33 [INFO] 19 Mar 2024 23:03:23:33 Ethernet0 Adapter Renamed DC-AFR-ADDC
19 Mar 2024 23:03:23:36 [ERROR] 
Instance MSFT_NetIPAddress already exists

InvalidArgument: (MSFT_NetIPAddress:ROOT/StandardCimv2/MSFT_NetIPAddress) [New-NetIPAddress], CimException
492:             Get-NetAdapter $ethernetNICName | New-NetIPAddress -IPAddress $serverIP -AddressFamily IPv4 -PrefixLength $serverSubnet -DefaultGateway $serverGateway -ErrorAction Stop | Out-Null

Any thoughts ?

Since Add-Content does not return any output by default thereā€™s nothing for Tee-Object to work with. Youā€™re using it wrong. It should be something line this:

"$(getDateTime) [$ErrorLevel] $ErrorMessage" | 
    Tee-Object -FilePath $logFilePath -Append
1 Like

Hi @Olaf

ā€œ$(getDateTime) [$ErrorLevel] $ErrorMessageā€ |
Tee-Object -FilePath $logFilePath -Append

Removing Add-Content causes everything to show in the CLI Terminal, even that which is only for the log fileā€¦

OUTPUT from CLI

20 Mar 2024 03:25:54:98 [INFO] 20 Mar 2024 03:25:54:98 Disabling IPv6
20 Mar 2024 03:25:54:99 Configuring Networking
20 Mar 2024 03:25:54:99 [INFO] 20 Mar 2024 03:25:54:99 Configuring Networking
Rename-Netadapter : No MSFT_NetAdapter objects found with property ā€˜Nameā€™ equal to ā€˜Ethernet0ā€™. Verify the value of
the property and retry.
At C:\Users\Administrator\Desktop\a\DC-AFR-ADDC.ps1:489 char:13

  •         Rename-Netadapter -name $ethernetNIC0 -newname $ethernetN ...
    
  •         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    • CategoryInfo : ObjectNotFound: (Ethernet0:String) [Rename-NetAdapter], CimJobException
    • FullyQualifiedErrorId : CmdletizationQuery_NotFound_Name,Rename-NetAdapter

20 Mar 2024 03:25:55:01 Ethernet0 Adapter Renamed DC-AFR-ADDC
20 Mar 2024 03:25:55:01 [INFO] 20 Mar 2024 03:25:55:01 Ethernet0 Adapter Renamed DC-AFR-ADDC
20 Mar 2024 03:25:55:06 [ERROR]
Instance MSFT_NetIPAddress already exists

InvalidArgument: (MSFT_NetIPAddress:ROOT/StandardCimv2/MSFT_NetIPAddress) [New-NetIPAddress], CimException
493: Get-NetAdapter $ethernetNICName | New-NetIPAddress -IPAddress $serverIP -AddressFamily IPv4 -PrefixLength $serverSubnet -DefaultGateway $serverGateway -ErrorAction Stop | Out-Null

PS C:\Users\Administrator\Desktop\a>

OUTPUT from Log

20 Mar 2024 03:25:54:98 [INFO] 20 Mar 2024 03:25:54:98 Disabling IPv6
20 Mar 2024 03:25:54:99 [INFO] 20 Mar 2024 03:25:54:99 Configuring Networking
20 Mar 2024 03:25:55:01 [INFO] 20 Mar 2024 03:25:55:01 Ethernet0 Adapter Renamed DC-AFR-ADDC
20 Mar 2024 03:25:55:06 [ERROR]
Instance MSFT_NetIPAddress already exists

InvalidArgument: (MSFT_NetIPAddress:ROOT/StandardCimv2/MSFT_NetIPAddress) [New-NetIPAddress], CimException
493: Get-NetAdapter $ethernetNICName | New-NetIPAddress -IPAddress $serverIP -AddressFamily IPv4 -PrefixLength $serverSubnet -DefaultGateway $serverGateway -ErrorAction Stop | Out-Null

You have the talent to confuse. :smirk:

I understood that this is waht you want. :thinking: :man_shrugging:t3:

If you donā€™t want to show something in the console you can use Add-Content and for things you want to show on the console and add it to your logfile you use Tee-Object. :point_up:t3:

1 Like

Thanks and apologies if it was confusingā€¦

The idea is to only see an error in both the CLI and Log file, what is happening is it shows everything in the CLI even that which is only for the log fileā€¦

Just adding some more code for better understandingā€¦

    Try
      {
        Write-host "$(getDateTime) Configuring Networking" -ForegroundColor DarkGreen
        WriteLog "$(getDateTime) Configuring Networking"

        Rename-Netadapter -name $ethernetNIC0 -newname $ethernetNICName
        Write-host "$(getDateTime) $ethernetNIC0 Adapter Renamed $ethernetNICName" -ForegroundColor DarkGreen
        WriteLog "$(getDateTime) $ethernetNIC0 Adapter Renamed $ethernetNICName"

        Get-NetAdapter $ethernetNICName | New-NetIPAddress -IPAddress $serverIP -AddressFamily IPv4 -PrefixLength $serverSubnet -DefaultGateway $serverGateway -ErrorAction Stop | Out-Null
        Write-host "$(getDateTime) $ethernetNICName IP address Is $serverIP`n$(getDateTime) $ethernetNICName Subnet Mask Is $serverSubnet`n$(getDateTime) $ethernetNICName Gateway Is $serverGateway" -ForegroundColor DarkGreen
        WriteLog "$(getDateTime) $ethernetNICName IP Address Is $serverIP`n$(getDateTime) $ethernetNICName Subnet Mask Is $serverSubnet`n$(getDateTime) $ethernetNICName Gateway Is $serverGateway"

        Get-NetAdapter $ethernetNICName | Set-DnsClientServerAddress -ServerAddresses $serverDNS,$serverIP -ErrorAction Stop | Out-Null
        Write-host "$(getDateTime) $ethernetNICName DNS Is $serverDNS, $serverIP" -ForegroundColor DarkGreen
        WriteLog "$(getDateTime) $ethernetNICName DNS Is $serverDNS, $serverIP"
    }
    Catch
      {
       WriteLog -ErrorLevel ERROR -ErrorMessage "$("`n" + $_.Exception.Message + "`n" + $_.CategoryInfo + "`n" + "$($_.InvocationInfo.ScriptLineNumber): $($_.InvocationInfo.Line)")"
        Break;
    }

It may not be an answer to your question - sorry, but it may be a solution to your actual problem:

I tend to think about Tee-Object as a solution for a third party CLI tool not able to write a log file by itself. This way you could keep the console output and write a log file at the same time. And I think itā€™s meant to be used in interactive sessions on the console - not in scripts of function where you other ways.

In a PowerShell function or script you have the full control over what should happen. You can use Write-Error when you want to output an error and you have some options to write a status or whatever you like to a file, to an event log or whatever. So I would like to encourage you to not getting stuck on one particular idea. Try to think another solution when the one came up with first does not work. :man_shrugging:t3:

Regardless of all that: In the vast majority of the cases youā€™re not the very first one with a given task. So it is very very likely that someone else alreadyā€™s got a solution and even shared it with the world.

For your example Iā€™d recommend to take a look at the PowerShell Framework. It provides besides a lot of other stuff ā€œAdvanced message & logging functionalityā€. So you can stand on the shoulders of giants and focus on more important stuff than logging and console output. I know Iā€™d like to spend my time and effort on more rewarding things than logging. :wink:

Thanks @Olaf

Appreciate that, and I can do that but I would rather make mistakes and learn because yesterday I did not know what parameters are or how they work, today I doā€¦

Appreciate all the helpā€¦

I know exactly what you mean. And of course you can spend your time and effort to whatever you like. But it does not contradict my recommendation to spend your time and effort on something more meaningfull than logging. You will still learn new things on the way even when youā€™re not building something what thousand others already have build before you. :wink: :love_you_gesture:t3: :slightly_smiling_face: :+1:t3:

Thanks @Olaf I understand your pointā€¦

However, apologies, it might be a mistake on your part that Iā€™m learning logging, Iā€™m not, its better for me to try and try a couple of times then find an alternate way to do it, but I do get your pointā€¦

Thanks again, cheersā€¦

OK, so what is your actual question then? :thinking: In the last code sample you posted you donā€™t even use Tee-Object. :man_shrugging:t3:

And BTW: You should format your code as code - not as quote!

When you post code, sample data, console output or error messages please format it as code using the preformatted text button ( </> ). Simply place your cursor on an empty line, click the button and paste your code.

Thanks in advance

How to format code in PowerShell.org 1 <---- Click :point_up_2:t4: :wink:

( !! Sometimes the preformatted text button hides behind the settings gear symbol. :wink: )

1 Like

Apprecite your understandingā€¦

1st every time I have to log into this website I have to reset my password even though the password is correct, or issue a 1 time login link (which only comes in after about10-15 minutes sometimes, and other times it doesnā€™t). Just found out about the Admins in the profile page, will message them.

As for the code yes I realized it only some time back the code icon hides behind the gear icon, will be careful about itā€¦

Sorry sometimes I forget that others will be able to relate the code I shared with the original oneā€¦

The is the current chunk of codeā€¦

Function WriteLog {
    param(
        [Parameter(Mandatory = $true)][string] $ErrorMessage,
        [Parameter(Mandatory = $false)]
        [ValidateSet("INFO","ERROR")]
        [string] $ErrorLevel = "INFO"
    )
    Add-Content -Path $logFilePath -Value "$(getDateTime) [$ErrorLevel] $ErrorMessage" | Tee-Object -FilePath $logFilePath -Append
}

    Try
      {
        Write-host "$(getDateTime) Configuring Networking" -ForegroundColor DarkGreen
        WriteLog -ErrorMessage "$(getDateTime) Configuring Networking"

        Rename-Netadapter -name $ethernetNIC0 -newname $ethernetNICName
        Write-host "$(getDateTime) $ethernetNIC0 Adapter Renamed $ethernetNICName" -ForegroundColor DarkGreen
        WriteLog -ErrorMessage "$(getDateTime) $ethernetNIC0 Adapter Renamed $ethernetNICName" <--- This is added to the log file as INFO
    }
    Catch
      {
       WriteLog -ErrorLevel ERROR -ErrorMessage "$("`n" + $_.Exception.Message + "`n" + $_.CategoryInfo + "`n" + "$($_.InvocationInfo.ScriptLineNumber): $($_.InvocationInfo.Line)")" **<--- This is added to the log file as ERROR, this appears in the log file but not in the console, even with Tee-Object. I got to know Add-Content does not has no output this is why there is nothing appearing in the console, so I'm thinking if ther is something else that can add to the log file, has output which can go into Tee.**
        Break;
    }

I have added comments in the code with what the issue isā€¦

Thanks @Olaf

You confuse me more and more.

How does this ā€¦

ā€¦relate to your issue?

I donā€™t know what this means.

Thatā€™s what I meant. You donā€™t have to do it all in one command. Use Write-Error to actually output an error message to the console and use a second command to add the desired string to a log file. Why does it have to be all in one? :man_shrugging:t3: It might be even a good idea to output some even more detailed information to the log file than you output to the console.

In general: I wonder that you get the Catch block to fire up at all. For a try catch finally to work properly you need a terminating error to happen inside your try block. If you use a cmdlet not throwing a terminating error by default you have to force it with the common parameter -ErrorAction set to ā€œStopā€.
And Iā€™d recommend having as few commands as possible in the try block. Otherwise you donā€™t know what command actually failed.

Regardless of that Iā€™d recommend using Write-Verbose or Write-Debug instead of Write-Host. This way you can enable verbose output with a switch parameter if you need but omit it during normal operation to not clutter your console with useless information.

Comments in PowerShell are prefixed with a hash symbol (#) !!! :point_up:t3: :face_with_raised_eyebrow:

Thanks @Olaf for clarifyingā€¦

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.