Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -499,10 +499,10 @@ private void ParseHelper(string[] args)

if (!SpecialCharacters.IsDash(switchKey[0]) && switchKey[0] != '/')
{
// then its a command
// then its a file

--i;
ParseCommand(args, ref i, noexitSeen, false);
ParseFile(args, ref i, noexitSeen);
break;
}

Expand Down Expand Up @@ -620,126 +620,10 @@ private void ParseHelper(string[] args)
#endif
else if (MatchSwitch(switchKey, "file", "f"))
{
// Process file execution. We don't need to worry about checking -command
// since if -command comes before -file, -file will be treated as part
// of the script to evaluate. If -file comes before -command, it will
// treat -command as an argument to the script...

++i;
if (i >= args.Length)
if (!ParseFile(args, ref i, noexitSeen))
{
WriteCommandLineError(
CommandLineParameterParserStrings.MissingFileArgument,
showHelp: true,
showBanner: true);
break;
}

// Don't show the startup banner unless -noexit has been specified.
if (!noexitSeen)
_showBanner = false;

// Process interactive input...
if (args[i] == "-")
{
// the arg to -file is -, which is secret code for "read the commands from stdin with prompts"

_explicitReadCommandsFromStdin = true;
_noPrompt = false;
}
else
{
// Exit on script completion unless -noexit was specified...
if (!noexitSeen)
_noExit = false;

// We need to get the full path to the script because it will be
// executed after the profiles are run and they may change the current
// directory.
string exceptionMessage = null;
try
{
// Normalize slashes
_file = args[i].Replace(StringLiterals.AlternatePathSeparator,
StringLiterals.DefaultPathSeparator);
_file = Path.GetFullPath(_file);
}
catch (Exception e)
{
// Catch all exceptions - we're just going to exit anyway so there's
// no issue of the system being destabilized.
exceptionMessage = e.Message;
}

if (exceptionMessage != null)
{
WriteCommandLineError(
string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidFileArgument, args[i], exceptionMessage),
showBanner: true);
break;
}

if (!Path.GetExtension(_file).Equals(".ps1", StringComparison.OrdinalIgnoreCase))
{
WriteCommandLineError(
string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidFileArgumentExtension, args[i]),
showBanner: true);
break;
}

if (!System.IO.File.Exists(_file))
{
WriteCommandLineError(
string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.ArgumentFileDoesNotExist, args[i]),
showBanner: true);
break;
}

i++;

Regex argPattern = new Regex(@"^.\w+\:", RegexOptions.CultureInvariant);
string pendingParameter = null;

// Accumulate the arguments to this script...
while (i < args.Length)
{
string arg = args[i];

// If there was a pending parameter, add a named parameter
// using the pending parameter and current argument
if (pendingParameter != null)
{
_collectedArgs.Add(new CommandParameter(pendingParameter, arg));
pendingParameter = null;
}
else if (!string.IsNullOrEmpty(arg) && SpecialCharacters.IsDash(arg[0]))
{
Match m = argPattern.Match(arg);
if (m.Success)
{
int offset = arg.IndexOf(':');
if (offset == arg.Length - 1)
{
pendingParameter = arg.TrimEnd(':');
}
else
{
_collectedArgs.Add(new CommandParameter(arg.Substring(0, offset), arg.Substring(offset + 1)));
}
}
else
{
_collectedArgs.Add(new CommandParameter(arg));
}
}
else
{
_collectedArgs.Add(new CommandParameter(null, arg));
}
++i;
}
}
break;
}
#if DEBUG
// this option is useful when debugging ConsoleHost remotely using VS remote debugging, as you can only
Expand Down Expand Up @@ -858,10 +742,10 @@ private void ParseHelper(string[] args)
#endif
else
{
// The first parameter we fail to recognize marks the beginning of the command string.
// The first parameter we fail to recognize marks the beginning of the file string.

--i;
if (!ParseCommand(args, ref i, noexitSeen, false))
if (!ParseFile(args, ref i, noexitSeen))
{
break;
}
Expand Down Expand Up @@ -967,6 +851,122 @@ private void ParseExecutionPolicy(string[] args, ref int i, ref string execution
executionPolicy = args[i];
}

private bool ParseFile(string[] args, ref int i, bool noexitSeen)
{
Copy link
Contributor

Choose a reason for hiding this comment

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

C# now supports local functions - that would make this a bit simpler because you wouldn't the parameters.

Copy link
Member Author

Choose a reason for hiding this comment

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

Making ParseFile a local function would make it inconsistent with similar methods like ParseCommand(), ParseFormat(), ParseExecutionPolicy(), etc...

// Process file execution. We don't need to worry about checking -command
// since if -command comes before -file, -file will be treated as part
// of the script to evaluate. If -file comes before -command, it will
// treat -command as an argument to the script...

++i;
if (i >= args.Length)
{
WriteCommandLineError(
CommandLineParameterParserStrings.MissingFileArgument,
showHelp: true,
showBanner: true);
return false;
}

// Don't show the startup banner unless -noexit has been specified.
if (!noexitSeen)
_showBanner = false;

// Process interactive input...
if (args[i] == "-")
{
// the arg to -file is -, which is secret code for "read the commands from stdin with prompts"

_explicitReadCommandsFromStdin = true;
_noPrompt = false;
}
else
{
// Exit on script completion unless -noexit was specified...
if (!noexitSeen)
_noExit = false;

// We need to get the full path to the script because it will be
// executed after the profiles are run and they may change the current
// directory.
string exceptionMessage = null;
try
{
// Normalize slashes
_file = args[i].Replace(StringLiterals.AlternatePathSeparator,
StringLiterals.DefaultPathSeparator);
_file = Path.GetFullPath(_file);
}
catch (Exception e)
{
// Catch all exceptions - we're just going to exit anyway so there's
// no issue of the system being destabilized.
exceptionMessage = e.Message;
}

if (exceptionMessage != null)
{
WriteCommandLineError(
string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.InvalidFileArgument, args[i], exceptionMessage),
showBanner: true);
return false;
}

if (!System.IO.File.Exists(_file))
{
WriteCommandLineError(
string.Format(CultureInfo.CurrentCulture, CommandLineParameterParserStrings.ArgumentFileDoesNotExist, args[i]),
showBanner: true);
return false;
}

i++;

Regex argPattern = new Regex(@"^.\w+\:", RegexOptions.CultureInvariant);
string pendingParameter = null;

// Accumulate the arguments to this script...
while (i < args.Length)
{
string arg = args[i];

// If there was a pending parameter, add a named parameter
// using the pending parameter and current argument
if (pendingParameter != null)
{
_collectedArgs.Add(new CommandParameter(pendingParameter, arg));
pendingParameter = null;
}
else if (!string.IsNullOrEmpty(arg) && SpecialCharacters.IsDash(arg[0]))
{
Match m = argPattern.Match(arg);
if (m.Success)
{
int offset = arg.IndexOf(':');
if (offset == arg.Length - 1)
{
pendingParameter = arg.TrimEnd(':');
}
else
{
_collectedArgs.Add(new CommandParameter(arg.Substring(0, offset), arg.Substring(offset + 1)));
}
}
else
{
_collectedArgs.Add(new CommandParameter(arg));
}
}
else
{
_collectedArgs.Add(new CommandParameter(null, arg));
}
++i;
}
}
return true;
}

private bool ParseCommand(string[] args, ref int i, bool noexitSeen, bool isEncoded)
{
if (_commandLineCommand != null)
Expand Down
12 changes: 11 additions & 1 deletion src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1820,7 +1820,17 @@ private void DoRunspaceInitialization(bool importSystemModules, bool skipProfile
s_tracer.WriteLine("running -file '{0}'", filePath);

Pipeline tempPipeline = exec.CreatePipeline();
Command c = new Command(filePath, false, false);
Command c;
// if file doesn't have .ps1 extension, we read the contents and treat it as a script to support shebang with no .ps1 extension usage
if (!Path.GetExtension(filePath).Equals(".ps1", StringComparison.OrdinalIgnoreCase))
{
string script = File.ReadAllText(filePath);
c = new Command(script, isScript: true, useLocalScope: false);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this set the exit code correctly? You don't have a test - you should add one as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will add test

else
{
c = new Command(filePath, false, false);
}
tempPipeline.Commands.Add(c);

if (initialCommandArgs != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ Copyright (C) Microsoft Corporation. All rights reserved.</value>
[-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
[-WindowStyle &lt;style&gt;] [-EncodedCommand &lt;Base64EncodedCommand&gt;]
[-ConfigurationName &lt;string&gt;]
[-File &lt;filePath&gt; &lt;args&gt;] [-ExecutionPolicy &lt;ExecutionPolicy&gt;]
[-Command { - | &lt;script-block&gt; [-args &lt;arg-array&gt;]
| &lt;string&gt; [&lt;CommandParameters&gt;] } ]
[-File &lt;filePath&gt; &lt;args&gt;] [-ExecutionPolicy &lt;ExecutionPolicy&gt;]

PowerShell[.exe] -Help | -? | /?

Expand Down Expand Up @@ -237,6 +237,7 @@ EXAMPLES
PowerShell -ConfigurationName AdminRoles
PowerShell -Command {Get-EventLog -LogName security}
PowerShell -Command "&amp; {Get-EventLog -LogName security}"
PowerShell HelloWorld.ps1

# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
Expand Down
Loading