Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

skip console messages if the host is non-interactive #13

Merged
merged 1 commit into from
Feb 1, 2017
Merged

skip console messages if the host is non-interactive #13

merged 1 commit into from
Feb 1, 2017

Conversation

lisaong
Copy link

@lisaong lisaong commented Jan 25, 2017

Issue #12

First try the -NonInteractive parameter check (which should catch most cases). If no parameters are supplied, check for the 'Default Host' name.

The latter check is needed when running the scripts within the EdgePS hosting environment. Unfortunately, no parameters are supplied in the binary version that we are consuming.

Resolves #12: Console messages should be suppressed in Write-Log for non-interactive consoles

@msftclas
Copy link

Hi @lisaong, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution!


It looks like you're a Microsoft contributor (Lisa Ong). If you're full-time, we DON'T require a Contribution License Agreement. If you are a vendor, please DO sign the electronic Contribution License Agreement. It will take 2 minutes and there's no faxing! https://cla.microsoft.com.

TTYL, MSBOT;

@@ -383,23 +401,27 @@ function Write-Log
$env:username,
$Message

switch ($Level)
# Output to the console if it is interactive
if ($global:SBInInteractiveConsole)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not appropriate to filter this out here. You should have this check only around the Write-Host.  People can modify the execution of a non-interactive PowerShell console to still redirect / pipe Error, Warning Verbose, Debug and Informational output to somewhere else. It's the Write-Host specifically that's causing you issues, and so that's the only one that should be protected by this check.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could solve this with Write-InteractiveHost, mentioned above

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Thanks for the feedback!

$output += "This is non-fatal, and your command will continue. Your log file will be missing this entry:"
$output += $ConsoleMessage
Write-Warning ($output -join [Environment]::NewLine)
if ($global:SBInInteractiveConsole)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, Write-Warning shouldn't be causing you issues. If it is, we should talk further.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed. Thanks!

@@ -71,6 +71,14 @@ function Initialize-HelpersGlobalVariables
{
$global:SBNotifyCredential = [PSCredential]$null
}

# Initialize and cache whether this console is interactive
$global:SBInInteractiveConsole = ![Bool]([Environment]::GetCommandLineArgs() -like '-noni*')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only time we use global variables is when we're looking to allow for a user configuration. This variable is not intended for users to set their own value for (its value is inferred by the environment), and therefore it shouldn't be global. $script: would be the appropriate scope for this one, and it therefore shouldn't be in this method.  Just move this block of code to be below the call to Initialize-HelpersGlobalVariables

if ($global:SBInInteractiveConsole)
{
# Some hosts like "Default Host" don't take command line arguments, but default to non-interactive
$global:SBInInteractiveConsole = (Get-Host).Name -ne 'Default Host'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if you can avoid this check if you do a check for [Environment]::UserInteractive and -and that with your other check. I was looking at StackOverflow and that appeared to be the consensus for this issue.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, [Environment]::UserInteractive returned true in the edge-ps environment, so I had to keep the check.

if ($global:SBInInteractiveConsole)
{
Write-Host "`r$($animationFrames[$($iteration % $($animationFrames.Length))]) Elapsed: $([int]($iteration / $framesPerSecond)) second(s) $Description" -NoNewline -f Yellow
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we could have a Write-InteractiveHost function that takes care of checking if we are in an interactive host and noops if we aren't. Then you just need to change the function names here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a great suggestion.  +1

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I ended up generating a proxy function, ripping out the guts (because it's more complicated than our purposes), and then forwarding the call to Write-Host appropriately.

In case you are curious, the proxy function is this complex because it allows you to augment parameters.  I pasted the original below.

https://blogs.technet.microsoft.com/heyscriptingguy/2011/03/01/proxy-functions-spice-up-your-powershell-core-cmdlets/

[CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113426', RemotingCapability='None')]
param(
    [Parameter(Position=0, ValueFromPipeline=$true, ValueFromRemainingArguments=$true)]
    [System.Object]
    ${Object},

    [switch]
    ${NoNewline},

    [System.Object]
    ${Separator},

    [System.ConsoleColor]
    ${ForegroundColor},

    [System.ConsoleColor]
    ${BackgroundColor})

begin
{
    try {
        $outBuffer = $null
        if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
        {
            $PSBoundParameters['OutBuffer'] = 1
        }
        $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Write-Host', [System.Management.Automation.CommandTypes]::Cmdlet)
        $scriptCmd = {& $wrappedCmd @PSBoundParameters }
        $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
        $steppablePipeline.Begin($PSCmdlet)
    } catch {
        throw
    }
}

process
{
    try {
        $steppablePipeline.Process($_)
    } catch {
        throw
    }
}

end
{
    try {
        $steppablePipeline.End()
    } catch {
        throw
    }
}
<#

.ForwardHelpTargetName Microsoft.PowerShell.Utility\Write-Host
.ForwardHelpCategory Cmdlet

#>

}

@@ -105,7 +105,6 @@ function Wait-JobWithAnimation
set of configuration options that Wait-Job does.
#>
[CmdletBinding()]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "", Justification="This function is intended for human interaction, not for scripting. Write-Host makes the most sense for visible feedback.")]
Copy link
Author

@lisaong lisaong Jan 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re-ran Invoke-ScriptAnalyzer -Path .\ -Recurse, and no new hits for Helpers.ps1 due to the changes.

[CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113426', RemotingCapability='None')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "", Justification="This provides a wrapper around Write-Host. In general, we'd like to use Write-Information, but it's not supported on PS 4.0 which we need to support.")]
param(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit picky stuff, this should be reformatted to be consistent with the file

  • closing paren ')' for the param block should be on its own line and aligned under the 'p' of 'param'
  • variables should be on the same line as their type, separated by a space
  • variables don't need the curlys, just the $ and their name
  • each characteristic in the Parameter attribute should be on its own line, see ConvertTo-Array in this file
    - just specify the characteristic, no need to add the $true as it is implicit. For example, it's enough to say 'ValueFromPipeline'. See ConvertTo-Array in this file

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some things to still fix on this topic:

  • Still don't need the brackets for these parameter names. Instead of ${NoNewLine}, just do $NoNewLine.
  • Please have a new-line between params for consistency with the other functions
  • make cmdletbinding multi-line like we do with all the other functions with multiple inputs to it.
  • capitalize CmdletBinding the same way as we do in the other functions.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure what you meant by "capitalize CmdletBinding the same way as we do in the other functions." Do you have an example?

$PSBoundParameters['OutBuffer'] = 1
}
Write-Host @PSBoundParameters
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: add a newline after the if-block before the next statement.

non-interactive hosts.

Boilerplate is generated using these commands:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This "boilerplate" info is interesting, but better suited for the .NOTES section of the comment-based-help since it doesn't help users who are trying to use the method.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

[CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113426', RemotingCapability='None')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "", Justification="This provides a wrapper around Write-Host. In general, we'd like to use Write-Information, but it's not supported on PS 4.0 which we need to support.")]
param(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some things to still fix on this topic:

  • Still don't need the brackets for these parameter names. Instead of ${NoNewLine}, just do $NoNewLine.
  • Please have a new-line between params for consistency with the other functions
  • make cmdletbinding multi-line like we do with all the other functions with multiple inputs to it.
  • capitalize CmdletBinding the same way as we do in the other functions.


# Determine if the host is interactive
if ([Environment]::UserInteractive -and ![Bool]([Environment]::GetCommandLineArgs() -like '-noni*') -and (Get-Host).Name -ne 'Default Host')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommend splitting this into three lines since this line exceeds 100 chars.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!


[CmdletBinding(HelpUri='http://go.microsoft.com/fwlink/?LinkID=113426', RemotingCapability='None')]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingWriteHost", "", Justification="This provides a wrapper around Write-Host. In general, we'd like to use Write-Information, but it's not supported on PS 4.0 which we need to support.")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to remove the other two PSAvoidUsingWriteHost SuppressMessageAttributes now...one is on Wait-JobWithAnimation and the other is on Write-Log.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they were already removed, I think you may be looking at an older version.


# Determine if the host is interactive
if ([Environment]::UserInteractive -and ![Bool]([Environment]::GetCommandLineArgs() -like '-noni*') -and (Get-Host).Name -ne 'Default Host')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a StackOverflow discussion I saw on this topic, some users were talking about the performance impact of some of these tests. I'm curious if you notice any change in perceived behavior when running the command in an interactive console window...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't noticed any difference so far. It could be because the commands themselves take a while to run (e.g. showing progress).  If there is really a perf impact, we can consider making a follow-up change to cache the state.

@@ -442,21 +440,21 @@ function Write-Log

switch ($Level)
{
'Error' { Write-Error $ConsoleMessage }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching these...

@HowardWolosky
Copy link
Member

It would also be helpful for you could bump the patch part of the version as well as part of your change.

ValueFromPipeline=$true,
ValueFromRemainingArguments=$true)]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: No linefeed between the [Parameter] attribute and the parameter that it's associated with,

[Parameter(
Position=0,
ValueFromPipeline=$true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no need to specify $true for the parameter configurations. When you reference them by name, they default to $true.

Copy link
Member

@HowardWolosky HowardWolosky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two minor nits. Once done, please squash your changes into a single commit, and then i'll rebase it into master.

consistent casing for $consoleMessage

Addressed feedback from @HowardWolosky-MSFT and @danbelcher-MSFT by wrapping Write-Host calls with Write-InteractiveHost, so that calls to Write-Host are only forwarded if the host is interactive.

Style feedback from @danbelcher-MSFT

Addressed more style feedback from @HowardWolosky-MSFT, bumped patch version

Addressed last remaining feedback from @HowardWolosky-MSFT
@HowardWolosky HowardWolosky merged commit ef9b01c into microsoft:master Feb 1, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants