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

Add VerboseAction, DebugAction, ProgressAction, VerboseVariable, DebugVariable, and ProgressVariable common parameters #10238

Closed
Closed
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e996df8
normalize stream common parameters
KirkMunro Jul 27, 2019
fc21ea9
test updates
KirkMunro Jul 27, 2019
5429151
CodeFactor update plus some Pester fixes
KirkMunro Jul 27, 2019
813f936
fix to Pester test
KirkMunro Jul 27, 2019
2717565
Update src/System.Management.Automation/engine/MshCommandRuntime.cs
KirkMunro Jul 29, 2019
314bf05
Update src/System.Management.Automation/engine/MshCommandRuntime.cs
KirkMunro Jul 29, 2019
9ee62ec
Update src/System.Management.Automation/engine/MshCommandRuntime.cs
KirkMunro Jul 29, 2019
84a6eb1
Update src/System.Management.Automation/engine/MshCommandRuntime.cs
KirkMunro Jul 29, 2019
9f50c65
Update src/System.Management.Automation/engine/MshCommandRuntime.cs
KirkMunro Jul 29, 2019
3dfb20f
remove file that is auto-generated
KirkMunro Jul 29, 2019
de65104
Merge branch 'normalize-common-parameters' of https://github.com/Kirk…
KirkMunro Jul 29, 2019
4531f36
Update test/powershell/Modules/Microsoft.PowerShell.Utility/Write-Str…
KirkMunro Jul 29, 2019
5b101c6
Merge branch 'normalize-common-parameters' of https://github.com/Kirk…
KirkMunro Jul 29, 2019
a0e6e7f
review updates
KirkMunro Jul 29, 2019
d78f5bf
sort common parameter usage
KirkMunro Jul 29, 2019
527e209
update tests to support what works now
KirkMunro Jul 29, 2019
4440334
update tests
KirkMunro Aug 5, 2019
12b00d0
Merge branch 'master' into normalize-common-parameters
KirkMunro Aug 5, 2019
cbc54e5
fix Pester test that fails due to bug in PS
KirkMunro Aug 5, 2019
716cc35
Merge branch 'master' into normalize-common-parameters
KirkMunro Aug 5, 2019
cde7ed2
Merge branch 'master' into normalize-common-parameters
KirkMunro Aug 15, 2019
20c96c0
add PSNewCommonParameters experimental feature
KirkMunro Aug 16, 2019
d38e481
CodeFactor changes
KirkMunro Aug 16, 2019
288e22d
fix Pester tests to work with experimental common params
KirkMunro Aug 16, 2019
497ab2b
Merge branch 'master' into normalize-common-parameters
KirkMunro Aug 19, 2019
c9fda28
merge master
KirkMunro Aug 23, 2019
4c635b7
merge master
KirkMunro Sep 6, 2019
9fda03f
move ActionPreference.Ignore fix to #10317
KirkMunro Sep 6, 2019
82b638d
merge master
KirkMunro Sep 9, 2019
d166fb5
add missing `Suspend` preference check
KirkMunro Sep 9, 2019
b04dd8a
merge master
KirkMunro Oct 4, 2019
aae169b
move ia alias change to another pr
KirkMunro Oct 4, 2019
de32dd5
Merge branch 'master' into normalize-common-parameters
KirkMunro Oct 11, 2019
8d29bc0
code review changes
KirkMunro Oct 11, 2019
a458143
more code review changes
KirkMunro Oct 11, 2019
18f19bf
add comments; rename fields; minor refactoring
KirkMunro Oct 11, 2019
ff1489b
add Pester test
KirkMunro Oct 12, 2019
c068c80
Merge branch 'master' into normalize-common-parameters
KirkMunro Oct 12, 2019
169d822
Merge branch 'master' into normalize-common-parameters
KirkMunro Oct 13, 2019
4f00c1b
merge master
KirkMunro Oct 23, 2019
c3b1932
merge master
KirkMunro Jun 14, 2020
2223f38
merge master
KirkMunro Jul 10, 2020
4ba4626
undo accidental search replace
KirkMunro Jul 10, 2020
d196fe5
Merge branch 'master' into normalize-common-parameters
KirkMunro Jul 15, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2727,7 +2727,22 @@ private string GenerateCertificateThumbprintParameter()

KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
TravisEz13 marked this conversation as resolved.
Show resolved Hide resolved
$clientSideParameters = @{}

$parametersToLeaveRemote = 'ErrorAction', 'WarningAction', 'InformationAction'
$parametersToLeaveRemote = if (!$EnabledExperimentalFeatures.Contains('PSNewCommonParameters')) {
@(
'ErrorAction'
'InformationAction'
'WarningAction'
)
} else {
@(
'DebugAction'
'ErrorAction'
'InformationAction'
'ProgressAction'
'VerboseAction'
'WarningAction'
)
}

Modify-PSImplicitRemotingParameters $clientSideParameters $PSBoundParameters 'AsJob'
if ($proxyForCmdlet)
Expand Down
47 changes: 22 additions & 25 deletions src/Microsoft.PowerShell.Security/security/CertificateProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@
#if !UNIX

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Internal;
using Runspaces = System.Management.Automation.Runspaces;
using Dbg = System.Management.Automation;
using Security = System.Management.Automation.Security;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections;
using System.Runtime.InteropServices;
using System.Management.Automation.Provider;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Globalization;
using System.IO;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Xml;
using System.Xml.XPath;
using System.Security;
using DWORD = System.UInt32;
using Runspaces = System.Management.Automation.Runspaces;
using Security = System.Management.Automation.Security;
using Sma = System.Management.Automation;

namespace Microsoft.PowerShell.Commands
{
Expand Down Expand Up @@ -1188,7 +1188,7 @@ protected override void GetItem(string path)
// satisfies the filter, output it. Otherwise, don't.

X509Certificate2 cert = item as X509Certificate2;
Dbg.Diagnostics.Assert(cert != null, "item should be a certificate");
Sma.Diagnostics.Assert(cert != null, "item should be a certificate");

// If it's Win8 or above, filter matching for certain properties is done by
// the certificate enumeration filter at the API level. In that case,
Expand Down Expand Up @@ -1299,17 +1299,14 @@ private void AttemptToImportPkiModule()

try
{
System.Management.Automation.PowerShell ps = null;
ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)
.AddCommand(importModuleCommand)
.AddParameter("Name", moduleName)
.AddParameter("Scope", StringLiterals.Global)
.AddParameter("ErrorAction", ActionPreference.Ignore)
.AddParameter("WarningAction", ActionPreference.Ignore)
.AddParameter("InformationAction", ActionPreference.Ignore)
.AddParameter("Verbose", false)
.AddParameter("Debug", false);
ps.Invoke();
using (var ps = Sma.PowerShell.Create(RunspaceMode.CurrentRunspace))
{
ps.AddCommand(importModuleCommand)
.AddParameter("Name", moduleName)
.AddParameter("Scope", StringLiterals.Global)
.IgnoreMessageStreamParameters()
.Invoke();
}
}
catch (Exception)
{
Expand Down Expand Up @@ -2683,7 +2680,7 @@ private static object GetCachedItem(string path)
if (s_pathCache.ContainsKey(path))
{
item = s_pathCache[path];
Dbg.Diagnostics.Assert(item != null, "GetCachedItem");
Sma.Diagnostics.Assert(item != null, "GetCachedItem");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ internal static IEnumerable<ExtendedTypeDefinition> GetFormatData()
"System.Management.Automation.InformationRecord",
ViewsOf_System_Management_Automation_InformationRecord());

yield return new ExtendedTypeDefinition(
"System.Management.Automation.ProgressRecord",
ViewsOf_System_Management_Automation_ProgressRecord());

yield return new ExtendedTypeDefinition(
"System.Exception",
ViewsOf_System_Exception());
Expand Down Expand Up @@ -1248,6 +1252,29 @@ private static IEnumerable<FormatViewDefinition> ViewsOf_System_Management_Autom
.EndControl());
}

private static IEnumerable<FormatViewDefinition> ViewsOf_System_Management_Automation_ProgressRecord()
{
// This generates string output that uses the following format:
// PROGRESS: [<PercentComplete>% - ]<Activity>[: <StatusDescription>][ (<CurrentOperation>)]
// Activity is always shown.
// Items in square brackets are conditional, so:
// - PercentComplete only shows up if it is set, and uses a format like this: " 83% -"
// - StatusDescription is only shown if it is not "Processing"
// - CurrentOperation is only shown if it is not null or empty
// The end result is a string that might look something like any of the following examples:
// PROGRESS: Initializing...
// PROGRESS: 57% - Creating user: 57 of 100 (Initializing home directory)
// PROGRESS: 100% - Task finished
yield return new FormatViewDefinition(
"ProgressRecord",
CustomControl
.Create(outOfBand: true)
.StartEntry()
.AddScriptBlockExpressionBinding($@"'{FormatStrings.ProgressFormatString}' -f ""$(if ($_.PercentComplete -ge 0) {{'{{0,3}}% - ' -f $_.PercentComplete}})$($_.Activity)$(if ($_.StatusDescription -ne '{FormatStrings.Processing}') {{"": $($_.StatusDescription)""}})$(if ($_.CurrentOperation) {{"" ($($_.CurrentOperation))""}})""")
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
KirkMunro marked this conversation as resolved.
Show resolved Hide resolved
.EndEntry()
.EndControl());
}

private static IEnumerable<FormatViewDefinition> ViewsOf_System_Exception()
{
yield return new FormatViewDefinition("Exception",
Expand Down
21 changes: 9 additions & 12 deletions src/System.Management.Automation/engine/CommandDiscovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -919,20 +919,17 @@ internal static Collection<PSModuleInfo> AutoloadSpecifiedModule(string moduleNa

discoveryTracer.WriteLine("Attempting to load module: {0}", moduleName);

PowerShell ps = null;
try
{
ps = PowerShell.Create(RunspaceMode.CurrentRunspace)
.AddCommand(importModuleCommand)
.AddParameter("Name", moduleName)
.AddParameter("Scope", StringLiterals.Global)
.AddParameter("PassThru")
.AddParameter("ErrorAction", ActionPreference.Ignore)
.AddParameter("WarningAction", ActionPreference.Ignore)
.AddParameter("InformationAction", ActionPreference.Ignore)
.AddParameter("Verbose", false)
.AddParameter("Debug", false);
matchingModules = (Collection<PSModuleInfo>)ps.Invoke<PSModuleInfo>();
using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
ps.AddCommand(importModuleCommand)
.AddParameter("Name", moduleName)
.AddParameter("Scope", StringLiterals.Global)
.AddParameter("PassThru")
.IgnoreMessageStreamParameters();
matchingModules = ps.Invoke<PSModuleInfo>();
}
}
catch (Exception e)
{
Expand Down
104 changes: 104 additions & 0 deletions src/System.Management.Automation/engine/CommonCommandParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,40 @@ public ActionPreference WarningAction
set { _commandRuntime.WarningPreference = value; }
}

/// <summary>
/// Gets or sets the value of the VerboseAction parameter for the cmdlet.
/// </summary>
/// <remarks>
/// This parameter tells the command what to do when a verbose record
/// occurs.
/// </remarks>
[Experimental("PSNewCommonParameters", ExperimentAction.Show)]
[Parameter]
[Alias("va")]
public ActionPreference VerboseAction
{
get { return _commandRuntime.VerbosePreference; }

set { _commandRuntime.VerbosePreference = value; }
}

/// <summary>
/// Gets or sets the value of the DebugAction parameter for the cmdlet.
/// </summary>
/// <remarks>
/// This parameter tells the command what to do when a debug record
/// occurs.
/// </remarks>
[Experimental("PSNewCommonParameters", ExperimentAction.Show)]
[Parameter]
[Alias("da")]
public ActionPreference DebugAction
{
get { return _commandRuntime.DebugPreference; }

set { _commandRuntime.DebugPreference = value; }
}

/// <summary>
/// Gets or sets the value of the InformationAction parameter for the cmdlet.
/// </summary>
Expand All @@ -123,6 +157,22 @@ public ActionPreference InformationAction
set { _commandRuntime.InformationPreference = value; }
}

/// <summary>
/// Gets or sets the value of the ProgressAction parameter for the cmdlet.
/// </summary>
/// <remarks>
/// This parameter tells the command what to do when an progress record occurs.
/// </remarks>
[Experimental("PSNewCommonParameters", ExperimentAction.Show)]
[Parameter]
[Alias("pra")]
public ActionPreference ProgressAction
{
get { return _commandRuntime.ProgressPreference; }

set { _commandRuntime.ProgressPreference = value; }
}

/// <summary>
/// Gets or sets the value of the ErrorVariable parameter for the cmdlet.
/// </summary>
Expand Down Expand Up @@ -161,6 +211,42 @@ public string WarningVariable
set { _commandRuntime.WarningVariable = value; }
}

/// <summary>
/// Gets or sets the value of the VerboseVariable parameter for the cmdlet.
/// </summary>
/// <remarks>
/// This parameter tells the command which variable to populate with verbose messages.
/// Use +varname to append to the variable rather than clearing it.
/// </remarks>
[Experimental("PSNewCommonParameters", ExperimentAction.Show)]
[Parameter]
[Alias("vv")]
[ValidateVariableName]
public string VerboseVariable
{
get { return _commandRuntime.VerboseVariable; }

set { _commandRuntime.VerboseVariable = value; }
}

/// <summary>
/// Gets or sets the value of the DebugVariable parameter for the cmdlet.
/// </summary>
/// <remarks>
/// This parameter tells the command which variable to populate with debug messages.
/// Use +varname to append to the variable rather than clearing it.
/// </remarks>
[Experimental("PSNewCommonParameters", ExperimentAction.Show)]
[Parameter]
[Alias("dv")]
[ValidateVariableName]
public string DebugVariable
{
get { return _commandRuntime.DebugVariable; }

set { _commandRuntime.DebugVariable = value; }
}

/// <summary>
/// Gets or sets the value of the InformationVariable parameter for the cmdlet.
/// </summary>
Expand All @@ -178,6 +264,24 @@ public string InformationVariable
set { _commandRuntime.InformationVariable = value; }
}

/// <summary>
/// Gets or sets the value of the ProgressVariable parameter for the cmdlet.
/// </summary>
/// <remarks>
/// This parameter tells the command which variable to populate with progress messages.
/// Use +varname to append to the variable rather than clearing it.
/// </remarks>
[Experimental("PSNewCommonParameters", ExperimentAction.Show)]
[Parameter]
[Alias("prv")]
[ValidateVariableName]
public string ProgressVariable
{
get { return _commandRuntime.ProgressVariable; }

set { _commandRuntime.ProgressVariable = value; }
}

/// <summary>
/// Gets or sets the OutVariable parameter for the cmdlet.
/// </summary>
Expand Down
14 changes: 14 additions & 0 deletions src/System.Management.Automation/engine/ExecutionContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,20 @@ internal ActionPreference InformationActionPreferenceVariable
}
}

internal ActionPreference ProgressActionPreferenceVariable
{
get => GetEnumPreference(
SpecialVariables.ProgressPreferenceVarPath,
InitialSessionState.defaultProgressPreference,
out _);

set => EngineSessionState.SetVariable(
SpecialVariables.ProgressPreferenceVarPath,
LanguagePrimitives.ConvertTo(value, typeof(ActionPreference), CultureInfo.InvariantCulture),
true,
CommandOrigin.Internal);
}

internal object WhatIfPreferenceVariable
{
get
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ static ExperimentalFeature()
new ExperimentalFeature(
name: "PSForEachObjectParallel",
description: "New parameter set for ForEach-Object to run script blocks in parallel"),
new ExperimentalFeature(
name: "PSNewCommonParameters",
description: "New -DebugAction, -DebugVariable, -ProgressAction, -ProgressVariable, -VerboseAction, and -VerboseVariable common parameters"),
new ExperimentalFeature(
name: "PSTernaryOperator",
description: "Support the ternary operator in PowerShell language"),
Expand Down
18 changes: 8 additions & 10 deletions src/System.Management.Automation/engine/Modules/AnalysisCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -593,16 +593,14 @@ private static void CallGetModuleDashList(ExecutionContext context, string modul

try
{
PowerShell.Create(RunspaceMode.CurrentRunspace)
.AddCommand(getModuleCommand)
.AddParameter("List", true)
.AddParameter("ErrorAction", ActionPreference.Ignore)
.AddParameter("WarningAction", ActionPreference.Ignore)
.AddParameter("InformationAction", ActionPreference.Ignore)
.AddParameter("Verbose", false)
.AddParameter("Debug", false)
.AddParameter("Name", modulePath)
.Invoke();
using (var ps = PowerShell.Create(RunspaceMode.CurrentRunspace))
{
ps.AddCommand(getModuleCommand)
.AddParameter("List", true)
.AddParameter("Name", modulePath)
.IgnoreMessageStreamParameters()
.Invoke();
}
}
catch (Exception e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,12 @@ private static void HandleErrorFromPipeline(Cmdlet cmdlet, ErrorRecord errorReco
CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "InformationAction");
CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "Verbose");
CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "Debug");
if (ExperimentalFeature.EnabledExperimentalFeatureNames.Contains("PSNewCommonParameters"))
Copy link
Contributor

Choose a reason for hiding this comment

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

This will break if the target remote session is an older version and does not support the new common parameters. We will need to update PowerShell remote encoding to support this only for target versions that implement the new common parameters. See:

dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.PowerShell, powerShell.ToPSObjectForRemoting()));

parametersAsListOfPSObjects.Add(parameter.ToPSObjectForRemoting());

internal PSObject ToPSObjectForRemoting()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @PaulHigin, I'll look into this.

I would also appreciate your thoughts on this comment from earlier, because taking that approach should allow us to deprecate -Verbose and -Debug (which will have questionable usefulness going forward with this change), while bringing their muscle memory and aliases forward, without breaking backwards compatibility, and it would be nice if we could replace -Verbose and -Debug to reduce unnecessary common parameters. That work could also be done independently, of course, but it is worth thinking about as part of this PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't fully understand the comment. Can you provide an example? But it sounds like a separate issue that should be discussed apart from these changes.

Copy link
Contributor Author

@KirkMunro KirkMunro Jul 20, 2020

Choose a reason for hiding this comment

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

It's really quite simple. Consider something you might do today, such as this:

Import-Module Microsoft.Graph -Verbose

That gives you verbose output that is generated during module import.

Once this PR is finalized/merged, you could do the same like this:

Import-Module -VerboseAction Continue

But the original syntax would work as well.

Where the question comes into play is this: do we need both -Verbose and -VerboseAction, or -Debug and -DebugAction?

The latter is necessary to allow you to properly handle those streams like any other stream. The former is "necessary" for backwards compatibility and muscle memory. My point was that it is possible to support both of these with a single parameter, which would treat a switch-like invocation as if you invoked the corresponding -*Action parameter with Continue.

i.e. Import-Module Microsoft.Graph -Verbose would be the exact same as invoking Import-Module Microsoft.Graph -VerboseAction Continue, by simply making the -VerboseAction parameter "switchable" (the generic type I said could be written). This approach would allow the -Verbose and -Debug parameters to be gracefully deprecated as superceded by -VerboseAction and -DebugAction, respectively.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another data point that could influence this: using -Verbose and -Debug is functionally different (in a bad way) than using a typical -*Action parameter. Why? Because of their implementation.

For example, this shows verbose output from Import-Module, which is expected:

Remove-Module MicrosoftTeams
# Turn off verbose messages by default
$VerbosePreference = [System.Management.Automation.ActionPreference]::SilentlyContinue
& {
    [CmdletBinding()]
    param()
    Write-Verbose 'Am I showing verbose output?'
    Import-Module MicrosoftTeams
} -Verbose

Unfortunately, so does this, which is unexpected:

Remove-Module MicrosoftTeams
# Turn on verbose messages by default
$VerbosePreference = [System.Management.Automation.ActionPreference]::Continue
& {
    [CmdletBinding()]
    param()
    Write-Verbose 'Am I showing verbose output?'
    Import-Module MicrosoftTeams
} -Verbose:$false

Why would Write-Verbose be influenced by the -Verbose common parameter in the calling scope, but not Import-Module? Maybe there is something else going on here, but I believe that this would be corrected by deprecating -Verbose and -Debug without breaking existing functionality by defining them such that they work as shorthand for -VerboseAction Continue and -DebugAction Continue, as described above.

{
CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "VerboseAction");
CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "DebugAction");
CopyParameterFromCmdletToPowerShell(cmdlet, powerShell, "ProgressAction");
}

var invocationSettings = new PSInvocationSettings { Host = cmdlet.Host };

Expand Down