Merge remote-tracking branch 'refs/remotes/PowerShell/master'

This commit is contained in:
Aleksandar Nikolic committed 2016-07-17 00:05:35 +02:00
commit 5aefd5616a
51 files changed
+1622 -1023

No files matched your search

+27 -13
View File
@@ -57,16 +57,39 @@ output will *not* have a runtime identifier in the path.
Thus the output location of `powershell.exe` will be Thus the output location of `powershell.exe` will be
`./src/Microsoft.PowerShell.ConsoleHost/bin/Debug/net451/powershell.exe` `./src/Microsoft.PowerShell.ConsoleHost/bin/Debug/net451/powershell.exe`
While building is easy, running FullCLR version is not as simple as Build manually
CoreCLR version. ==============
The build contains the following steps:
- generating Visual Studio project: `cmake`
- building `powershell.exe` from generated solution: `msbuild
powershell.sln`
- building managed DLLs: `dotnet publish --runtime net451`
What I can do with the produced binaries?
=========================================
Creating a deployable package out of them is **not a supported scenario**.
The reason why we are building these binaries is
we have components (i.e. workflows) that are not currently available in the CoreClr version.
We want to make sure that CoreClr PowerShell changes don't introduce regressions in FullClr PowerShelll.
It's possible to run (for test purposes) the dev version of these binaries as follows.
Running Dev version of FullClr PowerShell
-----------------------------------------
Running FullCLR version is not as simple as CoreCLR version.
If you just run `./powershell.exe`, you will get a `powershell` If you just run `./powershell.exe`, you will get a `powershell`
process, but all the interesting DLLs (such as process, but all the interesting DLLs (such as
`System.Management.Automation.dll`) would be loaded from the Global `System.Management.Automation.dll`) would be loaded from the Global
Assembly Cache (GAC), not your output directory. Assembly Cache (GAC), not your output directory.
[@lzybkr](https://github.com/lzybkr) wrote a module to deal with it Use `Start-DevPowerShell` helper funciton, to workaround it with `$env:DEVPATH`
and run side-by-side.
```powershell ```powershell
Start-DevPowerShell Start-DevPowerShell
@@ -88,12 +111,3 @@ Start-DevPowerShell -binDir (Split-Path -Parent (Get-PSOutput))
The default for produced `powershell.exe` is x64. The default for produced `powershell.exe` is x64.
You can control it with `Start-PSBuild -FullCLR -NativeHostArch x86` You can control it with `Start-PSBuild -FullCLR -NativeHostArch x86`
Build manually
==============
The build contains the following steps:
- generating Visual Studio project: `cmake`
- building `powershell.exe` from generated solution: `msbuild
powershell.sln`
- building managed DLLs: `dotnet publish --runtime net451`
@@ -1,7 +1,7 @@
Debugging in PowerShell Command-line Debugging in PowerShell Command-line
===== =====
As we know we can debug PowerShell code via GUI tools like [VS Code](./using-vscode.md#debugging-with-vs-code) or [ISE](./using-ise.md#debugging-with-ise). In addition we can directly perform debugging within the PowerShell command-line session by using the PowerShell debugger cmdlets. This document demonstrates how to use the cmdlets for the PowerShell command-line debugging. We will cover two topics: set a debug breakpoint on a line of code and on a variable. As we know, we can debug PowerShell code via GUI tools like [VS Code](./using-vscode.md#debugging-with-vs-code) or [ISE](./using-ise.md#debugging-with-ise). In addition, we can directly perform debugging within the PowerShell command-line session by using the PowerShell debugger cmdlets. This document demonstrates how to use the cmdlets for the PowerShell command-line debugging. We will cover the following topics: setting a debug breakpoint on a line of code and on a variable.
Let's use the following code snippet as our sample script. Let's use the following code snippet as our sample script.
@@ -21,17 +21,17 @@ Write-Host "$result Celsius"
``` ```
**1. Set a Breakpoint on a Line** **1. Setting a Breakpoint on a Line**
- Open a [PowerShell editor](learning-powershell.md#powershell-editor) - Open a [PowerShell editor](learning-powershell.md#powershell-editor)
- Save the above code snippet to a file, let's say "test.ps1" - Save the above code snippet to a file. For example, "test.ps1"
- Go to your command-line PowerShell - Go to your command-line PowerShell
- Clear existing breakpoints if any - Clear existing breakpoints if any
```PowerShell ```PowerShell
PS /home/jen/debug>Get-PSBreakpoint | Remove-PSBreakpoint PS /home/jen/debug>Get-PSBreakpoint | Remove-PSBreakpoint
``` ```
- Use **Set-PSBreakpoint** cmdlet to set a debug breakpoint, say set it to line 5 - Use **Set-PSBreakpoint** cmdlet to set a debug breakpoint. In this case, we will set it to line 5
```PowerShell ```PowerShell
PS /home/jen/debug>Set-PSBreakpoint -Line 5 -Script ./test.ps1 PS /home/jen/debug>Set-PSBreakpoint -Line 5 -Script ./test.ps1
@@ -40,7 +40,7 @@ ID Script Line Command Variable Action
-- ------ ---- ------- -------- ------ -- ------ ---- ------- -------- ------
0 test.ps1 5 0 test.ps1 5
``` ```
- Run the script, test.ps1. As we have set a breakpoint, it is expected the program will break into the debugger at the line 5. - Run the script "test.ps1". As we have set a breakpoint, it is expected the program will break into the debugger at the line 5.
```PowerShell ```PowerShell
@@ -54,10 +54,10 @@ At /home/jen/debug/test.ps1:5 char:1
[DBG]: PS /home/jen/debug>> [DBG]: PS /home/jen/debug>>
``` ```
- The PowerShell prompt has been changed to **[DBG]: PS /home/jen/debug>>** as you may noticed. This means - The PowerShell prompt now has the prefix **[DBG]:** as you may noticed. This means
we have entered into the debug mode. To watch the variables like $celsius, simply type $celsius as below. we have entered into the debug mode. To watch the variables like $celsius, simply type **$celsius** as below.
- To exit from the debugging, type **"q"** - To exit from the debugging, type **q**
- To get help for the debugging commands, simple type **"?"** - To get help for the debugging commands, simply type **?**. The following is an example of debugging output.
```PowerShell ```PowerShell
[DBG]: PS /home/jen/debug>> $celsius [DBG]: PS /home/jen/debug>> $celsius
@@ -103,13 +103,13 @@ PS /home/jen/debug>
``` ```
**2. Set a Breakpoint on a Variable** **2. Setting a Breakpoint on a Variable**
- Clear existing breakpoints if any - Clear existing breakpoints if there are any
```PowerShell ```PowerShell
PS /home/jen/debug>Get-PSBreakpoint | Remove-PSBreakpoint PS /home/jen/debug>Get-PSBreakpoint | Remove-PSBreakpoint
``` ```
- Use **Set-PSBreakpoint** cmdlet to set a debug breakpoint, say set it to line 5 - Use **Set-PSBreakpoint** cmdlet to set a debug breakpoint. In this case, we set it to line 5
```PowerShell ```PowerShell
@@ -117,10 +117,10 @@ PS /home/jen/debug>
``` ```
- Run the script, test.ps1. - Run the script "test.ps1"
Once hit the debug breakpoint, we can type **l** to list the source code that debugger is currently executing. As we can see line 3 has an asterisk at the front, meaning that's the line the program is currently executing and broke into the debugger as illustrated below. Once hit the debug breakpoint, we can type **l** to list the source code that debugger is currently executing. As we can see line 3 has an asterisk at the front, meaning that's the line the program is currently executing and broke into the debugger as illustrated below.
- Type **q** to exit from the debugging mode - Type **q** to exit from the debugging mode. The following is an example of debugging output.
```PowerShell ```PowerShell
@@ -165,7 +165,7 @@ PS /home/jen/debug>
``` ```
Now you know the basics of the PowerShell debugging from PowerShell command-line. For further learning read the following articles. Now you know the basics of the PowerShell debugging from PowerShell command-line. For further learning, read the following articles.
More Reading More Reading
@@ -11,11 +11,18 @@ First you need to launch a PowerShell session by following the [Installing Power
Getting Familiar with PowerShell Commands Getting Familiar with PowerShell Commands
--- ---
In this section, you will learn how to
- create a file, delete a file and change file directory
- find syntax of PowerShell cmdlets
- get help if you needed
- discover what version of PowerShell you are currently using
- exit a PowerShell session
- and more
As mentioned above PowerShell commands is designed to have Verb-Noun structure, for instance Get-Process, Set-Location, Clear-Host, etc. Let’s exercise some of the basic PowerShell commands also known as **cmdlets**. As mentioned above, PowerShell commands is designed to have Verb-Noun structure, for instance Get-Process, Set-Location, Clear-Host, etc. Let’s exercise some of the basic PowerShell commands, also known as **cmdlets**.
Please note that we will use the PowerShell prompt sign **PS />** in the following examples as it shows on Linux. Please note that we will use the PowerShell prompt sign **PS />** as it appears on Linux in the following examples.
It looks like **PS C:\>** on Windows. It is shown as **PS C:\\>** on Windows.
**1. Get-Process**: displays the processes running on your system. **1. Get-Process**: displays the processes running on your system.
@@ -88,7 +95,7 @@ PS /> cls
PS /> Set-Location /home PS /> Set-Location /home
PS /home> PS /home>
``` ```
**5. ls or dir - Get-ChildItem**: list all items in the specified location **5. dir - Get-ChildItem**: list all items in the specified location
```PowerShell ```PowerShell
Get all files under the current directory: Get all files under the current directory:
@@ -119,10 +126,10 @@ Mode LastWriteTime Length Name
---- ------------- ------ ---- ---- ------------- ------ ----
-a---- 7/7/2016 7:17 PM 0 test.ps1 -a---- 7/7/2016 7:17 PM 0 test.ps1
``` ```
You can use the **-value** parameter to add some data to your file. For example, the following command adds the phrase "Write-Host 'Hello There'" as a file content to the test.ps1. Because the test.txt file exists already, we use **-force** parameter to replace the existing content. You can use the **-Value** parameter to add some data to your file. For example, the following command adds the phrase "Write-Host 'Hello There'" as a file content to the test.ps1. Because the test.ps1 file exists already, we use **-Force** parameter to replace the existing content.
```PowerShell ```PowerShell
PS /home/jen> New-Item -Path ./test.ps1 -Value "Write-Host 'hello there'" -force PS /home/jen> New-Item -Path ./test.ps1 -Value "Write-Host 'hello there'" -Force
Directory: /home/jen Directory: /home/jen
@@ -132,7 +139,7 @@ Mode LastWriteTime Length Name
-a---- 7/7/2016 7:19 PM 24 test.ps1 -a---- 7/7/2016 7:19 PM 24 test.ps1
``` ```
There are other ways to add some data to a file, for example, you can use Set-Content to set the file contents: There are other ways to add some data to a file. For example, you can use Set-Content to set the file contents:
```PowerShell ```PowerShell
PS /home/jen>Set-Content -Path ./test.ps1 -Value "Write-Host 'hello there again!'" PS /home/jen>Set-Content -Path ./test.ps1 -Value "Write-Host 'hello there again!'"
@@ -162,19 +169,34 @@ This cmdlet will delete the file /home/jen/test.ps1:
```PowerShell ```PowerShell
PS /home/jen> Remove-Item ./test.ps1 PS /home/jen> Remove-Item ./test.ps1
``` ```
**9. Exit**: - to exit the PowerShell session, type "exit"
**9. $PSVersionTable**: displays the version of PowerShell you are currently using
Type **$PSVersionTable** in your PowerShell session, you will see something like below. "PSVersion" indicates the
PowerShell version that you are using.
```PowerShell
Name Value
---- -----
PSVersion 5.1.10032.0
PSEdition Linux
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 3.0.0.0
CLRVersion
WSManStackVersion 1.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
```
**10. Exit**: to exit the PowerShell session, type "exit"
```PowerShell ```PowerShell
PS /home/jen> exit PS /home/jen> exit
``` ```
Need Help? Need Help?
---- ----
The most important command in PowerShell is possibly the Get-Help, which allows you to quickly learn PowerShell without having to surfing around the Internet. The Get-Help cmdlet also shows you how PowerShell commands work with examples. The most important command in PowerShell is possibly the Get-Help, which allows you to quickly learn PowerShell without having to surf around the Internet. The Get-Help cmdlet also shows you how PowerShell commands work with examples.
PS />**Get-Help**
You can use this cmdlet to get help with any PowerShell commands.
PS />**Get-Help -Name Get-Process** PS />**Get-Help -Name Get-Process**
@@ -184,14 +206,14 @@ It shows the syntax and other technical information of the Get-Process cmdlet.
PS />**Get-Help -Name Get-Process -Examples** PS />**Get-Help -Name Get-Process -Examples**
It displays the examples how to use the Get-Process cmdlet. It displays the examples how to use the Get-Process cmdlet.
If you use **-full** parameter, i.e., "Get-Help -Name Get-Process -Full", it will display more technical information. If you use **-Full** parameter, i.e., "Get-Help -Name Get-Process -Full", it will display more technical information.
Discover All Commands Available on Your System Discover All Commands Available on Your System
---- ----
You want to discover what PowerShell cmdlets available on your system. Simple, just run "Get-Command" as below. You want to discover what PowerShell cmdlets available on your system? Simple, just run "Get-Command" as below.
PS /> **Get-Command** PS /> **Get-Command**
@@ -203,14 +225,14 @@ If you want to know the syntax of Get-Process cmdlet, type
PS /> **Get-Command Get-Process -Syntax** PS /> **Get-Command Get-Process -Syntax**
If you want to know how to sue the get-process, type If you want to know how to use the Get-Process, type
PS /> **Get-Help Get-Process -example** PS /> **Get-Help Get-Process -Example**
PowerShell Pipeline '|' PowerShell Pipeline '|'
---- ----
Sometimes when you run Get-ChildItem or "dir", you want to get a list of files in a descending order. To archive that, type: Sometimes when you run Get-ChildItem or "dir", you want to get a list of files in a descending order. To achieve that, type:
```PowerShell ```PowerShell
PS /home/jen> dir | sort -Descending PS /home/jen> dir | sort -Descending
``` ```
@@ -229,10 +251,10 @@ Mode LastWriteTime Length Name
``` ```
How to Create and Run PowerShell scripts How to Create and Run PowerShell scripts
---- ----
- You can use ISE, VS Code, or any favorite editor to create a PowerShell script and save the script with a .ps1 file extension (helloworld.ps1 in the example) - You can use ISE, VS Code or your favorite editor to create a PowerShell script and save the script with a .ps1 file extension (for example, helloworld.ps1)
- To run the script, cd to your current folder and type ./helloworld.ps1 - To run the script, cd to your current folder and type ./yourscript.ps1 (for example, ./helloworld.ps1).
See [Running PowerShell Scripts Is as Easy as 1-2-3] [run-ps] for more details. Note: if you are using Windows, make sure you set the PowerShell's execution policy to "RemoteSigned" in this case. See [Running PowerShell Scripts Is as Easy as 1-2-3] [run-ps] for more details.
[run-ps]:http://windowsitpro.com/powershell/running-powershell-scripts-easy-1-2-3 [run-ps]:http://windowsitpro.com/powershell/running-powershell-scripts-easy-1-2-3
+13 -13
View File
@@ -1,14 +1,14 @@
Using PowerShell Integrated Scripting Environment (ISE) Using PowerShell Integrated Scripting Environment (ISE)
==== ====
The PowerShell ISE works on Windows. If you are not using Windows, please see [Using VS Code](./using-vscode.md). The PowerShell ISE only works on Windows. If you are not using Windows, please see [Using VS Code](./using-vscode.md).
Editing with ISE Editing with ISE
--- ---
- Launch PowerShell ISE - Launch PowerShell ISE
* Press Windows Key -> type PowerShell ISE, click on PowerShell ISE to launch the ISE * Press Windows Key -> type "PowerShell ISE", click on PowerShell ISE to launch the ISE
- Create a new PowerShell Script - Create a new PowerShell Script
* Click on File -> New * Click on **File->New**
* Add a few lines of PowerShell scripts in your newly created file, for example, * Add a few lines of PowerShell code in your newly created file. In this case, we will use the following script snippet.
```PowerShell ```PowerShell
# Convert Fahrenheit to Celsius # Convert Fahrenheit to Celsius
@@ -25,21 +25,21 @@ Write-Host "$result Celsius"
``` ```
* **Note**: You can find more examples [here](http://examples.oreilly.com/9780596528492/). * **Note**: You can find more examples [here](http://examples.oreilly.com/9780596528492/).
- Save the script file - To save the script file
* Click on File-> Save As -> type "helloworld.ps1" * Click on **File->Save As**. Then type "helloworld.ps1"
- Close the helloworld.ps1 - To close the helloworld.ps1 file
* File-> Close * **File->Close**
- Reopen the helloworld.ps1 - To reopen the helloworld.ps1 file
* File-> Open, then choose helloworld.ps1. * **File->Open**, then choose helloworld.ps1
- For more details, go to [How to Write and Run Scripts in the Windows PowerShell ISE](https://msdn.microsoft.com/en-us/powershell/scripting/core-powershell/ise/how-to-write-and-run-scripts-in-the-windows-powershell-ise). - For more details, go to [How to Write and Run Scripts in the Windows PowerShell ISE](https://msdn.microsoft.com/en-us/powershell/scripting/core-powershell/ise/how-to-write-and-run-scripts-in-the-windows-powershell-ise).
Debugging with ISE Debugging with ISE
---- ----
To execute the entire script file, you can press **F5**; to execute several lines of your scripts, simply select them and press **F8**. However sometimes you would like to stop the execution on a particular line in order to exam some variables to check if the program runs as expected. In that case, you may follow the steps below. Let's take the helloworld.ps1 as an example and assume line 17 is the place where you want to stop. To execute the entire script file, you can press **F5**. To execute several lines of your scripts, simply select them and press **F8**. If you would like to stop the execution on a particular line in order to examine some variables to check if the program runs as expected. In that case, you may follow the steps below. Let's take the helloworld.ps1 as an example and assume line 17 is the place where you want to stop.
- Set a break point: Move mouse over on the line 17, and press **F9**. You will see the line 17 is highlighted which means a breakpoint gets set. - Set a break point: Move mouse over on the line 17, and press **F9**. You will see the line 17 is highlighted, which means a breakpoint is set.
- Press **F5** to run the script - Press **F5** to run the script
- Enter 80 (or any number in Fahrenheit) from the command line prompt - Enter 80 (or any number in Fahrenheit) from the command line prompt
- Notice that the ISE output pane becomes “[DBG]: PS C:\Test>>” prompt. This means the program is in the debugging mode. It stops at Line 17: - Notice that the ISE output pane becomes “[DBG]: PS C:\Test>>” prompt. This means the program is in the debugging mode. It stops at Line 17:
@@ -52,7 +52,7 @@ Hit Line breakpoint on 'C:\test\helloword.ps1:17'
``` ```
- From the output pane, you can type $celsius and $fahrenheit to exam the values of these variables to see if they are correct. - From the output pane, you can type $celsius and $fahrenheit to examine the values of these variables to see if they are correct.
```PowerShell ```PowerShell
[DBG]: PS C:\Test>> $celsius [DBG]: PS C:\Test>> $celsius
+14 -13
View File
@@ -1,11 +1,11 @@
Using Visual Studio Code (VS Code) Using Visual Studio Code (VS Code)
==== ====
If you are working on Linux and OS X, you cannot use ISE because it is not supported on these platforms. In this case you can choose your favorite editor to write PowerShell scripts. Here we choose VS Code as a PowerShell editor as an example. If you are working on Linux and OS X, you cannot use ISE because it is not supported on these platforms. In this case, you can choose your favorite editor to write PowerShell scripts. Here we choose VS Code as a PowerShell editor as an example.
You can use VS Code on Windows with PowerShell V5 by using Windows 10 or by installing [Windows Management Framework 5.0 RTM](https://www.microsoft.com/en-us/download/details.aspx?id=50395) for down-level Windows OSs. You can use VS Code on Windows with PowerShell V5 by using Windows 10 or by installing [Windows Management Framework 5.0 RTM](https://www.microsoft.com/en-us/download/details.aspx?id=50395) for down-level Windows OSs (e.g. Windows 8.1, etc.).
Before starting it, please make sure PowerShell exists on your system. Follow the [Installing PowerShell](./learning-powershell.md#installing-powershell) instruction you can install the PowerShell and launch the PowerShell session. Before starting it, please make sure PowerShell exists on your system. By following the [Installing PowerShell](./learning-powershell.md#installing-powershell) instructions you can install PowerShell and launch a PowerShell session.
Editing with VS Code Editing with VS Code
---- ----
@@ -28,28 +28,28 @@ Editing with VS Code
- Press **F1** (or **Ctrl+Shift+P**) which opens up the “Command Palette” inside the VS Code app. - Press **F1** (or **Ctrl+Shift+P**) which opens up the “Command Palette” inside the VS Code app.
- In the command palette, type **ext install** and hit Enter. It will show all VS Code extensions available on your system. - In the command palette, type **ext install** and hit **Enter**. It will show all VS Code extensions available on your system.
- Choose PowerShell and click on Install, you will see something like below - Choose PowerShell and click on **Install**, you will see something like below
![VSCode](vscode.png) ![VSCode](vscode.png)
- After the install, you will see the **Install** button turns to **Enable**. - After the install, you will see the **Install** button turns to **Enable**.
- Click on Enable and OK - Click on **Enable** and **OK**
- Now you are ready for editing. for example, to create a new file, click File->New; to save it, click File->Save and then provide - Now you are ready for editing. For example, to create a new file, click **File->New**. To save it, click **File->Save** and then provide
a file name, let's say "helloworld.ps1"; to close the file, click on "x"; to exit the VS Code, File->Exit. a file name, let's say "helloworld.ps1". To close the file, click on "x" next to the file name. To exit VS Code, **File->Exit**.
Debugging with VS Code Debugging with VS Code
---- ----
- Open a file folder (**File->Open Folder**) where contains the PowerShell modules or scripts you have written already and want to debug. In this example, we saved helloworld.ps1 under home/jen/debug. Thus we select the "debug" folder and open it in VS Code. - Open a file folder (**File->Open Folder**) that contains the PowerShell modules or scripts you have written already and want to debug. In this example, we saved the helloworld.ps1 under a directory called "demo". Thus we select the "demo" folder and open it in VS Code.
- Creating the Debug Configuration (launch.json) - Creating the Debug Configuration (launch.json)
Because some information regarding your scripts is needed for debugger to start executing your script, we need to set up the debug config First. This is one time only to debug PowerShell scripts under your current folder. Because some information regarding your scripts is needed for debugger to start executing your script, we need to set up the debug config first. This is one-time process to debug PowerShell scripts under your current folder. In our case, the "demo" folder.
* Click on the **Debug** icon (or **Ctrl+Shift+D**) * Click on the **Debug** icon (or **Ctrl+Shift+D**)
* Click on the **Settings** icon that looks like a gear. The VS Code will prompt you to **Select Environment**. Choose **PowerShell**. Then the VS code will auto create a debug configuration settings file in the same folder. It looks like the following: * Click on the **Settings** icon that looks like a gear. VS Code will prompt you to **Select Environment**. Choose **PowerShell**. Then VS code will auto create a debug configuration settings file in the same folder. It looks like the following:
```json ```json
{ {
"version": "0.2.0", "version": "0.2.0",
@@ -73,9 +73,10 @@ Debugging with VS Code
] ]
} }
``` ```
- Once the debug configuration is established, now go to your helloworld.ps1 and set a breakpoint by pressing **F9** on a line you wish to debug break into. - Once the debug configuration is established, go to your helloworld.ps1 and set a breakpoint by pressing **F9** on a line you wish to debug.
- To disable the breakpoint, press **F9** again. - To disable the breakpoint, press **F9** again.
- Press **F5** to let the run. - Press **F5** to run the script. The execution should stop on the line you put the breakpoint on.
- Press **F5** to continue running the script.
There are a few blogs that may be helpful to get you started using PowerShell extension for VS Code There are a few blogs that may be helpful to get you started using PowerShell extension for VS Code
@@ -61,7 +61,8 @@
"Microsoft.PowerShell.Commands.Management": "1.0.0-*", "Microsoft.PowerShell.Commands.Management": "1.0.0-*",
"Microsoft.PowerShell.Commands.Utility": "1.0.0-*", "Microsoft.PowerShell.Commands.Utility": "1.0.0-*",
"Microsoft.PowerShell.LocalAccounts": "1.0.0-*", "Microsoft.PowerShell.LocalAccounts": "1.0.0-*",
"Microsoft.PowerShell.PackageManagement": "1.0.0-*" "Microsoft.PowerShell.PackageManagement": "1.0.0-*",
"Microsoft.Management.Infrastructure.CimCmdlets": "1.0.0-*"
}, },
"frameworks": { "frameworks": {
@@ -92,7 +92,12 @@ namespace Microsoft.PowerShell
public const ConsoleColor DefaultEmphasisForegroundColor = ConsoleColor.Cyan; public const ConsoleColor DefaultEmphasisForegroundColor = ConsoleColor.Cyan;
public const ConsoleColor DefaultErrorForegroundColor = ConsoleColor.Red; public const ConsoleColor DefaultErrorForegroundColor = ConsoleColor.Red;
public const EditMode DefaultEditMode = EditMode.Windows; public const EditMode DefaultEditMode =
#if LINUX
EditMode.Emacs;
#else
EditMode.Windows;
#endif
public const string DefaultContinuationPrompt = ">> "; public const string DefaultContinuationPrompt = ">> ";
@@ -114,6 +114,25 @@ namespace Microsoft.PowerShell
private Dictionary<ConsoleKeyInfo, KeyHandler> _dispatchTable; private Dictionary<ConsoleKeyInfo, KeyHandler> _dispatchTable;
private Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>> _chordDispatchTable; private Dictionary<ConsoleKeyInfo, Dictionary<ConsoleKeyInfo, KeyHandler>> _chordDispatchTable;
/// <summary>
/// Helper to set bindings based on EditMode
/// </summary>
void SetDefaultBindings(EditMode editMode)
{
switch (editMode)
{
case EditMode.Emacs:
SetDefaultEmacsBindings();
break;
case EditMode.Vi:
SetDefaultViBindings();
break;
case EditMode.Windows:
SetDefaultWindowsBindings();
break;
}
}
void SetDefaultWindowsBindings() void SetDefaultWindowsBindings()
{ {
_dispatchTable = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer()) _dispatchTable = new Dictionary<ConsoleKeyInfo, KeyHandler>(new ConsoleKeyInfoComparer())
+1 -12
View File
@@ -96,18 +96,7 @@ namespace Microsoft.PowerShell
// Switching/resetting modes - clear out chord dispatch table // Switching/resetting modes - clear out chord dispatch table
_chordDispatchTable.Clear(); _chordDispatchTable.Clear();
switch (options._editMode) SetDefaultBindings(Options.EditMode);
{
case EditMode.Emacs:
SetDefaultEmacsBindings();
break;
case EditMode.Vi:
SetDefaultViBindings();
break;
case EditMode.Windows:
SetDefaultWindowsBindings();
break;
}
} }
if (options._showToolTips.HasValue) if (options._showToolTips.HasValue)
{ {
@@ -485,8 +485,6 @@ namespace Microsoft.PowerShell
_console = new ConhostConsole(); _console = new ConhostConsole();
#endif #endif
SetDefaultWindowsBindings();
_buffer = new StringBuilder(8 * 1024); _buffer = new StringBuilder(8 * 1024);
_statusBuffer = new StringBuilder(256); _statusBuffer = new StringBuilder(256);
_savedCurrentLine = new HistoryItem(); _savedCurrentLine = new HistoryItem();
@@ -516,6 +514,7 @@ namespace Microsoft.PowerShell
hostName = "PSReadline"; hostName = "PSReadline";
} }
_options = new PSConsoleReadlineOptions(hostName); _options = new PSConsoleReadlineOptions(hostName);
SetDefaultBindings(_options.EditMode);
} }
private void Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics) private void Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics)
@@ -893,13 +893,10 @@ namespace System.Management.Automation
return GetEnvironmentVariables(); return GetEnvironmentVariables();
} }
if (!Platform.HasRegistrySupport()) #if LINUX
{ return null;
// Porting note: Does not throw a PlatformUnsupported because #else
// GetEnvironmentVariable cannot throw, and we want the same interface.
return null;
}
if( target == EnvironmentVariableTarget.Machine) if( target == EnvironmentVariableTarget.Machine)
{ {
using (RegistryKey environmentKey = using (RegistryKey environmentKey =
@@ -916,6 +913,7 @@ namespace System.Management.Automation
return GetRegistryKeyNameValuePairs(environmentKey); return GetRegistryKeyNameValuePairs(environmentKey);
} }
} }
#endif
} }
/// <summary> /// <summary>
@@ -956,13 +954,9 @@ namespace System.Management.Automation
return System.Environment.GetEnvironmentVariable(variable); return System.Environment.GetEnvironmentVariable(variable);
} }
if (!Platform.HasRegistrySupport()) #if LINUX
{ return null;
// Porting note: This cannot throw since it would otherwise throw while #else
// creating a runspace. Returning null is appropriate to signal that there
// is no value for a registry key with no registry.
return null;
}
if (target == EnvironmentVariableTarget.Machine) if (target == EnvironmentVariableTarget.Machine)
{ {
@@ -985,6 +979,7 @@ namespace System.Management.Automation
return value; return value;
} }
} }
#endif
} }
#endregion EnvironmentVariable_Extensions #endregion EnvironmentVariable_Extensions
@@ -143,12 +143,12 @@ namespace System.Management.Automation
//the user has set XDG_DATA_HOME corresponding to module path //the user has set XDG_DATA_HOME corresponding to module path
if (String.IsNullOrEmpty(xdgdatahome)){ if (String.IsNullOrEmpty(xdgdatahome)){
// create the xdg folder if needed // create the xdg folder if needed
if (!Directory.Exists(xdgDataHomeDefault)) if (!Directory.Exists(xdgDataHomeDefault))
{ {
Directory.CreateDirectory(xdgDataHomeDefault); Directory.CreateDirectory(xdgDataHomeDefault);
} }
return xdgDataHomeDefault; return xdgDataHomeDefault;
} }
else else
{ {
@@ -159,12 +159,12 @@ namespace System.Management.Automation
//the user has set XDG_DATA_HOME corresponding to module path //the user has set XDG_DATA_HOME corresponding to module path
if (String.IsNullOrEmpty(xdgdatahome)){ if (String.IsNullOrEmpty(xdgdatahome)){
//xdg values have not been set //xdg values have not been set
if (!Directory.Exists(xdgModuleDefault)) //module folder not always guaranteed to exist if (!Directory.Exists(xdgModuleDefault)) //module folder not always guaranteed to exist
{ {
Directory.CreateDirectory(xdgModuleDefault); Directory.CreateDirectory(xdgModuleDefault);
} }
return xdgModuleDefault; return xdgModuleDefault;
} }
else else
{ {
@@ -175,7 +175,7 @@ namespace System.Management.Automation
//the user has set XDG_CACHE_HOME //the user has set XDG_CACHE_HOME
if (String.IsNullOrEmpty(xdgcachehome)) if (String.IsNullOrEmpty(xdgcachehome))
{ {
//xdg values have not been set //xdg values have not been set
if (!Directory.Exists(xdgCacheDefault)) //module folder not always guaranteed to exist if (!Directory.Exists(xdgCacheDefault)) //module folder not always guaranteed to exist
{ {
Directory.CreateDirectory(xdgCacheDefault); Directory.CreateDirectory(xdgCacheDefault);
@@ -217,90 +217,6 @@ namespace System.Management.Automation
} }
// ComObjectType is null on CoreCLR for Linux since there is
// no COM support on Linux
internal static bool HasCom()
{
// TODO: catch exception from Type.IsComObject
return IsWindows;
}
// The Antimalware Scan Interface is not supported on Linux
internal static bool HasAmsi()
{
return IsWindows;
}
// This is mainly with respect to the auto-mounting of
// disconnected network drives on Windows
internal static bool HasDriveAutoMounting()
{
return IsWindows;
}
// Linux does not have a registry
internal static bool HasRegistrySupport()
{
return IsWindows;
}
// Linux does not have PowerShell execution policies
internal static bool HasExecutionPolicy()
{
return IsWindows;
}
// Linux has a single rooted file system
internal static bool HasSingleRootFilesystem()
{
return !IsWindows;
}
// Linux has no notion of file shares. It has mount points
// instead, which are subdirectories of its single-root
// filesystem.
internal static bool HasFileShares()
{
return !HasSingleRootFilesystem();
}
// Linux has no support for UNC, just mounts in a single rooted hierarchy
// the UNC equivalent of a "network drive" aka mount would be the mount itself
internal static bool HasUNCSupport()
{
return IsWindows;
}
// Linux uses .net to query file attributes
internal static bool UseDotNetToQueryFileAttributes()
{
return true;
}
// Linux does not have group policy support
internal static bool HasGroupPolicySupport()
{
return IsWindows;
}
// non-windows does not have network drive support
internal static bool HasNetworkDriveSupport()
{
return IsWindows;
}
// non-windows does not have reparse points
internal static bool SupportsReparsePoints()
{
return IsWindows;
}
// non-windows does not support removing drives
internal static bool SupportsRemoveDrive()
{
return IsWindows;
}
// Platform methods prefixed NonWindows are: // Platform methods prefixed NonWindows are:
// - non-windows by the definition of the IsWindows method above // - non-windows by the definition of the IsWindows method above
// - here, because porting to Linux and other operating systems // - here, because porting to Linux and other operating systems
@@ -313,27 +229,17 @@ namespace System.Management.Automation
internal static bool NonWindowsIsHardLink(ref IntPtr handle) internal static bool NonWindowsIsHardLink(ref IntPtr handle)
{ {
return LinuxPlatform.IsHardLink(ref handle); return Unix.IsHardLink(ref handle);
} }
internal static bool NonWindowsIsHardLink(FileSystemInfo fileInfo) internal static bool NonWindowsIsHardLink(FileSystemInfo fileInfo)
{ {
if (!IsWindows) return Unix.IsHardLink(fileInfo);
{
return LinuxPlatform.IsHardLink(fileInfo);
}
throw new PlatformNotSupportedException();
} }
internal static bool NonWindowsIsSymLink(FileSystemInfo fileInfo) internal static bool NonWindowsIsSymLink(FileSystemInfo fileInfo)
{ {
if (!IsWindows) return Unix.NativeMethods.IsSymLink(fileInfo.FullName);
{
return LinuxPlatform.IsSymLink(fileInfo);
}
throw new PlatformNotSupportedException();
} }
internal static string NonWindowsInternalGetTarget(SafeFileHandle handle) internal static string NonWindowsInternalGetTarget(SafeFileHandle handle)
@@ -344,166 +250,101 @@ namespace System.Management.Automation
internal static string NonWindowsInternalGetTarget(string path) internal static string NonWindowsInternalGetTarget(string path)
{ {
if (!IsWindows) return Unix.NativeMethods.FollowSymLink(path);
{
return LinuxPlatform.FollowSymLink(path);
}
else
{
throw new PlatformNotSupportedException();
}
} }
internal static string NonWindowsGetUserFromPid(int path) internal static string NonWindowsGetUserFromPid(int path)
{ {
if (!IsWindows) return Unix.NativeMethods.GetUserFromPid(path);
{
return LinuxPlatform.GetUserFromPid(path);
}
else
{
throw new PlatformNotSupportedException();
}
} }
#if CORECLR #if CORECLR
internal static string NonWindowsGetFolderPath(SpecialFolder folder) internal static string NonWindowsGetFolderPath(SpecialFolder folder)
{ {
if (!IsWindows) return Unix.GetFolderPath(folder);
{
return LinuxPlatform.GetFolderPath(folder);
}
else
{
throw new PlatformNotSupportedException();
}
} }
#endif #endif
internal static string NonWindowsInternalGetLinkType(FileSystemInfo fileInfo) internal static string NonWindowsInternalGetLinkType(FileSystemInfo fileInfo)
{ {
if (!IsWindows) if (NonWindowsIsSymLink(fileInfo))
{ {
if (NonWindowsIsSymLink(fileInfo)) return "SymbolicLink";
{
return "SymbolicLink";
}
if (NonWindowsIsHardLink(fileInfo))
{
return "HardLink";
}
return null;
}
else
{
throw new PlatformNotSupportedException();
} }
if (NonWindowsIsHardLink(fileInfo))
{
return "HardLink";
}
return null;
} }
internal static bool NonWindowsCreateSymbolicLink(string path, string strTargetPath, bool isDirectory) internal static bool NonWindowsCreateSymbolicLink(string path, string target)
{ {
if (!IsWindows) // Linux doesn't care if target is a directory or not
{ return Unix.NativeMethods.CreateSymLink(path, target);
// Linux doesn't care if target is a directory or not
return LinuxPlatform.CreateSymbolicLink(path, strTargetPath);
}
else
{
throw new PlatformNotSupportedException();
}
} }
internal static bool NonWindowsCreateHardLink(string path, string strTargetPath) internal static bool NonWindowsCreateHardLink(string path, string strTargetPath)
{ {
if (!IsWindows) return Unix.CreateHardLink(path, strTargetPath);
{
return LinuxPlatform.CreateHardLink(path, strTargetPath);
}
else
{
throw new PlatformNotSupportedException();
}
} }
internal static void NonWindowsSetDate(DateTime dateToUse) internal static void NonWindowsSetDate(DateTime dateToUse)
{ {
if (!IsWindows) Unix.SetDateInfoInternal date = new Unix.SetDateInfoInternal(dateToUse);
{ Unix.SetDate(date);
LinuxPlatform.SetDateInfoInternal date = new LinuxPlatform.SetDateInfoInternal(dateToUse);
LinuxPlatform.SetDate(date);
}
else
{
throw new PlatformNotSupportedException();
}
} }
internal static string NonWindowsGetDomainName() internal static string NonWindowsGetDomainName()
{ {
if (!IsWindows) string fullyQualifiedName = Unix.NativeMethods.GetFullyQualifiedName();
if (string.IsNullOrEmpty(fullyQualifiedName))
{ {
string fullyQualifiedName = LinuxPlatform.Native.GetFullyQualifiedName(); int lastError = Marshal.GetLastWin32Error();
if (string.IsNullOrEmpty(fullyQualifiedName)) throw new InvalidOperationException("Unix.NonWindowsGetDomainName error: " + lastError);
{
int lastError = Marshal.GetLastWin32Error();
throw new InvalidOperationException("LinuxPlatform.NonWindowsGetDomainName error: " + lastError);
}
int index = fullyQualifiedName.IndexOf('.');
if (index >= 0)
{
return fullyQualifiedName.Substring(index + 1);
}
return "";
} }
else
int index = fullyQualifiedName.IndexOf('.');
if (index >= 0)
{ {
throw new PlatformNotSupportedException(); return fullyQualifiedName.Substring(index + 1);
} }
return "";
} }
internal static string NonWindowsGetUserName() internal static string NonWindowsGetUserName()
{ {
if (!IsWindows) return Unix.UserName;
{
return LinuxPlatform.UserName;
}
else
{
throw new PlatformNotSupportedException();
}
} }
// Hostname in this context seems to be the FQDN // Hostname in this context seems to be the FQDN
internal static string NonWindowsGetHostName() internal static string NonWindowsGetHostName()
{ {
if (!IsWindows) string hostName = Unix.NativeMethods.GetFullyQualifiedName();
if (string.IsNullOrEmpty(hostName))
{ {
string hostName = LinuxPlatform.Native.GetFullyQualifiedName(); int lastError = Marshal.GetLastWin32Error();
if (string.IsNullOrEmpty(hostName)) throw new InvalidOperationException("Unix.NonWindowsHostName error: " + lastError);
{ }
int lastError = Marshal.GetLastWin32Error(); return hostName;
throw new InvalidOperationException("LinuxPlatform.NonWindowsHostName error: " + lastError); }
}
return hostName;
} internal static bool NonWindowsIsFile(string path)
else {
{ return Unix.NativeMethods.IsFile(path);
throw new PlatformNotSupportedException(); }
}
internal static bool NonWindowsIsDirectory(string path)
{
return Unix.NativeMethods.IsDirectory(path);
} }
internal static bool NonWindowsIsExecutable(string path) internal static bool NonWindowsIsExecutable(string path)
{ {
if (!IsWindows) return Unix.NativeMethods.IsExecutable(path);
{
return LinuxPlatform.IsExecutable(path);
}
throw new PlatformNotSupportedException();
} }
internal static uint NonWindowsGetThreadId() internal static uint NonWindowsGetThreadId()
@@ -512,15 +353,6 @@ namespace System.Management.Automation
return 0; return 0;
} }
/// <summary>
/// This exception is meant to be thrown if a code path is not supported due
/// to platform restrictions
/// </summary>
internal class PlatformNotSupportedException : System.Exception
{
public PlatformNotSupportedException() : base() {}
}
/// <summary> /// <summary>
/// This models the native call CommandLineToArgvW in managed code. /// This models the native call CommandLineToArgvW in managed code.
/// </summary> /// </summary>
@@ -581,7 +413,7 @@ namespace System.Management.Automation
} }
} }
internal static class LinuxPlatform internal static class Unix
{ {
private static string _userName; private static string _userName;
public static string UserName public static string UserName
@@ -590,11 +422,11 @@ namespace System.Management.Automation
{ {
if (string.IsNullOrEmpty(_userName)) if (string.IsNullOrEmpty(_userName))
{ {
_userName = Native.GetUserName(); _userName = NativeMethods.GetUserName();
if (string.IsNullOrEmpty(_userName)) if (string.IsNullOrEmpty(_userName))
{ {
int lastError = Marshal.GetLastWin32Error(); int lastError = Marshal.GetLastWin32Error();
throw new InvalidOperationException("LinuxPlatform.UserName error: " + lastError); throw new InvalidOperationException("Unix.UserName error: " + lastError);
} }
} }
return _userName; return _userName;
@@ -620,40 +452,40 @@ namespace System.Management.Automation
} }
} }
#if CORECLR #if CORECLR
public static string GetFolderPath(SpecialFolder folder) public static string GetFolderPath(SpecialFolder folder)
{ {
string s = null; string s = null;
switch (folder) switch (folder)
{ {
case SpecialFolder.ProgramFiles: case SpecialFolder.ProgramFiles:
s = "/bin"; s = "/bin";
break; break;
case SpecialFolder.ProgramFilesX86: case SpecialFolder.ProgramFilesX86:
s = "/usr/bin"; s = "/usr/bin";
break; break;
case SpecialFolder.System: case SpecialFolder.System:
s = "/sbin"; s = "/sbin";
break; break;
case SpecialFolder.SystemX86: case SpecialFolder.SystemX86:
s = "/sbin"; s = "/sbin";
break; break;
case SpecialFolder.Personal: case SpecialFolder.Personal:
s = System.Environment.GetEnvironmentVariable("HOME"); s = System.Environment.GetEnvironmentVariable("HOME");
break; break;
case SpecialFolder.LocalApplicationData: case SpecialFolder.LocalApplicationData:
s = System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".config"); s = System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".config");
if (!System.IO.Directory.Exists(s)) if (!System.IO.Directory.Exists(s))
{ {
System.IO.Directory.CreateDirectory(s); System.IO.Directory.CreateDirectory(s);
} }
break; break;
default: default:
throw new NotSupportedException(); throw new NotSupportedException();
} }
return s; return s;
} }
#endif #endif
public static bool IsHardLink(ref IntPtr handle) public static bool IsHardLink(ref IntPtr handle)
{ {
@@ -671,7 +503,7 @@ namespace System.Management.Automation
int count; int count;
string filePath = fs.FullName; string filePath = fs.FullName;
int ret = Native.GetLinkCount(filePath, out count); int ret = NativeMethods.GetLinkCount(filePath, out count);
if (ret == 1) if (ret == 1)
{ {
return count > 1; return count > 1;
@@ -679,84 +511,27 @@ namespace System.Management.Automation
else else
{ {
int lastError = Marshal.GetLastWin32Error(); int lastError = Marshal.GetLastWin32Error();
throw new InvalidOperationException("LinuxPlatform.IsHardLink error: " + lastError); throw new InvalidOperationException("Unix.IsHardLink error: " + lastError);
} }
} }
public static bool IsSymLink(FileSystemInfo fs)
{
if (!fs.Exists)
{
return false;
}
string filePath = fs.FullName;
int ret = Native.IsSymLink(filePath);
switch(ret)
{
case 1:
return true;
case 0:
return false;
default:
int lastError = Marshal.GetLastWin32Error();
throw new InvalidOperationException("LinuxPlatform.IsSymLink error: " + lastError);
}
}
public static bool IsExecutable(string filePath)
{
if (!File.Exists(filePath))
{
return false;
}
int ret = Native.IsExecutable(filePath);
switch(ret)
{
case 1:
return true;
case 0:
return false;
default:
int lastError = Marshal.GetLastWin32Error();
throw new InvalidOperationException("LinuxPlatform.IsExecutable error: " + lastError);
}
}
public static void SetDate(SetDateInfoInternal info) public static void SetDate(SetDateInfoInternal info)
{ {
int ret = Native.SetDate(info); int ret = NativeMethods.SetDate(info);
if (ret == -1) if (ret == -1)
{ {
int lastError = Marshal.GetLastWin32Error(); int lastError = Marshal.GetLastWin32Error();
throw new InvalidOperationException("LinuxPlatform.NonWindowsSetDate error: " + lastError); throw new InvalidOperationException("Unix.NonWindowsSetDate error: " + lastError);
} }
} }
public static bool CreateSymbolicLink(string path, string strTargetPath)
{
int ret = Native.CreateSymLink(path, strTargetPath);
return ret == 1 ? true : false;
}
public static bool CreateHardLink(string path, string strTargetPath) public static bool CreateHardLink(string path, string strTargetPath)
{ {
int ret = Native.CreateHardLink(path, strTargetPath); int ret = NativeMethods.CreateHardLink(path, strTargetPath);
return ret == 1 ? true : false; return ret == 1 ? true : false;
} }
public static string FollowSymLink(string path)
{
return Native.FollowSymLink(path);
}
public static string GetUserFromPid(int pid)
{
return Native.GetUserFromPid(pid);
}
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal class SetDateInfoInternal internal class SetDateInfoInternal
{ {
@@ -788,12 +563,14 @@ namespace System.Management.Automation
} }
} }
internal static class Native internal static class NativeMethods
{ {
const string psLib = "libpsl-native"; const string psLib = "libpsl-native";
// Ansi is a misnomer, it is hardcoded to UTF-8 on Linux and OS X // Ansi is a misnomer, it is hardcoded to UTF-8 on Linux and OS X
// C bools are 1 byte and so must be marshaled as I1
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.LPStr)] [return: MarshalAs(UnmanagedType.LPStr)]
internal static extern string GetUserName(); internal static extern string GetUserName();
@@ -802,10 +579,12 @@ namespace System.Management.Automation
internal static extern int GetLinkCount([MarshalAs(UnmanagedType.LPStr)]string filePath, out int linkCount); internal static extern int GetLinkCount([MarshalAs(UnmanagedType.LPStr)]string filePath, out int linkCount);
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int IsSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath); [return: MarshalAs(UnmanagedType.I1)]
internal static extern bool IsSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath);
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int IsExecutable([MarshalAs(UnmanagedType.LPStr)]string filePath); [return: MarshalAs(UnmanagedType.I1)]
internal static extern bool IsExecutable([MarshalAs(UnmanagedType.LPStr)]string filePath);
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.LPStr)] [return: MarshalAs(UnmanagedType.LPStr)]
@@ -815,7 +594,8 @@ namespace System.Management.Automation
internal static extern int SetDate(SetDateInfoInternal info); internal static extern int SetDate(SetDateInfoInternal info);
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
internal static extern int CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath, [return: MarshalAs(UnmanagedType.I1)]
internal static extern bool CreateSymLink([MarshalAs(UnmanagedType.LPStr)]string filePath,
[MarshalAs(UnmanagedType.LPStr)]string target); [MarshalAs(UnmanagedType.LPStr)]string target);
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
@@ -829,6 +609,15 @@ namespace System.Management.Automation
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)] [DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.LPStr)] [return: MarshalAs(UnmanagedType.LPStr)]
internal static extern string GetUserFromPid(int pid); internal static extern string GetUserFromPid(int pid);
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.I1)]
internal static extern bool IsFile([MarshalAs(UnmanagedType.LPStr)]string filePath);
[DllImport(psLib, CharSet = CharSet.Ansi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.I1)]
internal static extern bool IsDirectory([MarshalAs(UnmanagedType.LPStr)]string filePath);
} }
} }
@@ -4464,12 +4464,9 @@ namespace System.Management.Automation
internal static List<string> GetFileShares(string machine, bool ignoreHidden) internal static List<string> GetFileShares(string machine, bool ignoreHidden)
{ {
// Platform notes: don't throw an exception since this is being used in auto-completion #if LINUX
if (!Platform.HasFileShares()) return new List<string>();
{ #else
return new List<string>();
}
IntPtr shBuf; IntPtr shBuf;
uint numEntries; uint numEntries;
uint totalEntries; uint totalEntries;
@@ -4495,6 +4492,7 @@ namespace System.Management.Automation
} }
} }
return shares; return shares;
#endif
} }
private static bool CheckFileExtension(string path, HashSet<string> extension) private static bool CheckFileExtension(string path, HashSet<string> extension)
@@ -1903,13 +1903,9 @@ namespace System.Management.Automation
/// ///
internal static string GetShellPathFromRegistry(string shellID) internal static string GetShellPathFromRegistry(string shellID)
{ {
if (!Platform.HasRegistrySupport())
{
return null;
}
string result = null; string result = null;
#if !LINUX
try try
{ {
RegistryKey shellKey = Registry.LocalMachine.OpenSubKey(Utils.GetRegistryConfigurationPath(shellID)); RegistryKey shellKey = Registry.LocalMachine.OpenSubKey(Utils.GetRegistryConfigurationPath(shellID));
@@ -1935,6 +1931,7 @@ namespace System.Management.Automation
catch (ArgumentException) catch (ArgumentException)
{ {
} }
#endif
return result; return result;
} }
@@ -103,13 +103,9 @@ namespace System.Management.Automation
// Gets the current WSMan stack version from the registry. // Gets the current WSMan stack version from the registry.
private static Version GetWSManStackVersion() private static Version GetWSManStackVersion()
{ {
if (!Platform.HasRegistrySupport())
{
return new Version(1, 0);
}
Version version = null; Version version = null;
#if !LINUX
try try
{ {
using (RegistryKey wsManStackVersionKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\WSMAN")) using (RegistryKey wsManStackVersionKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\WSMAN"))
@@ -133,6 +129,7 @@ namespace System.Management.Automation
catch (FormatException) { } catch (FormatException) { }
catch (OverflowException) { } catch (OverflowException) { }
catch (InvalidCastException) { } catch (InvalidCastException) { }
#endif
return version ?? System.Management.Automation.Remoting.Client.WSManNativeApi.WSMAN_STACK_VERSION; return version ?? System.Management.Automation.Remoting.Client.WSManNativeApi.WSMAN_STACK_VERSION;
} }
@@ -1469,11 +1469,12 @@ namespace System.Management.Automation
bool driveIsValid = true; bool driveIsValid = true;
// If the drive is auto-mounted, ensure that it still exists, or remove the drive. // If the drive is auto-mounted, ensure that it still exists, or remove the drive.
// note: not all platforms support drive auto-mounting #if !LINUX
if (Platform.HasDriveAutoMounting() && (drive.IsAutoMounted || IsAStaleVhdMountedDrive(drive))) if (drive.IsAutoMounted || IsAStaleVhdMountedDrive(drive))
{ {
driveIsValid = ValidateOrRemoveAutoMountedDrive(drive, lookupScope); driveIsValid = ValidateOrRemoveAutoMountedDrive(drive, lookupScope);
} }
#endif
if(drive.Name.Length == 1) if(drive.Name.Length == 1)
{ {
if(!(driveNames.Contains(drive.Name))) if(!(driveNames.Contains(drive.Name)))
+34 -146
View File
@@ -62,15 +62,6 @@ namespace System.Management.Automation
return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7, h8)); return CombineHashCodes(CombineHashCodes(h1, h2, h3, h4), CombineHashCodes(h5, h6, h7, h8));
} }
/// <summary>
/// IsWinPEHost indicates if the machine on which PowerShell is hosted is WinPE or not.
/// This is a helper variable used to kep track if the IsWinPE() helper method has
/// already checked for the WinPE specific registry key or not.
/// If the WinPE specific registry key has not yet been checked even
/// once then this variable will point to null.
/// </summary>
internal static bool? isWinPEHost = null;
/// <summary> /// <summary>
/// The existence of the following registry confirms that the host machine is a WinPE /// The existence of the following registry confirms that the host machine is a WinPE
/// HKLM\System\CurrentControlSet\Control\MiniNT /// HKLM\System\CurrentControlSet\Control\MiniNT
@@ -368,58 +359,31 @@ namespace System.Management.Automation
/// </summary> /// </summary>
internal static bool IsWinPEHost() internal static bool IsWinPEHost()
{ {
if (Platform.HasRegistrySupport()) #if !LINUX
{
return WinIsWinPEHost();
}
else
{
return false;
}
}
internal static bool WinIsWinPEHost()
{
RegistryKey winPEKey = null; RegistryKey winPEKey = null;
if (!isWinPEHost.HasValue) try
{ {
try // The existence of the following registry confirms that the host machine is a WinPE
{ // HKLM\System\CurrentControlSet\Control\MiniNT
// The existence of the following registry confirms that the host machine is a WinPE winPEKey = Registry.LocalMachine.OpenSubKey(WinPEIdentificationRegKey);
// HKLM\System\CurrentControlSet\Control\MiniNT
winPEKey = Registry.LocalMachine.OpenSubKey(WinPEIdentificationRegKey);
if (null != winPEKey) return winPEKey != null;
{ }
isWinPEHost = true; catch (ArgumentException) { }
} catch (SecurityException) { }
else catch (ObjectDisposedException) { }
{ finally
isWinPEHost = false; {
} if (winPEKey != null)
}
catch (ArgumentException) { }
catch (SecurityException) { }
catch (ObjectDisposedException) { }
finally
{ {
if (winPEKey != null) winPEKey.Dispose();
{
winPEKey.Dispose();
}
} }
} }
#endif
return false;
}
if (isWinPEHost.HasValue)
{
return (bool)isWinPEHost;
}
else
{
return false;
}
}
#region Versioning related methods #region Versioning related methods
@@ -652,13 +616,9 @@ namespace System.Management.Automation
internal static Dictionary<string, object> GetGroupPolicySetting(string groupPolicyBase, string settingName, RegistryKey[] preferenceOrder) internal static Dictionary<string, object> GetGroupPolicySetting(string groupPolicyBase, string settingName, RegistryKey[] preferenceOrder)
{ {
if (!Platform.HasGroupPolicySupport()) #if LINUX
{ return _emptyDictionary;
// Porting note: No group policy support means we have an empty set of #else
// policies.
return _emptyDictionary;
}
lock (cachedGroupPolicySettings) lock (cachedGroupPolicySettings)
{ {
// Return cached information, if we have it // Return cached information, if we have it
@@ -733,6 +693,7 @@ namespace System.Management.Automation
return settings; return settings;
} }
#endif
} }
static ConcurrentDictionary<string, Dictionary<string, object>> cachedGroupPolicySettings = static ConcurrentDictionary<string, Dictionary<string, object>> cachedGroupPolicySettings =
new ConcurrentDictionary<string, Dictionary<string, object>>(); new ConcurrentDictionary<string, Dictionary<string, object>>();
@@ -984,38 +945,9 @@ namespace System.Management.Automation
return NativeItemExists(path, out unusedIsDirectory, out unusedException); return NativeItemExists(path, out unusedIsDirectory, out unusedException);
} }
// This is done through P/Invoke since File.Exists and Directory.Exists pay 13% performance degradation
// through the CAS checks, and are terribly slow for network paths.
internal static bool NativeItemExists(string path, out bool isDirectory, out Exception exception) internal static bool NativeItemExists(string path, out bool isDirectory, out Exception exception)
{
if (Platform.UseDotNetToQueryFileAttributes())
{
// TODO:PSL replace by System.IO.File.GetAttributes
exception = null;
if (NativeDirectoryExists(path))
{
isDirectory = true;
return true;
}
else if (NativeFileExists(path))
{
isDirectory = false;
return true;
}
else
{
isDirectory = false;
return false;
}
}
else
{
// This is done through P/Invoke since File.Exists and Directory.Exists
// pay 13% performance degradation through the CAS checks, and are
// terribly slow for network paths.
return WinNativeItemExists(path,out isDirectory,out exception);
}
}
internal static bool WinNativeItemExists(string path, out bool isDirectory, out Exception exception)
{ {
exception = null; exception = null;
@@ -1024,6 +956,10 @@ namespace System.Management.Automation
isDirectory = false; isDirectory = false;
return false; return false;
} }
#if LINUX
isDirectory = Platform.NonWindowsIsDirectory(path);
return Platform.NonWindowsIsFile(path);
#else
if (IsReservedDeviceName(path)) if (IsReservedDeviceName(path))
{ {
@@ -1057,23 +993,12 @@ namespace System.Management.Automation
((int)NativeMethods.FileAttributes.Directory); ((int)NativeMethods.FileAttributes.Directory);
return true; return true;
#endif
} }
// This is done through P/Invoke since we pay 13% performance degradation
// through the CAS checks required by File.Exists and Directory.Exists
internal static bool NativeFileExists(string path) internal static bool NativeFileExists(string path)
{
if (Platform.UseDotNetToQueryFileAttributes())
{
return System.IO.File.Exists(path);
}
else
{
// This is done through P/Invoke since we pay 13% performance degradation
// through the CAS checks required by File.Exists and Directory.Exists
return WinNativeFileExists(path);
}
}
internal static bool WinNativeFileExists(string path)
{ {
bool isDirectory; bool isDirectory;
Exception ioException; Exception ioException;
@@ -1090,18 +1015,6 @@ namespace System.Management.Automation
// This is done through P/Invoke since we pay 13% performance degradation // This is done through P/Invoke since we pay 13% performance degradation
// through the CAS checks required by File.Exists and Directory.Exists // through the CAS checks required by File.Exists and Directory.Exists
internal static bool NativeDirectoryExists(string path) internal static bool NativeDirectoryExists(string path)
{
if (Platform.UseDotNetToQueryFileAttributes())
{
return System.IO.Directory.Exists(path);
}
else
{
return WinNativeDirectoryExists(path);
}
}
internal static bool WinNativeDirectoryExists(string path)
{ {
bool isDirectory; bool isDirectory;
Exception ioException; Exception ioException;
@@ -1116,31 +1029,6 @@ namespace System.Management.Automation
} }
internal static void NativeEnumerateDirectory(string directory, out List<string> directories, out List<string> files) internal static void NativeEnumerateDirectory(string directory, out List<string> directories, out List<string> files)
{
if (Platform.UseDotNetToQueryFileAttributes())
{
IEnumerable<string> fileEnum = System.IO.Directory.EnumerateFiles(directory);
IEnumerable<string> dirEnum = System.IO.Directory.EnumerateDirectories(directory);
files = new List<string>();
directories = new List<string>();
foreach (string entry in fileEnum)
{
files.Add(directory + "/" + entry);
}
foreach (string entry in dirEnum)
{
directories.Add(directory + "/" + entry);
}
}
else
{
WinNativeEnumerateDirectory(directory, out directories, out files);
}
}
internal static void WinNativeEnumerateDirectory(string directory, out List<string> directories, out List<string> files)
{ {
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
NativeMethods.WIN32_FIND_DATA findData; NativeMethods.WIN32_FIND_DATA findData;
@@ -1205,12 +1093,12 @@ namespace System.Management.Automation
internal static bool PathIsUnc(string path) internal static bool PathIsUnc(string path)
{ {
if (!Platform.HasUNCSupport()) #if LINUX
{ return false;
return false; #else
}
Uri uri; Uri uri;
return !string.IsNullOrEmpty(path) && Uri.TryCreate(path, UriKind.Absolute, out uri) && uri.IsUnc; return !string.IsNullOrEmpty(path) && Uri.TryCreate(path, UriKind.Absolute, out uri) && uri.IsUnc;
#endif
} }
internal class NativeMethods internal class NativeMethods
@@ -96,12 +96,10 @@ namespace Microsoft.PowerShell.Commands
/// </summary> /// </summary>
internal static void CheckRemotingCmdletPrerequisites() internal static void CheckRemotingCmdletPrerequisites()
{ {
//If the operating system (ie Linux) does not support the registry, simply return to avoid calls to the Windows registry. #if LINUX
if (!Platform.HasRegistrySupport()) // TODO: check that PSRP requirements are installed
{ return;
return; #else
}
bool notSupported = true; bool notSupported = true;
String WSManKeyPath = "Software\\Microsoft\\Windows\\CurrentVersion\\WSMAN\\"; String WSManKeyPath = "Software\\Microsoft\\Windows\\CurrentVersion\\WSMAN\\";
@@ -155,6 +153,7 @@ namespace Microsoft.PowerShell.Commands
throw new InvalidOperationException( throw new InvalidOperationException(
"Windows PowerShell remoting features are not enabled or not supported on this machine.\nThis may be because you do not have the correct version of WS-Management installed or this version of Windows does not support remoting currently.\n For more information, type 'get-help about_remote_requirements'."); "Windows PowerShell remoting features are not enabled or not supported on this machine.\nThis may be because you do not have the correct version of WS-Management installed or this version of Windows does not support remoting currently.\n For more information, type 'get-help about_remote_requirements'.");
} }
#endif
} }
/// <summary> /// <summary>
@@ -677,14 +677,11 @@ namespace System.Management.Automation.Language
private static TypeInfo GetComObjectType() private static TypeInfo GetComObjectType()
{ {
if (Platform.HasCom()) #if LINUX
{ return null;
return typeof(object).GetTypeInfo().Assembly.GetType("System.__ComObject").GetTypeInfo(); #else
} return typeof(object).GetTypeInfo().Assembly.GetType("System.__ComObject").GetTypeInfo();
else #endif
{
return null;
}
} }
internal static bool IsComObject(object obj) internal static bool IsComObject(object obj)
@@ -496,7 +496,7 @@ namespace Microsoft.PowerShell.Commands
} }
else else
{ {
throw new Platform.PlatformNotSupportedException(); throw new PlatformNotSupportedException();
} }
} }
@@ -607,15 +607,11 @@ namespace Microsoft.PowerShell.Commands
/// </returns> /// </returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive) protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{ {
// if removing the drive is not supported, just return the drive #if LINUX
if (Platform.SupportsRemoveDrive()) return drive;
{ #else
return WinRemoveDrive(drive); return WinRemoveDrive(drive);
} #endif
else
{
return drive;
}
} }
private PSDriveInfo WinRemoveDrive(PSDriveInfo drive) private PSDriveInfo WinRemoveDrive(PSDriveInfo drive)
@@ -685,15 +681,11 @@ namespace Microsoft.PowerShell.Commands
/// <returns></returns> /// <returns></returns>
internal static string GetUNCForNetworkDrive(string driveName) internal static string GetUNCForNetworkDrive(string driveName)
{ {
// Porting note: on systems that do not support UNC paths, the UNC equivalent is the path itself #if LINUX
if (Platform.HasUNCSupport()) return driveName;
{ #else
return WinGetUNCForNetworkDrive(driveName); return WinGetUNCForNetworkDrive(driveName);
} #endif
else
{
return driveName;
}
} }
private static string WinGetUNCForNetworkDrive(string driveName) private static string WinGetUNCForNetworkDrive(string driveName)
@@ -747,14 +739,11 @@ namespace Microsoft.PowerShell.Commands
/// <returns></returns> /// <returns></returns>
internal static string GetSubstitutedPathForNetworkDosDevice(string driveName) internal static string GetSubstitutedPathForNetworkDosDevice(string driveName)
{ {
if (Platform.HasNetworkDriveSupport()) #if LINUX
{ throw new PlatformNotSupportedException();
return WinGetSubstitutedPathForNetworkDosDevice(driveName); #else
} return WinGetSubstitutedPathForNetworkDosDevice(driveName);
else #endif
{
throw new Platform.PlatformNotSupportedException();
}
} }
private static string WinGetSubstitutedPathForNetworkDosDevice(string driveName) private static string WinGetSubstitutedPathForNetworkDosDevice(string driveName)
@@ -926,15 +915,15 @@ namespace Microsoft.PowerShell.Commands
if (newDrive.DriveType == DriveType.Network) if (newDrive.DriveType == DriveType.Network)
{ {
// Platform notes: This is important because certain mount // Platform notes: This is important because certain mount
// points on non-Windows are enumerated as drives by .net, but // points on non-Windows are enumerated as drives by .NET, but
// the platform itself then has no real network drive support // the platform itself then has no real network drive support
// as required by this context. Solution: check for network // as required by this context. Solution: check for network
// drive support before using it. // drive support before using it.
if (!Platform.HasNetworkDriveSupport()) #if LINUX
{ continue;
continue; #else
}
displayRoot = GetRootPathForNetworkDriveOrDosDevice(newDrive); displayRoot = GetRootPathForNetworkDriveOrDosDevice(newDrive);
#endif
} }
if (newDrive.DriveType == DriveType.Fixed) if (newDrive.DriveType == DriveType.Fixed)
@@ -947,12 +936,14 @@ namespace Microsoft.PowerShell.Commands
root = newDrive.RootDirectory.FullName; root = newDrive.RootDirectory.FullName;
} }
#if LINUX
// Porting notes: On platforms with single root filesystems, only // Porting notes: On platforms with single root filesystems, only
// add the filesystem with the root "/" to the initial drive list, // add the filesystem with the root "/" to the initial drive list,
// otherwise path handling will not work correctly because there // otherwise path handling will not work correctly because there
// is no : available to separate the filesystems from each other // is no : available to separate the filesystems from each other
if (Platform.HasSingleRootFilesystem() && root != StringLiterals.DefaultPathSeparatorString) if (root != StringLiterals.DefaultPathSeparatorString)
continue; continue;
#endif
// Porting notes: On non-windows platforms .net can report two // Porting notes: On non-windows platforms .net can report two
// drives with the same root, make sure to only add one of those // drives with the same root, make sure to only add one of those
@@ -2229,7 +2220,7 @@ namespace Microsoft.PowerShell.Commands
} }
else else
{ {
success = Platform.NonWindowsCreateSymbolicLink(path,strTargetPath,isDirectory); success = Platform.NonWindowsCreateSymbolicLink(path,strTargetPath);
} }
} }
else if(itemType == ItemType.HardLink) else if(itemType == ItemType.HardLink)
@@ -6971,48 +6962,47 @@ namespace Microsoft.PowerShell.Commands
internal static int SafeGetFileAttributes(string path) internal static int SafeGetFileAttributes(string path)
{ {
if (Platform.UseDotNetToQueryFileAttributes()) #if LINUX
{ System.IO.FileAttributes attr = System.IO.File.GetAttributes(path);
System.IO.FileAttributes attr = System.IO.File.GetAttributes(path);
int result = 0; int result = 0;
if ((attr & FileAttributes.Archive) == FileAttributes.Archive) if ((attr & FileAttributes.Archive) == FileAttributes.Archive)
result |= 0x20; result |= 0x20;
if ((attr & FileAttributes.Compressed) == FileAttributes.Compressed) if ((attr & FileAttributes.Compressed) == FileAttributes.Compressed)
result |= 0x800; result |= 0x800;
if ((attr & FileAttributes.Device) == FileAttributes.Device) if ((attr & FileAttributes.Device) == FileAttributes.Device)
result |= 0x40; result |= 0x40;
if ((attr & FileAttributes.Directory) == FileAttributes.Directory) if ((attr & FileAttributes.Directory) == FileAttributes.Directory)
result |= 0x10; result |= 0x10;
if ((attr & FileAttributes.Encrypted) == FileAttributes.Encrypted) if ((attr & FileAttributes.Encrypted) == FileAttributes.Encrypted)
result |= 0x4000; result |= 0x4000;
if ((attr & FileAttributes.Hidden) == FileAttributes.Hidden) if ((attr & FileAttributes.Hidden) == FileAttributes.Hidden)
result |= 0x2; result |= 0x2;
if ((attr & FileAttributes.IntegrityStream) == FileAttributes.IntegrityStream) if ((attr & FileAttributes.IntegrityStream) == FileAttributes.IntegrityStream)
result |= 0x8000; result |= 0x8000;
if ((attr & FileAttributes.Normal) == FileAttributes.Normal) if ((attr & FileAttributes.Normal) == FileAttributes.Normal)
result |= 0x80; result |= 0x80;
if ((attr & FileAttributes.NoScrubData) == FileAttributes.NoScrubData) if ((attr & FileAttributes.NoScrubData) == FileAttributes.NoScrubData)
result |= 0x20000; result |= 0x20000;
if ((attr & FileAttributes.NotContentIndexed) == FileAttributes.NotContentIndexed) if ((attr & FileAttributes.NotContentIndexed) == FileAttributes.NotContentIndexed)
result |= 0x2000; result |= 0x2000;
if ((attr & FileAttributes.Offline) == FileAttributes.Offline) if ((attr & FileAttributes.Offline) == FileAttributes.Offline)
result |= 0x1000; result |= 0x1000;
if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) if ((attr & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
result |= 0x1; result |= 0x1;
if ((attr & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint) if ((attr & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
result |= 0x400; result |= 0x400;
if ((attr & FileAttributes.SparseFile) == FileAttributes.SparseFile) if ((attr & FileAttributes.SparseFile) == FileAttributes.SparseFile)
result |= 0x200; result |= 0x200;
if ((attr & FileAttributes.System) == FileAttributes.System) if ((attr & FileAttributes.System) == FileAttributes.System)
result |= 0x4; result |= 0x4;
if ((attr & FileAttributes.Temporary) == FileAttributes.Temporary) if ((attr & FileAttributes.Temporary) == FileAttributes.Temporary)
result |= 0x100; result |= 0x100;
return result; return result;
} #else
else return WinSafeGetFileAttributes(path);
return WinSafeGetFileAttributes(path); #endif
} }
internal static int WinSafeGetFileAttributes(string path) internal static int WinSafeGetFileAttributes(string path)
@@ -7074,11 +7064,11 @@ namespace Microsoft.PowerShell.Commands
/// <returns></returns> /// <returns></returns>
internal static bool PathIsNetworkPath(string path) internal static bool PathIsNetworkPath(string path)
{ {
// no other logic possible for now on linux #if LINUX
if (Platform.HasNetworkDriveSupport()) return false;
return WinPathIsNetworkPath(path); #else
else return WinPathIsNetworkPath(path);
return false; #endif
} }
internal static bool WinPathIsNetworkPath(string path) internal static bool WinPathIsNetworkPath(string path)
@@ -8202,7 +8192,7 @@ namespace Microsoft.PowerShell.Commands
{ {
if (!Platform.IsWindows) if (!Platform.IsWindows)
{ {
throw new Platform.PlatformNotSupportedException(); throw new PlatformNotSupportedException();
} }
using (SafeFileHandle handle = OpenReparsePoint(filePath, FileDesiredAccess.GenericRead)) using (SafeFileHandle handle = OpenReparsePoint(filePath, FileDesiredAccess.GenericRead))
@@ -8595,14 +8585,11 @@ namespace Microsoft.PowerShell.Commands
private static SafeFileHandle OpenReparsePoint(string reparsePoint, FileDesiredAccess accessMode) private static SafeFileHandle OpenReparsePoint(string reparsePoint, FileDesiredAccess accessMode)
{ {
if (Platform.SupportsReparsePoints()) #if LINUX
{ throw new PlatformNotSupportedException();
return WinOpenReparsePoint(reparsePoint,accessMode); #else
} return WinOpenReparsePoint(reparsePoint,accessMode);
else #endif
{
throw new Platform.PlatformNotSupportedException();
}
} }
private static SafeFileHandle WinOpenReparsePoint(string reparsePoint, FileDesiredAccess accessMode) private static SafeFileHandle WinOpenReparsePoint(string reparsePoint, FileDesiredAccess accessMode)
@@ -1589,9 +1589,12 @@ namespace System.Management.Automation
/// </returns> /// </returns>
internal static bool IsSingleFileSystemAbsolutePath(string path) internal static bool IsSingleFileSystemAbsolutePath(string path)
{ {
return Platform.HasSingleRootFilesystem() && #if LINUX
(path.StartsWith(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal) || return path.StartsWith(StringLiterals.DefaultPathSeparatorString, StringComparison.Ordinal)
path.StartsWith(StringLiterals.AlternatePathSeparatorString, StringComparison.Ordinal)); || path.StartsWith(StringLiterals.AlternatePathSeparatorString, StringComparison.Ordinal);
#else
return false;
#endif
} // IsSingleFileSystemAbsolutePath } // IsSingleFileSystemAbsolutePath
/// <summary> /// <summary>
@@ -136,11 +136,7 @@ namespace Microsoft.PowerShell.Commands
{ {
Collection<PSDriveInfo> drives = new Collection<PSDriveInfo>(); Collection<PSDriveInfo> drives = new Collection<PSDriveInfo>();
if (!Platform.HasRegistrySupport()) #if !LINUX
{
return drives;
}
drives.Add( drives.Add(
new PSDriveInfo( new PSDriveInfo(
"HKLM", "HKLM",
@@ -156,6 +152,7 @@ namespace Microsoft.PowerShell.Commands
"HKEY_CURRENT_USER", "HKEY_CURRENT_USER",
RegistryProviderStrings.HKCUDriveDescription, RegistryProviderStrings.HKCUDriveDescription,
null)); null));
#endif
return drives; return drives;
} // InitializeDefaultDrives } // InitializeDefaultDrives
@@ -58,13 +58,13 @@ namespace Microsoft.PowerShell.Commands.Internal
override protected bool ReleaseHandle() override protected bool ReleaseHandle()
{ {
if (!Platform.HasRegistrySupport()) #if LINUX
{ return true;
return true; #else
}
// Returns a Win32 error code, 0 for success // Returns a Win32 error code, 0 for success
int r = RegCloseKey(handle); int r = RegCloseKey(handle);
return r == 0; return r == 0;
#endif
} }
} }
} }
@@ -138,11 +138,9 @@ namespace System.Management.Automation
internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPolicy policy, string shellId) internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPolicy policy, string shellId)
{ {
if (!Platform.HasExecutionPolicy()) #if LINUX
{ throw new PlatformNotSupportedException();
throw new PlatformNotSupportedException(); #else
}
string executionPolicy = "Restricted"; string executionPolicy = "Restricted";
string preferenceKey = Utils.GetRegistryConfigurationPath(shellId); string preferenceKey = Utils.GetRegistryConfigurationPath(shellId);
const string PolicyKeyValueName = "ExecutionPolicy"; const string PolicyKeyValueName = "ExecutionPolicy";
@@ -227,6 +225,7 @@ namespace System.Management.Automation
break; break;
} }
} }
#endif
} }
// Clean up the parents of a registry key as long as they // Clean up the parents of a registry key as long as they
@@ -283,11 +282,9 @@ namespace System.Management.Automation
internal static ExecutionPolicy GetExecutionPolicy(string shellId, ExecutionPolicyScope scope) internal static ExecutionPolicy GetExecutionPolicy(string shellId, ExecutionPolicyScope scope)
{ {
if (!Platform.HasExecutionPolicy()) #if LINUX
{ return ExecutionPolicy.Unrestricted;
throw new PlatformNotSupportedException(); #else
}
switch (scope) switch (scope)
{ {
case ExecutionPolicyScope.Process: case ExecutionPolicyScope.Process:
@@ -368,6 +365,7 @@ namespace System.Management.Automation
} }
return ExecutionPolicy.Restricted; return ExecutionPolicy.Restricted;
#endif
} }
internal static ExecutionPolicy ParseExecutionPolicy(string policy) internal static ExecutionPolicy ParseExecutionPolicy(string policy)
@@ -1633,14 +1631,11 @@ namespace System.Management.Automation
/// <returns>AMSI_RESULT_DETECTED if malware was detected in the sample.</returns> /// <returns>AMSI_RESULT_DETECTED if malware was detected in the sample.</returns>
internal static AmsiNativeMethods.AMSI_RESULT ScanContent(string content, string sourceMetadata) internal static AmsiNativeMethods.AMSI_RESULT ScanContent(string content, string sourceMetadata)
{ {
if (Platform.HasAmsi()) #if LINUX
{ return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
return WinScanContent(content,sourceMetadata); #else
} return WinScanContent(content,sourceMetadata);
else #endif
{
return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
} }
internal static AmsiNativeMethods.AMSI_RESULT WinScanContent(string content, string sourceMetadata) internal static AmsiNativeMethods.AMSI_RESULT WinScanContent(string content, string sourceMetadata)
@@ -1730,14 +1725,9 @@ namespace System.Management.Automation
internal static void CurrentDomain_ProcessExit(object sender, EventArgs e) internal static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{ {
if (Platform.HasAmsi()) #if !LINUX
{ VerifyAmsiUninitializeCalled();
VerifyAmsiUninitializeCalled(); #endif
}
else
{
throw new PlatformNotSupportedException();
}
} }
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
@@ -1753,16 +1743,9 @@ namespace System.Management.Automation
/// </summary> /// </summary>
internal static void CloseSession() internal static void CloseSession()
{ {
if (Platform.HasAmsi()) #if !LINUX
{ WinCloseSession();
WinCloseSession(); #endif
}
else
{
// Porting note: cannot throw here because this is called whether or not
// AMSI was initialized in the first place
return;
}
} }
internal static void WinCloseSession() internal static void WinCloseSession()
@@ -1789,16 +1772,9 @@ namespace System.Management.Automation
/// </summary> /// </summary>
internal static void Uninitialize() internal static void Uninitialize()
{ {
if (Platform.HasAmsi()) #if !LINUX
{ WinUninitialize();
WinUninitialize(); #endif
}
else
{
// Porting note: cannot throw here because this is called whether or not
// AMSI was initialized in the first place
return;
}
} }
internal static void WinUninitialize() internal static void WinUninitialize()
@@ -130,12 +130,9 @@ namespace System.Management.Automation
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool IsComObject(this Type type) internal static bool IsComObject(this Type type)
{ {
if (!Platform.HasCom()) #if LINUX
{ return false;
return false; #elif CORECLR // Type.IsComObject(Type) is not in CoreCLR
}
#if CORECLR // Type.IsComObject(Type) is not in CoreCLR
return ComObjectType.IsAssignableFrom(type); return ComObjectType.IsAssignableFrom(type);
#else #else
return type.IsCOMObject; return type.IsCOMObject;
+3
View File
@@ -1,5 +1,6 @@
add_library(psl-native SHARED add_library(psl-native SHARED
getstat.cpp getstat.cpp
getlstat.cpp
getpwuid.cpp getpwuid.cpp
getuserfrompid.cpp getuserfrompid.cpp
getfileowner.cpp getfileowner.cpp
@@ -8,6 +9,8 @@ add_library(psl-native SHARED
getcomputername.cpp getcomputername.cpp
getlinkcount.cpp getlinkcount.cpp
getfullyqualifiedname.cpp getfullyqualifiedname.cpp
isfile.cpp
isdirectory.cpp
issymlink.cpp issymlink.cpp
isexecutable.cpp isexecutable.cpp
setdate.cpp setdate.cpp
+9 -9
View File
@@ -39,26 +39,25 @@
//! - ERROR_INVALID_FUNCTION: incorrect function //! - ERROR_INVALID_FUNCTION: incorrect function
//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters //! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
//! //!
//! @retval 1 if creation is successful //! @retval boolean successful
//! @retval 0 if createion failed
//! //!
int32_t CreateSymLink(const char *link, const char *target) bool CreateSymLink(const char *link, const char *target)
{ {
errno = 0; errno = 0;
// Check parameters // Check parameters
if (!link || !target) if (!link || !target)
{ {
errno = ERROR_INVALID_PARAMETER; errno = ERROR_INVALID_PARAMETER;
return 0; return false;
} }
int returnCode = symlink(target, link); int ret = symlink(target, link);
if (returnCode == 0) if (ret == 0)
{ {
return 1; return true;
} }
switch(errno) switch(errno)
@@ -102,5 +101,6 @@ int32_t CreateSymLink(const char *link, const char *target)
default: default:
errno = ERROR_INVALID_FUNCTION; errno = ERROR_INVALID_FUNCTION;
} }
return 0;
return false;
} }
+2 -1
View File
@@ -1,9 +1,10 @@
#pragma once #pragma once
#include "pal.h" #include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC PAL_BEGIN_EXTERNC
int32_t CreateSymLink(const char *link, const char *target); bool CreateSymLink(const char *link, const char *target);
PAL_END_EXTERNC PAL_END_EXTERNC
+95
View File
@@ -0,0 +1,95 @@
//! @file getlstat.cpp
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns the lstat of a file
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "getlstat.h"
//! @brief GetLStat returns the lstat of a file. This simply delegates to the
//! lstat() system call and maps errno to the expected values for GetLastError.
//!
//! GetLstat
//!
//! @param[in] path
//! @parblock
//! A pointer to the buffer that contains the file name
//!
//! char* is marshaled as an LPStr, which on Linux is UTF-8.
//! @endparblock
//!
//! @param[in] lstat
//! @parblock
//! A pointer to the buffer in which to place the lstat information
//! @endparblock
//!
//! @exception errno Passes these errors via errno to GetLastError:
//! - ERROR_INVALID_PARAMETER: parameter is not valid
//! - ERROR_FILE_NOT_FOUND: file does not exist
//! - ERROR_ACCESS_DENIED: access is denied
//! - ERROR_INVALID_ADDRESS: attempt to access invalid address
//! - ERROR_STOPPED_ON_SYMLINK: too many symbolic links
//! - ERROR_GEN_FAILURE: I/O error occurred
//! - ERROR_INVALID_NAME: file provided is not a symbolic link
//! - ERROR_INVALID_FUNCTION: incorrect function
//! - ERROR_BAD_PATH_NAME: pathname is too long
//! - ERROR_OUTOFMEMORY insufficient kernel memory
//!
//! @retval 0 if successful
//! @retval -1 if failed
//!
int32_t GetLStat(const char* path, struct stat* buf)
{
errno = 0;
if (!path)
{
errno = ERROR_INVALID_PARAMETER;
return -1;
}
int32_t ret = lstat(path, buf);
if (ret != 0)
{
switch(errno)
{
case EACCES:
errno = ERROR_ACCESS_DENIED;
break;
case EBADF:
errno = ERROR_FILE_NOT_FOUND;
break;
case EFAULT:
errno = ERROR_INVALID_ADDRESS;
break;
case ELOOP:
errno = ERROR_STOPPED_ON_SYMLINK;
break;
case ENAMETOOLONG:
errno = ERROR_GEN_FAILURE;
break;
case ENOENT:
errno = ERROR_FILE_NOT_FOUND;
break;
case ENOMEM:
errno = ERROR_NO_SUCH_USER;
break;
case ENOTDIR:
errno = ERROR_INVALID_NAME;
break;
case EOVERFLOW:
errno = ERROR_BUFFER_OVERFLOW;
break;
default:
errno = ERROR_INVALID_FUNCTION;
}
}
return ret;
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <sys/stat.h>
#include "pal.h"
PAL_BEGIN_EXTERNC
int32_t GetLStat(const char* path, struct stat* buf);
PAL_END_EXTERNC
+1 -2
View File
@@ -89,8 +89,7 @@ int32_t GetStat(const char* path, struct stat* buf)
default: default:
errno = ERROR_INVALID_FUNCTION; errno = ERROR_INVALID_FUNCTION;
} }
return -1;
} }
return 0; return ret;
} }
+50
View File
@@ -0,0 +1,50 @@
//! @file isdirectory.cpp
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns if the path is a directory
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <unistd.h>
#include "getstat.h"
#include "getpwuid.h"
#include "getfileowner.h"
#include "isdirectory.h"
//! @brief returns if the path is a directory; uses stat and so follows symlinks
//!
//! IsDirectory
//!
//! @param[in] path
//! @parblock
//! A pointer to the buffer that contains the file name
//!
//! char* is marshaled as an LPStr, which on Linux is UTF-8.
//! @endparblock
//!
//! @exception errno Passes this error via errno to GetLastError:
//! - ERROR_INVALID_PARAMETER: parameter is not valid
//!
//! @retval true if directory, false otherwise
//!
bool IsDirectory(const char* path)
{
errno = 0;
if (!path)
{
errno = ERROR_INVALID_PARAMETER;
return false;
}
struct stat buf;
int32_t ret = GetStat(path, &buf);
if (ret != 0)
{
return false;
}
return S_ISDIR(buf.st_mode);
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC
bool IsDirectory(const char* path);
PAL_END_EXTERNC
+8 -50
View File
@@ -1,5 +1,5 @@
//! @file isExecutable.cpp //! @file isexecutable.cpp
//! @author George FLeming <v-geflem@microsoft.com> //! @author George Fleming <v-geflem@microsoft.com>
//! @brief returns whether a file is executable //! @brief returns whether a file is executable
#include <errno.h> #include <errno.h>
@@ -11,7 +11,7 @@
//! //!
//! IsExecutable //! IsExecutable
//! //!
//! @param[in] fileName //! @param[in] path
//! @parblock //! @parblock
//! A pointer to the buffer that contains the file name //! A pointer to the buffer that contains the file name
//! //!
@@ -19,63 +19,21 @@
//! @endparblock //! @endparblock
//! //!
//! @exception errno Passes these errors via errno to GetLastError: //! @exception errno Passes these errors via errno to GetLastError:
//! - ERROR_FILE_NOT_FOUND: the system cannot find the file specified
//! - ERROR_INVALID_ADDRESS: attempt to access invalid address //! - ERROR_INVALID_ADDRESS: attempt to access invalid address
//! - ERROR_GEN_FAILURE: device attached to the system is not functioning
//! - ERROR_INVALID_NAME: filename, directory name, or volume label syntax is incorrect
//! - ERROR_INVALID_FUNCTION: incorrect function
//! - ERROR_INVALID_PARAMETER: parameter to access(2) call is incorrect
//! //!
//! @retval 1 if path is an executable //! @retval true if path is an executable, false otherwise
//! @retval 0 if path is not a executable
//! @retval -1 If the function fails.. To get extended error information, call GetLastError.
//! //!
int32_t IsExecutable(const char* fileName) bool IsExecutable(const char* path)
{ {
errno = 0; errno = 0;
// Check parameters // Check parameters
if (!fileName) if (!path)
{ {
errno = ERROR_INVALID_PARAMETER; errno = ERROR_INVALID_PARAMETER;
return -1; return false;
} }
int returnCode = access(fileName, X_OK); return access(path, X_OK) != -1;
if (returnCode == 0)
{
return 1;
}
switch(errno)
{
case EACCES:
return 0;
case EBADF:
case ENOENT:
errno = ERROR_FILE_NOT_FOUND;
break;
case EFAULT:
errno = ERROR_INVALID_ADDRESS;
break;
case ELOOP:
errno = ERROR_STOPPED_ON_SYMLINK;
break;
case EIO:
case ENOMEM:
errno = ERROR_GEN_FAILURE;
break;
case ENOTDIR:
case ENAMETOOLONG:
errno = ERROR_INVALID_NAME;
break;
case EINVAL:
errno = ERROR_INVALID_PARAMETER;
break;
default:
errno = ERROR_INVALID_FUNCTION;
}
return -1;
} }
+2 -1
View File
@@ -1,9 +1,10 @@
#pragma once #pragma once
#include "pal.h" #include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC PAL_BEGIN_EXTERNC
int32_t IsExecutable(const char* fileName); bool IsExecutable(const char* path);
PAL_END_EXTERNC PAL_END_EXTERNC
+43
View File
@@ -0,0 +1,43 @@
//! @file isfile.cpp
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief returns if the path exists
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include "getlstat.h"
#include "isfile.h"
//! @brief returns if the path is a file or directory
//!
//! IsFile
//!
//! @param[in] path
//! @parblock
//! A pointer to the buffer that contains the file name
//!
//! char* is marshaled as an LPStr, which on Linux is UTF-8.
//! @endparblock
//!
//! @exception errno Passes this error via errno to GetLastError:
//! - ERROR_INVALID_PARAMETER: parameter is not valid
//!
//! @retval true if path exists, false otherwise
//!
bool IsFile(const char* path)
{
errno = 0;
if (!path)
{
errno = ERROR_INVALID_PARAMETER;
return false;
}
struct stat buf;
return GetLStat(path, &buf) == 0;
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC
bool IsFile(const char* path);
PAL_END_EXTERNC
+14 -50
View File
@@ -7,13 +7,14 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <string> #include <string>
#include "getlstat.h"
#include "issymlink.h" #include "issymlink.h"
//! @brief IsSymLink determines if path is a symbolic link //! @brief IsSymlink determines if path is a symbolic link
//! //!
//! IsSymLink //! IsSymlink
//! //!
//! @param[in] fileName //! @param[in] path
//! @parblock //! @parblock
//! A pointer to the buffer that contains the file name //! A pointer to the buffer that contains the file name
//! //!
@@ -34,63 +35,26 @@
//! - ERROR_INVALID_FUNCTION: incorrect function //! - ERROR_INVALID_FUNCTION: incorrect function
//! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters //! - ERROR_BAD_PATH_NAME: pathname is too long, or contains invalid characters
//! //!
//! @retval 1 if path is a symbolic link //! @retval true if path is a symbolic link, false otherwise
//! @retval 0 if path is not a symbolic link
//! @retval -1 If the function fails.. To get extended error information, call GetLastError.
//! //!
int32_t IsSymLink(const char* fileName) bool IsSymLink(const char* path)
{ {
errno = 0;
errno = 0;
// Check parameters // Check parameters
if (!fileName) if (!path)
{ {
errno = ERROR_INVALID_PARAMETER; errno = ERROR_INVALID_PARAMETER;
return -1; return false;
} }
struct stat statBuf; struct stat buf;
int32_t ret = GetLStat(path, &buf);
int returnCode = lstat(fileName, &statBuf); if (ret != 0)
if (returnCode != 0)
{ {
switch(errno) return false;
{
case EACCES:
errno = ERROR_ACCESS_DENIED;
break;
case EBADF:
errno = ERROR_FILE_NOT_FOUND;
break;
case EFAULT:
errno = ERROR_INVALID_ADDRESS;
break;
case ELOOP:
errno = ERROR_STOPPED_ON_SYMLINK;
break;
case ENAMETOOLONG:
errno = ERROR_GEN_FAILURE;
break;
case ENOENT:
errno = ERROR_FILE_NOT_FOUND;
break;
case ENOMEM:
errno = ERROR_NO_SUCH_USER;
break;
case ENOTDIR:
errno = ERROR_INVALID_NAME;
break;
case EOVERFLOW:
errno = ERROR_BUFFER_OVERFLOW;
break;
default:
errno = ERROR_INVALID_FUNCTION;
}
return -1;
} }
return S_ISLNK(statBuf.st_mode) ? 1 : 0; return S_ISLNK(buf.st_mode);
} }
+2 -1
View File
@@ -1,9 +1,10 @@
#pragma once #pragma once
#include "pal.h" #include "pal.h"
#include <stdbool.h>
PAL_BEGIN_EXTERNC PAL_BEGIN_EXTERNC
int32_t IsSymLink(const char* fileName); bool IsSymLink(const char* path);
PAL_END_EXTERNC PAL_END_EXTERNC
+2
View File
@@ -9,6 +9,8 @@ add_executable(psl-native-test
test-getcomputername.cpp test-getcomputername.cpp
test-getlinkcount.cpp test-getlinkcount.cpp
test-getfullyqualifiedname.cpp test-getfullyqualifiedname.cpp
test-isdirectory.cpp
test-isfile.cpp
test-issymlink.cpp test-issymlink.cpp
test-isexecutable.cpp test-isexecutable.cpp
test-createsymlink.cpp test-createsymlink.cpp
+19 -19
View File
@@ -39,36 +39,36 @@ protected:
EXPECT_TRUE(dir != NULL); EXPECT_TRUE(dir != NULL);
// Create symbolic link to file // Create symbolic link to file
int ret1 = CreateSymLink(fileSymLink.c_str(), file); bool ret1 = CreateSymLink(fileSymLink.c_str(), file);
EXPECT_EQ(ret1, 1); EXPECT_TRUE(ret1);
// Create symbolic link to directory // Create symbolic link to directory
int ret2 = CreateSymLink(dirSymLink.c_str(), dir); bool ret2 = CreateSymLink(dirSymLink.c_str(), dir);
EXPECT_EQ(ret2, 1); EXPECT_TRUE(ret2);
} }
~CreateSymLinkTest() ~CreateSymLinkTest()
{ {
int ret; bool ret;
ret = unlink(fileSymLink.c_str()); ret = unlink(fileSymLink.c_str());
EXPECT_EQ(0, ret); EXPECT_FALSE(ret);
ret = unlink(dirSymLink.c_str()); ret = unlink(dirSymLink.c_str());
EXPECT_EQ(0, ret); EXPECT_FALSE(ret);
ret = unlink(file); ret = unlink(file);
EXPECT_EQ(0, ret); EXPECT_FALSE(ret);
ret = rmdir(dir); ret = rmdir(dir);
EXPECT_EQ(0, ret); EXPECT_FALSE(ret);
} }
}; };
TEST_F(CreateSymLinkTest, FilePathNameIsNull) TEST_F(CreateSymLinkTest, FilePathNameIsNull)
{ {
int retVal = CreateSymLink(NULL, NULL); bool retVal = CreateSymLink(NULL, NULL);
EXPECT_EQ(retVal, 0); EXPECT_FALSE(retVal);
EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
} }
@@ -82,8 +82,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
unlink(invalidLink.c_str()); unlink(invalidLink.c_str());
// Linux allows creation of symbolic link that points to an invalid file // Linux allows creation of symbolic link that points to an invalid file
int retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str()); bool retVal = CreateSymLink(invalidLink.c_str(), invalidFile.c_str());
EXPECT_EQ(retVal, 1); EXPECT_TRUE(retVal);
std::string target = FollowSymLink(invalidLink.c_str()); std::string target = FollowSymLink(invalidLink.c_str());
EXPECT_EQ(target, invalidFile); EXPECT_EQ(target, invalidFile);
@@ -93,8 +93,8 @@ TEST_F(CreateSymLinkTest, FilePathNameDoesNotExist)
TEST_F(CreateSymLinkTest, SymLinkToFile) TEST_F(CreateSymLinkTest, SymLinkToFile)
{ {
int retVal = IsSymLink(fileSymLink.c_str()); bool retVal = IsSymLink(fileSymLink.c_str());
EXPECT_EQ(1, retVal); EXPECT_TRUE(retVal);
std::string target = FollowSymLink(fileSymLink.c_str()); std::string target = FollowSymLink(fileSymLink.c_str());
char buffer[PATH_MAX]; char buffer[PATH_MAX];
@@ -104,8 +104,8 @@ TEST_F(CreateSymLinkTest, SymLinkToFile)
TEST_F(CreateSymLinkTest, SymLinkToDirectory) TEST_F(CreateSymLinkTest, SymLinkToDirectory)
{ {
int retVal = IsSymLink(dirSymLink.c_str()); bool retVal = IsSymLink(dirSymLink.c_str());
EXPECT_EQ(1, retVal); EXPECT_TRUE(retVal);
std::string target = FollowSymLink(dirSymLink.c_str()); std::string target = FollowSymLink(dirSymLink.c_str());
char buffer[PATH_MAX]; char buffer[PATH_MAX];
@@ -115,7 +115,7 @@ TEST_F(CreateSymLinkTest, SymLinkToDirectory)
TEST_F(CreateSymLinkTest, SymLinkAgain) TEST_F(CreateSymLinkTest, SymLinkAgain)
{ {
int retVal = CreateSymLink(fileSymLink.c_str(), file); bool retVal = CreateSymLink(fileSymLink.c_str(), file);
EXPECT_EQ(0, retVal); EXPECT_FALSE(retVal);
EXPECT_EQ(ERROR_FILE_EXISTS, errno); EXPECT_EQ(ERROR_FILE_EXISTS, errno);
} }
@@ -0,0 +1,31 @@
//! @file test-isdirectory.cpp
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief Tests IsDirectory
#include <gtest/gtest.h>
#include <errno.h>
#include <unistd.h>
#include "isdirectory.h"
TEST(IsDirectoryTest, RootIsDirectory)
{
EXPECT_TRUE(IsDirectory("/"));
}
TEST(IsDirectoryTest, BinLsIsNotDirectory)
{
EXPECT_FALSE(IsDirectory("/bin/ls"));
}
TEST(IsDirectoryTest, ReturnsFalseForFakeDirectory)
{
EXPECT_FALSE(IsDirectory("SomeMadeUpFileNameThatDoesNotExist"));
EXPECT_EQ(errno, ERROR_FILE_NOT_FOUND);
}
TEST(IsDirectoryTest, ReturnsFalseForNullInput)
{
EXPECT_FALSE(IsDirectory(NULL));
EXPECT_EQ(errno, ERROR_INVALID_PARAMETER);
}
+10 -20
View File
@@ -33,62 +33,52 @@ protected:
// First create a file // First create a file
int fd = mkstemp(fileTemplateBuf); int fd = mkstemp(fileTemplateBuf);
EXPECT_TRUE(fd != -1); EXPECT_TRUE(fd != -1);
file = fileTemplateBuf; file = fileTemplateBuf;
} }
~IsExecutableTest() ~IsExecutableTest()
{ {
int ret; EXPECT_FALSE(unlink(file));
ret = unlink(file);
EXPECT_EQ(0, ret);
} }
void ChangeFilePermission(const char* file, mode_t mode) void ChangeFilePermission(const char* file, mode_t mode)
{ {
int ret = chmod(file, mode); EXPECT_FALSE(chmod(file, mode));
EXPECT_EQ(ret, 0);
} }
}; };
TEST_F(IsExecutableTest, FilePathNameIsNull) TEST_F(IsExecutableTest, FilePathNameIsNull)
{ {
int32_t retVal = IsExecutable(NULL); EXPECT_FALSE(IsExecutable(NULL));
EXPECT_EQ(retVal, -1);
EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
} }
TEST_F(IsExecutableTest, FilePathNameDoesNotExist) TEST_F(IsExecutableTest, FilePathNameDoesNotExist)
{ {
std::string invalidFile = "/tmp/isexecutabletest_invalidFile"; std::string invalidFile = "/tmp/isexecutabletest_invalidFile";
int32_t retVal = IsExecutable(invalidFile.c_str()); EXPECT_FALSE(IsExecutable(invalidFile.c_str()));
EXPECT_EQ(retVal, -1);
EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno);
} }
TEST_F(IsExecutableTest, NormalFileIsNotIsexecutable) TEST_F(IsExecutableTest, NormalFileIsNotIsexecutable)
{ {
int32_t retVal = IsExecutable(file); EXPECT_FALSE(IsExecutable(file));
EXPECT_EQ(0, retVal);
ChangeFilePermission(file, mode_444); ChangeFilePermission(file, mode_444);
retVal = IsExecutable(file); EXPECT_FALSE(IsExecutable(file));
EXPECT_EQ(0, retVal);
} }
TEST_F(IsExecutableTest, FilePermission_700) TEST_F(IsExecutableTest, FilePermission_700)
{ {
ChangeFilePermission(file, mode_700); ChangeFilePermission(file, mode_700);
int32_t retVal = IsExecutable(file); EXPECT_TRUE(IsExecutable(file));
EXPECT_EQ(1, retVal);
} }
TEST_F(IsExecutableTest, FilePermission_777) TEST_F(IsExecutableTest, FilePermission_777)
{ {
ChangeFilePermission(file, mode_777); ChangeFilePermission(file, mode_777);
int32_t retVal = IsExecutable(file); EXPECT_TRUE(IsExecutable(file));
EXPECT_EQ(1, retVal);
} }
+30
View File
@@ -0,0 +1,30 @@
//! @file test-isfile.cpp
//! @author Andrew Schwartzmeyer <andschwa@microsoft.com>
//! @brief Tests Isfile
#include <gtest/gtest.h>
#include <errno.h>
#include <unistd.h>
#include "isfile.h"
TEST(IsFileTest, RootIsFile)
{
EXPECT_TRUE(IsFile("/"));
}
TEST(IsFileTest, BinLsIsFile)
{
EXPECT_TRUE(IsFile("/bin/ls"));
}
TEST(IsFileTest, CannotGetOwnerOfFakeFile)
{
EXPECT_FALSE(IsFile("SomeMadeUpFileNameThatDoesNotExist"));
EXPECT_EQ(errno, ERROR_FILE_NOT_FOUND);
}
TEST(IsFileTest, ReturnsFalseForNullInput)
{
EXPECT_FALSE(IsFile(NULL));
EXPECT_EQ(errno, ERROR_INVALID_PARAMETER);
}
+16 -31
View File
@@ -30,75 +30,60 @@ protected:
// First create a file // First create a file
int fd = mkstemp(fileTemplateBuf); int fd = mkstemp(fileTemplateBuf);
EXPECT_TRUE(fd != -1); EXPECT_TRUE(fd != -1);
file = fileTemplateBuf; file = fileTemplateBuf;
// Create a temp directory // Create a temp directory
dir = mkdtemp(dirTemplateBuf); dir = mkdtemp(dirTemplateBuf);
EXPECT_TRUE(dir != NULL); EXPECT_TRUE(dir != NULL);
// Create symbolic link to file // Create symbolic link to file
int ret1 = symlink(file, fileSymLink.c_str()); EXPECT_FALSE(symlink(file, fileSymLink.c_str()));
EXPECT_EQ(ret1, 0);
// Create symbolic link to directory // Create symbolic link to directory
int ret2 = symlink(dir, dirSymLink.c_str()); EXPECT_FALSE(symlink(dir, dirSymLink.c_str()));
EXPECT_EQ(ret2, 0);
} }
~isSymLinkTest() ~isSymLinkTest()
{ {
int ret; EXPECT_FALSE(unlink(fileSymLink.c_str()));
ret = unlink(fileSymLink.c_str()); EXPECT_FALSE(unlink(dirSymLink.c_str()));
EXPECT_EQ(0, ret);
ret = unlink(dirSymLink.c_str()); EXPECT_FALSE(unlink(file));
EXPECT_EQ(0, ret);
ret = unlink(file); EXPECT_FALSE(rmdir(dir));
EXPECT_EQ(0, ret);
ret = rmdir(dir);
EXPECT_EQ(0, ret);
} }
}; };
TEST_F(isSymLinkTest, FilePathNameIsNull) TEST_F(isSymLinkTest, FilePathNameIsNull)
{ {
int retVal = IsSymLink(NULL); EXPECT_FALSE(IsSymLink(NULL));
EXPECT_EQ(retVal, -1);
EXPECT_EQ(ERROR_INVALID_PARAMETER, errno); EXPECT_EQ(ERROR_INVALID_PARAMETER, errno);
} }
TEST_F(isSymLinkTest, FilePathNameDoesNotExist) TEST_F(isSymLinkTest, FilePathNameDoesNotExist)
{ {
std::string invalidFile = "/tmp/symlinktest_invalidFile"; std::string invalidFile = "/tmp/symlinktest_invalidFile";
int retVal = IsSymLink(invalidFile.c_str()); EXPECT_FALSE(IsSymLink(invalidFile.c_str()));
EXPECT_EQ(retVal, -1);
EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno); EXPECT_EQ(ERROR_FILE_NOT_FOUND, errno);
} }
TEST_F(isSymLinkTest, NormalFileIsNotSymLink) TEST_F(isSymLinkTest, NormalFileIsNotSymLink)
{ {
int retVal = IsSymLink(file); EXPECT_FALSE(IsSymLink(file));
EXPECT_EQ(0, retVal);
} }
TEST_F(isSymLinkTest, SymLinkToFile) TEST_F(isSymLinkTest, SymLinkToFile)
{ {
int retVal = IsSymLink(fileSymLink.c_str()); EXPECT_TRUE(IsSymLink(fileSymLink.c_str()));
EXPECT_EQ(1, retVal);
} }
TEST_F(isSymLinkTest, NormalDirectoryIsNotSymbLink) TEST_F(isSymLinkTest, NormalDirectoryIsNotSymbLink)
{ {
int retVal = IsSymLink(dir); EXPECT_FALSE(IsSymLink(dir));
EXPECT_EQ(0, retVal);
} }
TEST_F(isSymLinkTest, SymLinkToDirectory) TEST_F(isSymLinkTest, SymLinkToDirectory)
{ {
int retVal = IsSymLink(dirSymLink.c_str()); EXPECT_TRUE(IsSymLink(dirSymLink.c_str()));
EXPECT_EQ(1, retVal);
} }
-24
View File
@@ -15,30 +15,6 @@ namespace PSTests
Assert.True(Platform.IsCore); Assert.True(Platform.IsCore);
} }
[Fact]
public static void TestHasCom()
{
Assert.False(Platform.HasCom());
}
[Fact]
public static void TestHasAmsi()
{
Assert.False(Platform.HasAmsi());
}
[Fact]
public static void TestHasDriveAutoMounting()
{
Assert.False(Platform.HasDriveAutoMounting());
}
[Fact]
public static void TestHasRegistrySupport()
{
Assert.False(Platform.HasRegistrySupport());
}
[Fact] [Fact]
public static void TestGetUserName() public static void TestGetUserName()
{ {
@@ -0,0 +1,6 @@
Describe 'Get-CimClass' {
# Get-CimClass works only on windows
It 'can get CIM_Error CIM class' -Skip:(-not $IsWindows) {
Get-CimClass -ClassName CIM_Error | Should Not Be $null
}
}
@@ -2,17 +2,17 @@ function Clean-State
{ {
if (Test-Path $FullyQualifiedLink) if (Test-Path $FullyQualifiedLink)
{ {
Remove-Item $FullyQualifiedLink -Force Remove-Item $FullyQualifiedLink -Force
} }
if (Test-Path $FullyQualifiedFile) if (Test-Path $FullyQualifiedFile)
{ {
Remove-Item $FullyQualifiedFile -Force Remove-Item $FullyQualifiedFile -Force
} }
if (Test-Path $FullyQualifiedFolder) if (Test-Path $FullyQualifiedFolder)
{ {
Remove-Item $FullyQualifiedFolder -Force Remove-Item $FullyQualifiedFolder -Force
} }
} }
@@ -26,17 +26,17 @@ Describe "New-Item" {
$FullyQualifiedLink = Join-Path -Path $tmpDirectory -ChildPath $testlink $FullyQualifiedLink = Join-Path -Path $tmpDirectory -ChildPath $testlink
BeforeEach { BeforeEach {
Clean-State Clean-State
} }
It "should call the function without error" { It "should call the function without error" {
{ New-Item -Name $testfile -Path $tmpDirectory -ItemType file } | Should Not Throw { New-Item -Name $testfile -Path $tmpDirectory -ItemType file } | Should Not Throw
} }
It "Should create a file without error" { It "Should create a file without error" {
New-Item -Name $testfile -Path $tmpDirectory -ItemType file New-Item -Name $testfile -Path $tmpDirectory -ItemType file
Test-Path $FullyQualifiedFile | Should Be $true Test-Path $FullyQualifiedFile | Should Be $true
$fileInfo = Get-ChildItem $FullyQualifiedFile $fileInfo = Get-ChildItem $FullyQualifiedFile
$fileInfo.Target | Should Be $null $fileInfo.Target | Should Be $null
@@ -44,72 +44,72 @@ Describe "New-Item" {
} }
It "Should create a folder without an error" { It "Should create a folder without an error" {
New-Item -Name newDirectory -Path $tmpDirectory -ItemType directory New-Item -Name newDirectory -Path $tmpDirectory -ItemType directory
Test-Path $FullyQualifiedFolder | Should Be $true Test-Path $FullyQualifiedFolder | Should Be $true
} }
It "Should create a file using the ni alias" { It "Should create a file using the ni alias" {
ni -Name $testfile -Path $tmpDirectory -ItemType file ni -Name $testfile -Path $tmpDirectory -ItemType file
Test-Path $FullyQualifiedFile | Should Be $true Test-Path $FullyQualifiedFile | Should Be $true
} }
It "Should create a file using the Type alias instead of ItemType" { It "Should create a file using the Type alias instead of ItemType" {
New-Item -Name $testfile -Path $tmpDirectory -Type file New-Item -Name $testfile -Path $tmpDirectory -Type file
Test-Path $FullyQualifiedFile | Should Be $true Test-Path $FullyQualifiedFile | Should Be $true
} }
It "Should create a file with sample text inside the file using the Value switch" { It "Should create a file with sample text inside the file using the Value switch" {
$expected = "This is test string" $expected = "This is test string"
New-Item -Name $testfile -Path $tmpDirectory -ItemType file -Value $expected New-Item -Name $testfile -Path $tmpDirectory -ItemType file -Value $expected
Test-Path $FullyQualifiedFile | Should Be $true Test-Path $FullyQualifiedFile | Should Be $true
Get-Content $FullyQualifiedFile | Should Be $expected Get-Content $FullyQualifiedFile | Should Be $expected
} }
It "Should not create a file when the Name switch is not used and only a directory specified" { It "Should not create a file when the Name switch is not used and only a directory specified" {
#errorAction used because permissions issue in Windows #errorAction used because permissions issue in Windows
New-Item -Path $tmpDirectory -ItemType file -ErrorAction SilentlyContinue New-Item -Path $tmpDirectory -ItemType file -ErrorAction SilentlyContinue
Test-Path $FullyQualifiedFile | Should Be $false Test-Path $FullyQualifiedFile | Should Be $false
} }
It "Should create a file when the Name switch is not used but a fully qualified path is specified" { It "Should create a file when the Name switch is not used but a fully qualified path is specified" {
New-Item -Path $FullyQualifiedFile -ItemType file New-Item -Path $FullyQualifiedFile -ItemType file
Test-Path $FullyQualifiedFile | Should Be $true Test-Path $FullyQualifiedFile | Should Be $true
} }
It "Should be able to create a multiple items in different directories" { It "Should be able to create a multiple items in different directories" {
$FullyQualifiedFile2 = Join-Path -Path $tmpDirectory -ChildPath test2.txt $FullyQualifiedFile2 = Join-Path -Path $tmpDirectory -ChildPath test2.txt
New-Item -ItemType file -Path $FullyQualifiedFile, $FullyQualifiedFile2 New-Item -ItemType file -Path $FullyQualifiedFile, $FullyQualifiedFile2
Test-Path $FullyQualifiedFile | Should Be $true Test-Path $FullyQualifiedFile | Should Be $true
Test-Path $FullyQualifiedFile2 | Should Be $true Test-Path $FullyQualifiedFile2 | Should Be $true
Remove-Item $FullyQualifiedFile2 Remove-Item $FullyQualifiedFile2
} }
It "Should be able to call the whatif switch without error" { It "Should be able to call the whatif switch without error" {
{ New-Item -Name testfile.txt -Path $tmpDirectory -ItemType file -WhatIf } | Should Not Throw { New-Item -Name testfile.txt -Path $tmpDirectory -ItemType file -WhatIf } | Should Not Throw
} }
It "Should not create a new file when the whatif switch is used" { It "Should not create a new file when the whatif switch is used" {
New-Item -Name $testfile -Path $tmpDirectory -ItemType file -WhatIf New-Item -Name $testfile -Path $tmpDirectory -ItemType file -WhatIf
Test-Path $FullyQualifiedFile | Should Be $false Test-Path $FullyQualifiedFile | Should Be $false
} }
It "Should create a symbolic link of a file without error" { It "Should create a symbolic link of a file without error" {
New-Item -Name $testfile -Path $tmpDirectory -ItemType file New-Item -Name $testfile -Path $tmpDirectory -ItemType file
Test-Path $FullyQualifiedFile | Should Be $true Test-Path $FullyQualifiedFile | Should Be $true
New-Item -ItemType SymbolicLink -Target $FullyQualifiedFile -Name $testlink -Path $tmpDirectory New-Item -ItemType SymbolicLink -Target $FullyQualifiedFile -Name $testlink -Path $tmpDirectory
Test-Path $FullyQualifiedLink | Should Be $true Test-Path $FullyQualifiedLink | Should Be $true
$fileInfo = Get-ChildItem $FullyQualifiedLink $fileInfo = Get-ChildItem $FullyQualifiedLink
$fileInfo.Target | Should Match ([regex]::Escape($FullyQualifiedFile)) $fileInfo.Target | Should Match ([regex]::Escape($FullyQualifiedFile))
@@ -128,18 +128,18 @@ Describe "New-Item" {
} }
It "Should create a symbolic link from directory without error" { It "Should create a symbolic link from directory without error" {
New-Item -Name $testFolder -Path $tmpDirectory -ItemType directory New-Item -Name $testFolder -Path $tmpDirectory -ItemType directory
Test-Path $FullyQualifiedFolder | Should Be $true Test-Path $FullyQualifiedFolder | Should Be $true
New-Item -ItemType SymbolicLink -Target $FullyQualifiedFolder -Name $testlink -Path $tmpDirectory New-Item -ItemType SymbolicLink -Target $FullyQualifiedFolder -Name $testlink -Path $tmpDirectory
Test-Path $FullyQualifiedLink | Should Be $true Test-Path $FullyQualifiedLink | Should Be $true
$fileInfo = Get-ChildItem $FullyQualifiedLink $fileInfo = Get-ChildItem $FullyQualifiedLink
$fileInfo.Target | Should Match ([regex]::Escape($FullyQualifiedFolder)) $fileInfo.Target | Should Match ([regex]::Escape($FullyQualifiedFolder))
$fileInfo.LinkType | Should Be "SymbolicLink" $fileInfo.LinkType | Should Be "SymbolicLink"
# Remove the link explicitly to avoid broken symlink issue # Remove the link explicitly to avoid broken symlink issue
Remove-Item $FullyQualifiedLink -Force Remove-Item $FullyQualifiedLink -Force
} }
It "Should create a hard link of a file without error" { It "Should create a hard link of a file without error" {
@@ -1,24 +1,24 @@
Describe "ExecutionPolicy" { Describe "ExecutionPolicy" {
Context "Check Get-ExecutionPolicy behavior" { Context "Check Get-ExecutionPolicy behavior" {
It "Should throw PlatformNotSupported when not on Windows" -Skip:$IsWindows { It "Should unrestricted when not on Windows" -Skip:$IsWindows {
{ Get-ExecutionPolicy } | Should Throw "Operation is not supported on this platform." Get-ExecutionPolicy | Should Be Unrestricted
} }
It "Should return Microsoft.Powershell.ExecutionPolicy PSObject on Windows" -Skip:($IsLinux -Or $IsOSX) { It "Should return Microsoft.Powershell.ExecutionPolicy PSObject on Windows" -Skip:($IsLinux -Or $IsOSX) {
(Get-ExecutionPolicy).GetType() | Should Be Microsoft.Powershell.ExecutionPolicy (Get-ExecutionPolicy).GetType() | Should Be Microsoft.Powershell.ExecutionPolicy
} }
} }
Context "Check Set-ExecutionPolicy behavior" { Context "Check Set-ExecutionPolicy behavior" {
It "Should throw PlatformNotSupported when not on Windows" -Skip:$IsWindows { It "Should throw PlatformNotSupported when not on Windows" -Skip:$IsWindows {
{ Set-ExecutionPolicy Unrestricted } | Should Throw "Operation is not supported on this platform." { Set-ExecutionPolicy Unrestricted } | Should Throw "Operation is not supported on this platform."
} }
It "Should succeed on Windows" -Skip:($IsLinux -Or $IsOSX) { It "Should succeed on Windows" -Skip:($IsLinux -Or $IsOSX) {
# We use the Process scope to avoid affecting the system # We use the Process scope to avoid affecting the system
# Unrestricted is assumed "safe", otherwise these tests would not be running # Unrestricted is assumed "safe", otherwise these tests would not be running
{ Set-ExecutionPolicy -Force -Scope Process -ExecutionPolicy Unrestricted } | Should Not Throw { Set-ExecutionPolicy -Force -Scope Process -ExecutionPolicy Unrestricted } | Should Not Throw
} }
} }
} }
@@ -13,6 +13,16 @@ Describe "PSReadLine" {
$module.Version | Should Be "1.2" $module.Version | Should Be "1.2"
} }
It "Should use Emacs Bindings on Linux and OS X" -skip:$IsWindows {
(Get-PSReadLineOption).EditMode | Should Be Emacs
(Get-PSReadlineKeyHandler | where { $_.Key -eq "Ctrl+A" }).Function | Should Be BeginningOfLine
}
It "Should use Windows Bindings on Windows" -skip:(-not $IsWindows) {
(Get-PSReadLineOption).EditMode | Should Be Windows
(Get-PSReadlineKeyHandler | where { $_.Key -eq "Ctrl+A" }).Function | Should Be SelectAll
}
It "Should set the edit mode" { It "Should set the edit mode" {
Set-PSReadlineOption -EditMode Windows Set-PSReadlineOption -EditMode Windows
(Get-PSReadlineKeyHandler | where { $_.Key -eq "Ctrl+A" }).Function | Should Be SelectAll (Get-PSReadlineKeyHandler | where { $_.Key -eq "Ctrl+A" }).Function | Should Be SelectAll
+753
View File
@@ -0,0 +1,753 @@
Describe "ParserTests (admin\monad\tests\monad\src\engine\core\ParserTests.cs)" {
BeforeAll {
$functionDefinitionFile = Join-Path -Path $TestDrive -ChildPath "functionDefinition.ps1"
$functionDefinition = @'
function testcmd-parserbvt
{
[CmdletBinding()]
param (
[Parameter(Position = 0)]
[string] $Property1 = "unset",
[Parameter(Position = 1)]
[string] $Property2 = "unset",
[Parameter(Position = 2)]
[string] $Property3 = "unset",
[Parameter()]
[ValidateSet("default","array","object","nestedobject","struct","mshobject","nulltostring")]
[string]$ReturnType = "default"
)
BEGIN {}
PROCESS {
if ( ! $ReturnType ) {
$ReturnType = "default"
}
switch ( $ReturnType )
{
"default" {
$result = "$Property1;$Property2;$Property3"
break
}
"array" {
$result = 1,2,3
break
}
"object" {
$result = new-object psobject
break
}
"nestedobject" {
$result = [pscustomobject]@{Name="John";Person=[pscustomobject]@{Name="John";Age=30}}
break
}
"struct" {
$result = [pscustomobject]@{Name="John";Age=30}
break
}
"mshobject" {
$result = new-object psobject
break
}
"nulltostring" {
$result = $null
break
}
default {
throw ([invalidoperationexception]::new("ReturnType parameter wasn't of any Expected value!"))
break
}
}
return $result
}
END {}
}
'@
$functionDefinition>$functionDefinitionFile
$PowerShell = [powershell]::Create()
function ExecuteCommand {
param ([string]$command)
try {
$PowerShell.AddScript(". $functionDefinitionFile").Invoke()
$PowerShell.AddScript($command).Invoke()
}
finally {
$PowerShell.Commands.Clear()
}
}
}
BeforeEach {
$testfile = Join-Path -Path $TestDrive -ChildPath "testfile.ps1"
$shellfile = Join-Path -Path $TestDrive -ChildPath "testfile.cmd"
$testfolder1 = Join-Path -Path $TestDrive -ChildPath "dir1"
$testfolder2 = Join-Path -Path $testfolder1 -ChildPath "dir2"
if(-not(Test-Path $testfolder1))
{
New-Item $testfolder1 -Type Directory
}
if(-not(Test-Path $testfolder2))
{
New-Item $testfolder2 -Type Directory
}
$testdirfile1 = Join-Path -Path $testfolder2 -ChildPath "testdirfile1.txt"
$testdirfile2 = Join-Path -Path $testfolder2 -ChildPath "testdirfile2.txt"
"">$testdirfile1
"">$testdirfile2
}
AfterEach {
$PowerShell.Commands.Clear()
if(Test-Path $testfile)
{
Remove-Item $testfile
}
if(Test-Path $shellfile)
{
Remove-Item $shellfile
}
if(Test-Path $testdirfile1)
{
Remove-Item $testdirfile1
}
if(Test-Path $testdirfile2)
{
Remove-Item $testdirfile2
}
if(Test-Path $testfolder2)
{
Remove-Item $testfolder2
}
if(Test-Path $testfolder1)
{
Remove-Item $testfolder1
}
}
AfterAll {
if(Test-Path $functionDefinitionFile)
{
Remove-Item $functionDefinitionFile
}
}
It "Throws a syntax error when parsing a string without a closing quote. (line 164)" {
try {
ExecuteCommand '"This is a test'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "IncompleteParseException"
}
}
It "Throws an error if an open parenthesis is not closed (line 176)" {
try {
ExecuteCommand "("
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | should be "IncompleteParseException"
}
}
It "Throws an exception if the the first statement starts with an empty pipe element (line 188)" {
try {
ExecuteCommand "| get-location"
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | should be "ParseException"
}
}
It "Throws an CommandNotFoundException exception if using a label in front of an if statement is not allowed. (line 225)"{
ExecuteCommand ":foo if ($x -eq 3) { 1 }"
$PowerShell.HadErrors | should be $true
$PowerShell.Streams.Error.FullyQualifiedErrorId | should be "CommandNotFoundException"
}
It "Pipe an expression into a value expression. (line 237)" {
try {
ExecuteCommand "testcmd-parserbvt | 3"
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | should be "ParseException"
}
try {
ExecuteCommand "testcmd-parserbvt | $(1 + 1)"
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | should be "ParseException"
}
try {
ExecuteCommand "testcmd-parserbvt | 'abc'"
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | should be "ParseException"
}
}
It "Throws when you pipe into a value expression (line 238)" {
foreach($command in "1;2;3|3",'1;2;3|$(1+1)',"1;2;3|'abc'") {
try {
ExecuteCommand $command
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
}
It "Throws an incomplete parse exeception when a comma follows an expression (line 247)" {
try {
ExecuteCommand "(1+ 1),"
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "IncompleteParseException"
}
}
It "Test that invoke has a higher precedence for a script than for an executable. (line 279)" {
"1">$testfile
$result = ExecuteCommand ". $testfile"
$result | should be 1
}
It "This test will check that a path is correctly interpreted when using '..' and '.' (line 364)" {
$result = ExecuteCommand "set-location $TestDrive; get-childitem dir1\.\.\.\..\dir1\.\dir2\..\..\dir1\.\dir2"
$result.Count | should be 2
$result[0].Name | should be "testdirfile1.txt"
$result[1].Name | should be "testdirfile2.txt"
}
It "This test will check that the parser can handle a mix of forward slashes and back slashes in the path (line 417)" {
$result = ExecuteCommand "get-childitem $TestDrive/dir1/./.\.\../dir1/.\dir2\../..\dir1\.\dir2"
$result.Count | should be 2
$result[0].Name | should be "testdirfile1.txt"
$result[1].Name | should be "testdirfile2.txt"
}
It "This test checks that the asterisk globs as expected. (line 545)" {
$result = ExecuteCommand "get-childitem $TestDrive/dir1\dir2\*.txt"
$result.Count | should be 2
$result[0].Name | should be "testdirfile1.txt"
$result[1].Name | should be "testdirfile2.txt"
}
It "This test checks that we can use a range for globbing: [1-2] (line 557)" {
$result = ExecuteCommand "get-childitem $TestDrive/dir1\dir2\testdirfile[1-2].txt"
$result.Count | should be 2
$result[0].Name | should be "testdirfile1.txt"
$result[1].Name | should be "testdirfile2.txt"
}
It "This test will check that escaping the $ sigil inside single quotes simply returns the $ character. (line 583)" {
$result = ExecuteCommand "'`$'"
$result | should be "`$"
}
It "Test that escaping a space just returns that space. (line 593)" {
$result = ExecuteCommand '"foo` bar"'
$result | should be "foo bar"
}
It "Test that escaping any character with no special meaning just returns that char. (line 602)" {
$result = ExecuteCommand '"fo`obar"'
$result | should be "foobar"
}
Context "Test that we support all of the C# escape sequences. We use the ` instead of \. (line 613)" {
# the first two sequences are tricky, because we need to provide something to
# execute without causing an incomplete parse error
$tests = @{ sequence = "write-output ""`'"""; expected = ([char]39) },
@{ sequence = 'write-output "`""'; expected = ([char]34) },
# this is a string, of 2 "\", the initial backtick should essentially be ignored
@{ sequence = '"`\\"'; expected = '\\' },
# control sequences
@{ sequence = '"`0"'; expected = ([char]0) }, # null
@{ sequence = '"`a"'; expected = ([char]7) },
@{ sequence = '"`b"'; expected = ([char]8) }, # backspace
@{ sequence = '"`f"'; expected = ([char]12) }, # form
@{ sequence = '"`n"'; expected = ([char]10) }, # newline
@{ sequence = '"`r"'; expected = ([char]13) }, # return
@{ sequence = '"`t"'; expected = ([char]9) }, # tab
@{ sequence = '"`v"'; expected = ([char]11) }
It "C# escape sequence <sequence> is supported using `` instead of \. (line 613)" -TestCases $tests {
param ( $sequence, $expected )
$result = ExecuteCommand $sequence
$result | should be $expected
}
}
It "This test checks that array substitution occurs inside double quotes. (line 646)" {
$result = ExecuteCommand '$MyArray = "a","b";"Hello $MyArray"'
$result | should be "Hello a b"
}
It "This tests declaring an array in nested variable tables. (line 761)" {
$result = ExecuteCommand "`$Variable:vtbl1:vtbl2:b=@(5,6);`$Variable:vtbl1:vtbl2:b"
$result.Count | should be 2
$result[0] | should be 5
$result[1] | should be 6
}
It "Test a simple multiple assignment. (line 773)" {
$result = ExecuteCommand '$one,$two = 1,2,3; "One = $one"; "Two = $two"'
$result.Count | should be 2
$result[0] | should be "One = 1"
$result[1] | should be "Two = 2 3"
}
It "Tests script, global and local scopes from a function inside a script. (line 824)" {
"`$var = 'script';function func { `$var; `$var = 'local'; `$local:var; `$script:var; `$global:var };func;`$var;">$testfile
ExecuteCommand "`$var = 'global'"
$result = ExecuteCommand "$testfile"
$result.Count | should be 5
$result[0] | should be "script"
$result[1] | should be "local"
$result[2] | should be "script"
$result[3] | should be "global"
$result[4] | should be "script"
}
It "Use break inside of a loop that is inside another loop. (line 945)" {
$commands = " while (1) { 1; while(1) { 2; break; 3; }; 4; break; 5; } ",
" for (;;) { 1; for(;;) { 2; break; 3; }; 4; break; 5; } ",
" foreach(`$a in 1,2,3) { 1; foreach( `$b in 1,2,3 ) { 2; break; 3; }; 4; break; 5; } "
$results = "1", "2", "4"
$i = 0
for(;$i -lt $commands.Count;$i++)
{
$result = ExecuteCommand $commands[$i]
$result | should be $results
}
}
It "Use break in two loops with same label. (line 967)" {
$commands = " :foo while (1) { 1; :foo while(1) { 2; break foo; 3; }; 4; break; 5; } ",
" :foo for (;;) { 1; :foo for(;;) { 2; break foo; 3; }; 4; break; 5; } ",
" :foo foreach(`$a in 1,2,3) { 1; :foo foreach( `$b in 1,2,3 ) { 2; break foo; 3; }; 4; break; 5; } "
$results = "1", "2", "4"
$i = 0
for(;$i -lt $commands.Count;$i++)
{
$result = ExecuteCommand $commands[$i]
$result | should be $results
}
}
It "Try continue inside of different loop statements. (line 1039)" {
$commands = " `$a = 0; while (`$a -lt 2) { `$a; `$a += 1; continue; 2; } ",
" for (`$a = 0;`$a -lt 2; `$a += 1) { 9; continue; 3; } ",
" foreach(`$a in 0,1) { `$a; continue; 2; } "
$result = ExecuteCommand $commands[0]
$result | should be "0", "1"
$result = ExecuteCommand $commands[1]
$result | should be "9", "9"
$result = ExecuteCommand $commands[2]
$result | should be "0", "1"
}
It "Use a label to continue an inner loop. (line 1059)" {
$commands = " `$x = 0; while (`$x -lt 1) { `$x += 1; `$x; `$a = 0; :foo while(`$a -lt 2) { `$a += 1; `$a; continue foo; 3; }; 4; continue; 5; } ",
" for (`$x = 0;`$x -lt 1;`$x += 1) { 1; :foo for(`$a = 0; `$a -lt 2; `$a += 1) { `$a; continue foo; 3; }; 4; continue; 5; } ",
" foreach(`$a in 1) { 1; :foo foreach( `$b in 1,2 ) { `$b; continue foo; 3; }; 4; continue; 5; } "
$result = ExecuteCommand $commands[0]
$result | should be "1", "1", "2", "4"
$result = ExecuteCommand $commands[1]
$result | should be "1", "0", "1", "4"
$result = ExecuteCommand $commands[2]
$result | should be "1", "1", "2", "4"
}
It "Use continue with a label on a nested loop. (line 1059)" {
$commands = " `$x = 0; :foo while (`$x -lt 2) { `$x; `$x += 1; :bar while(1) { 2; continue foo; 3; }; 4; continue; 5; } ",
" :foo for (`$x = 0;`$x -lt 2;`$x += 1) { 1; :bar for(;;) { 2; continue foo; 3; }; 4; continue; 5; } ",
" :foo foreach(`$a in 1,2) { 1; :bar foreach( `$b in 1,2,3 ) { 2; continue foo; 3; }; 4; continue; 5; } "
$result = ExecuteCommand $commands[0]
$result | should be "0", "2", "1", "2"
$result = ExecuteCommand $commands[1]
$result | should be "1", "2", "1", "2"
$result = ExecuteCommand $commands[2]
$result | should be "1", "2", "1", "2"
}
It "This test will check that it is a syntax error to use if without a code block. (line 1141)" {
try {
ExecuteCommand 'if ("true")'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "IncompleteParseException"
}
}
It "This test will check that it is a syntax error if the if condition is not complete. (line 1150)" {
try {
ExecuteCommand 'if ('
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "IncompleteParseException"
}
}
It "This test will check that it is a syntax error to have an if condition without parentheses. (line 1159)" {
try {
ExecuteCommand 'if "true" { 1} else {2}'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
It "This test will check that the parser throws a syntax error when the if condition is missing the closing parentheses. (line 1168)" {
try {
ExecuteCommand 'if ("true" { 1};'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
It "This test will check that it is a syntax error to have an else keyword without the corresponding code block. (line 1177)" {
try {
ExecuteCommand 'if ("true") {1} else'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "IncompleteParseException"
}
}
It "This test will check that the parser throws a syntax error when a foreach loop is not complete. (line 1238)" {
try {
ExecuteCommand '$count=0;$files = $(get-childitem / -filter *.txt );foreach ($i ;$count'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
It "This test will check that the parser throws a syntax error if the foreach loop is not complete. (line 1248)" {
try {
ExecuteCommand '$count=0;$files = $(get-childitem / -filter *.txt );foreach ($i in ;$count'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
It "This will test that the parser throws a syntax error if the foreach loop is missing a closing parentheses. (line 1258)" {
try {
ExecuteCommand '$count=0;$files = $(get-childitem / -filter *.txt );foreach ($i in $files ;$count'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
It "Test that if an exception is thrown from the try block it will be caught in the apprpropriate catch block and that the finally block will run regardless of whether an exception is thrown. (line 1317)" {
$result = ExecuteCommand 'try { try { throw (new-object System.ArgumentException) } catch [System.DivideByZeroException] { } finally { "Finally" } } catch { $_.Exception.GetType().FullName }'
$result | should be "Finally", "System.ArgumentException"
}
It "Test that null can be passed to a method that expects a reference type. (line 1439)" {
$result = ExecuteCommand '$test = "String";$test.CompareTo($())'
$result | should be 1
}
It "Tests that command expansion operators can be used as a parameter to an object method. (line 1507)" {
$result = ExecuteCommand '$test = "String";$test.SubString($("hello" | foreach-object { $_.length - 2 } ))'
$result | should be "ing"
}
It "Test that & can be used as a parameter as long as it is quoted. (line 1606)" {
$result = ExecuteCommand 'testcmd-parserbvt `&get-childitem'
$result | should be "&get-childitem;unset;unset"
$result = ExecuteCommand 'testcmd-parserbvt `&*'
$result | should be "&*;unset;unset"
}
It "Run a command with parameters. (line 1621)" {
$result = ExecuteCommand 'testcmd-parserBVT -Property1 set'
$result | should be "set;unset;unset"
}
It "Test that typing a number at the command line will return that number. (line 1630)" {
$result = ExecuteCommand '3'
$result | should be "3"
$result.gettype() |should be ([int])
}
It "This test will check that an msh script can be run without invoking. (line 1641)" {
"1">$testfile
$result = ExecuteCommand ". $testfile"
$result | should be 1
}
It "Test that an alias is resolved before a function. (line 1657)" {
$result = ExecuteCommand 'set-alias parserInvokeTest testcmd-parserBVT;function parserInvokeTest { 3 };parserInvokeTest'
$result | should be "unset;unset;unset"
}
It "Test that functions are resolved before cmdlets. (line 1678)"{
$result = ExecuteCommand 'function testcmd-parserBVT { 3 };testcmd-parserBVT'
$result | should be "3"
}
It "Check that a command that uses shell execute can be run from the command line and that no exception is thrown. (line 1702)" {
if ( $IsLinux -or $IsOSX ) {
# because we execute on *nix based on executable bit, and the file name doesn't matter
# so we can use the same filename as for windows, just make sure it's executable with chmod
"#!/bin/sh`necho ""Hello World""" | out-file -encoding ASCII $shellfile
/bin/chmod +x $shellfile
}
else {
"@echo Hello, I'm a Cmd script!">$shellfile
}
{ ExecuteCommand "$shellfile" } | Should Not Throw
}
Context "Boolean Tests (starting at line 1723 to line 1772)" {
$testData = @(
@{ Script = '"False"'; Expected = $true }
@{ Script = 'if ("A") { $true } else { $false }'; Expected = $true }
@{ Script = 'if (" ") { $true } else { $false }'; Expected = $true }
@{ Script = 'if ("String with spaces") { $true } else { $false }'; Expected = $true }
@{ Script = 'if ("DoubleQuoted") { $true } else { $false }'; Expected = $true }
@{ Script = 'if ("StringWithNullVar$aEmbedded") { $true } else { $false }'; Expected = $true }
@{ Script = 'if (0) { $true } else { $false }'; Expected = $false }
@{ Script = '$a = $(0);if ($a) { $true } else { $false }'; Expected = $false }
@{ Script = '$obj = testcmd-parserBVT -ReturnType object;if ($obj) { $true } else { $false }'; Expected = $true }
)
It "<Script> should return <Expected>" -TestCases $testData {
param ( $Script, $Expected )
ExecuteCommand $Script | Should be $Expected
}
}
Context "Comparison operator Tests (starting at line 1785 to line 1842)" {
$testData = @(
@{ Script = 'if (1 -and 1) { $true } else { $false }'; Expected = $true }
@{ Script = 'if (1 -and 0) { $true } else { $false }'; Expected = $false }
@{ Script = 'if (0 -and 1) { $true } else { $false }'; Expected = $false }
@{ Script = 'if (0 -and 0) { $true } else { $false }'; Expected = $false }
@{ Script = 'if (1 -or 1) { $true } else { $false }'; Expected = $true }
@{ Script = 'if (1 -or 0) { $true } else { $false }'; Expected = $true }
@{ Script = 'if (0 -or 1) { $true } else { $false }'; Expected = $true }
@{ Script = 'if (0 -or 0) { $true } else { $false }'; Expected = $false }
#-eq
@{ Script = 'if ($False -eq $True -and $False) { $true } else { $false }'; Expected = $false }
@{ Script = 'if ($False -and $True -eq $False) { $true } else { $false }'; Expected = $false }
#-ieq
@{ Script = 'if ($False -ieq $True -and $False) { $true } else { $false }'; Expected = $false }
@{ Script = 'if ($False -and $True -ieq $False) { $true } else { $false }'; Expected = $false }
#-le
@{ Script = 'if ($False -le $True -and $False) { $true } else { $false }'; Expected = $false }
@{ Script = 'if ($False -and $True -le $False) { $true } else { $false }'; Expected = $false }
#-ile
@{ Script = 'if ($False -ile $True -and $False) { $true } else { $false }'; Expected = $false }
@{ Script = 'if ($False -and $True -ile $False) { $true } else { $false }'; Expected = $false }
#-ge
@{ Script = 'if ($False -ge $True -and $False) { $true } else { $false }'; Expected = $false }
@{ Script = 'if ($False -and $True -ge $False) { $true } else { $false }'; Expected = $false }
#-ige
@{ Script = 'if ($False -ige $True -and $False) { $true } else { $false }'; Expected = $false }
@{ Script = 'if ($False -and $True -ige $False) { $true } else { $false }'; Expected = $false }
#-like
@{ Script = 'if ($False -like $True -and $False) { $true } else { $false }'; Expected = $false }
@{ Script = 'if ($False -and $True -like $False) { $true } else { $false }'; Expected = $false }
#!
@{ Script = 'if (!$True -and $False) { $true } else { $false }'; Expected = $false }
)
It "<Script> should return <Expected>" -TestCases $testData {
param ( $Script, $Expected )
ExecuteCommand $Script | Should be $Expected
}
}
Context "Arithmetic and String Comparison Tests (starting at line 1848 to line 1943)" {
$testData = @(
@{ Script = '$a=10; if( !$a -eq 10) { $a=1 } else {$a=2};$a'; Expected = 2 }
@{ Script = "!3"; Expected = $false }
@{ Script = '$a=10; if($a -lt 15) { $a=1 } else {$a=2};$a'; Expected = 1 }
@{ Script = "'aaa' -ilt 'AAA'"; Expected = $false }
@{ Script = "'aaa' -lt 'AAA'"; Expected = $false }
@{ Script = "'aaa' -clt 'AAA'"; Expected = $true }
@{ Script = '$a=10; if($a -gt 15) { $a=1 } else {$a=2};$a'; Expected = 2 }
@{ Script = "'AAA' -igt 'aaa'"; Expected = $false }
@{ Script = "'AAA' -gt 'aaa'"; Expected = $false }
@{ Script = "'AAA' -cgt 'aaa'"; Expected = $true }
@{ Script = '$a=10; if($a -ge 10) { $a=1 } else {$a=2};$a'; Expected = 1 }
@{ Script = "'aaa' -ge 'aaa'"; Expected = $true }
@{ Script = '$a=10; if($a -ne 10) { $a=1 } else {$a=2};$a'; Expected = 2 }
@{ Script = "'aaa' -ine 'AAA'"; Expected = $false }
@{ Script = "'aaa' -ne 'AAA'"; Expected = $false }
@{ Script = "'aaa' -cne 'AAA'"; Expected = $true }
@{ Script = '$a="abc"; if($a -ieq "ABC") { $a=1 } else {$a=2};$a'; Expected = 1 }
@{ Script = "'aaa' -ieq 'AAA'"; Expected = $true }
@{ Script = '$a="abc"; if($a -igt "bbc") { $a=1 } else {$a=2};$a'; Expected = 2 }
@{ Script = "'aaa' -igt 'AAA'"; Expected = $false }
@{ Script = '$a="abc"; if($a -ile "bbc") { $a=1 } else {$a=2};$a'; Expected = 1 }
@{ Script = "'aaa' -ile 'AAA'"; Expected = $true }
)
It "<Script> should return <Expected>" -TestCases $testData {
param ( $Script, $Expected )
ExecuteCommand $Script | Should be $Expected
}
}
Context "Comparison Operators with Arrays Tests (starting at line 2015 to line 2178)" {
$testData = @(
@{ Script = "@(3) -eq 3"; Expected = "3" }
@{ Script = "@(4) -eq 3"; Expected = $null }
@{ Script = "@() -eq 3"; Expected = $null }
@{ Script = '$test = 1,2,@(3,4);$test -eq 3'; Expected = $null }
@{ Script = '$test = 1,2,@(3,4);$test -eq 2'; Expected = "2" }
@{ Script = '$test = 1,2,@(3,4);$test -eq 0'; Expected = $null }
)
It "<Script> should return <Expected>" -TestCases $testData {
param ( $Script, $Expected )
ExecuteCommand $Script | Should be $Expected
}
}
It "A simple test for trapping a specific exception. Expected Result: The exception is caught and ignored. (line 2265)" {
{ ExecuteCommand "trap [InvalidCastException] { continue; }; [int] 'abc'" } | Should Not Throw
}
It "Test that assign to input var and use then execute a script block with piped input. (line 2297)"{
$result = ExecuteCommand '$input = 1,2,3;4,-5,6 | & { $input }'
$result -join "" | should be (4,-5,6 -join "")
}
It "Test that pipe objects into a script and use arguments. (line 2313)"{
"`$input; `$args;">$testfile
$result = ExecuteCommand "1,2,3 | $testfile"
$result -join "" | should be (1, 2, 3 -join "")
$result = ExecuteCommand "$testfile 4 -5 6 -blah -- foo -bar"
$result | should be "4", "-5", "6", "-blah", "foo", "-bar"
}
Context "Numerical Notations Tests (starting at line 2374 to line 2452)" {
$testData = @(
#Test various numbers using the standard notation.
@{ Script = "0"; Expected = "0" }
@{ Script = "-2"; Expected = "-2" }
@{ Script = "2"; Expected = "2" }
@{ Script = $([int32]::MaxValue); Expected = $([int32]::MaxValue) }
@{ Script = $([int32]::MinValue); Expected = $([int32]::MinValue) }
#Tests for hexadecimal notation.
@{ Script = "0x0"; Expected = "0" }
@{ Script = "0xF"; Expected = "15" }
@{ Script = "0x80000000"; Expected = $([int32]::MinValue) }
@{ Script = "0xFFFFFFFF"; Expected = "-1" }
@{ Script = "0x7fffffff"; Expected = $([int32]::MaxValue) }
@{ Script = "0x100000000"; Expected = [int64]0x100000000 }
#Tests for exponential notation.
@{ Script = "0e0"; Expected = "0" }
@{ Script = "0e1"; Expected = "0" }
@{ Script = "1e2"; Expected = "100" }
@{ Script = $([int32]::MaxValue); Expected = $([int32]::MaxValue) }
@{ Script = "0e2"; Expected = "0" }
@{ Script = "-2e2"; Expected = "-200" }
@{ Script = "-0e2"; Expected = "0" }
@{ Script = "3e0"; Expected = "3" }
#Tests for floating point notation.
@{ Script = ".01"; Expected = "0.01" }
@{ Script = "0.0"; Expected = "0" }
@{ Script = "-0.1"; Expected = "-0.1" }
@{ Script = "9.12"; Expected = "9.12" }
@{ Script = $([single]::MinValue); Expected = $([float]::MinValue).ToString() }
@{ Script = $([float]::MaxValue); Expected = $([float]::MaxValue).ToString() }
#Tests for the K suffix for numbers.
@{ Script = "0kb"; Expected = "0" }
@{ Script = "1kb"; Expected = "1024" }
@{ Script = "-2KB"; Expected = "-2048" }
)
It "<Script> should return <Expected>" -TestCases $testData {
param ( $Script, $Expected )
ExecuteCommand $Script | Should be $Expected
}
}
It "This is a simple test of the concatenation of two arrays. (line 2460)"{
$result = ExecuteCommand '1,2,3 + 4,5,6'
$result -join "" | should be (1, 2, 3, 4, 5, 6 -join "")
}
It "Test that an incomplete parse exception is thrown if the array is unfinished. (line 2473)"{
try {
ExecuteCommand '1,2,'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "IncompleteParseException"
}
}
It "Test that the unary comma is not valid in cmdlet parameters. (line 2482)"{
try {
ExecuteCommand 'write-output 2,,1'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
It 'Test that "$var:" will expand to nothing inside a string. (line 2551)'{
try {
ExecuteCommand '"$var:"'
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | Should be "ParseException"
}
}
It "Tests the assignment to a read-only property (line 2593)"{
$result = ExecuteCommand '$A=$(testcmd-parserBVT -returntype array); $A.rank =5;$A.rank'
$result | Should be "1"
}
It "Newlines are allowed after operators (line 3033)" {
$result = ExecuteCommand "(20 %
6 *
4 +
2) /
2 -
3"
$result | should be 2
}
It "A here string must have one line (line 3266)" {
try {
ExecuteCommand "@`"`"@"
throw "Execution OK"
}
catch {
$_.FullyQualifiedErrorId | should be "ParseException"
}
}
}